mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-30 04:45:09 +08:00
Merge remote-tracking branch 'origin-wawanbreton/master' into optimized-prime-tower
This commit is contained in:
commit
f7814874ee
71
.github/ISSUE_TEMPLATE/SlicingCrash.yaml
vendored
Normal file
71
.github/ISSUE_TEMPLATE/SlicingCrash.yaml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
name: ❌ Slicing Failed
|
||||
description: When you see the message Slicing failed with an unexpected error
|
||||
labels: ["Type: Bug", "Status: Triage", "Slicing Error :collision:"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Project File
|
||||
**⚠️ Before you continue, we need your project file to troubleshoot a slicing crash.**
|
||||
It contains the printer and settings we need for troubleshooting.
|
||||
|
||||

|
||||
|
||||
To save a project file go to File -> Save project.
|
||||
Please make sure to .zip your project file.
|
||||
For big files, you may need to use [WeTransfer](https://wetransfer.com/) or similar file-sharing sites.
|
||||
|
||||
🤔 Before you share, please think to yourself. Is this a model that can be shared?
|
||||
Unfortunately we cannot help if this file is missing.
|
||||
Do you have the project file? Than let's continue ⬇️
|
||||
|
||||
### Questions
|
||||
- type: input
|
||||
attributes:
|
||||
label: Cura Version
|
||||
placeholder: 5.3.1
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We work hard on improving our slicing crashes. Our most recent release is 5.3.1.
|
||||
If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/tag/5.3.1)
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: Information about the operating system the issue occurs on. Include at least the operating system and maybe GPU.
|
||||
placeholder: Windows 11 / MacOS Catalina / MX Linux
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Printer
|
||||
description: Which printer was selected in Cura?
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Name abnormal settings
|
||||
description: Are there any settings that you might have changed that caused the crash? Does your model slice when you select the default profiles?
|
||||
placeholder:
|
||||
validations:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Describe model location
|
||||
description: Does your model slice if you rotate the model 90 degrees or if you move it away from the center of the buildplate?
|
||||
placeholder:
|
||||
validations:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Describe your model
|
||||
description: Have you sliced your model succesfully before? Is it watertight? Have you tried doing a quick [Mesh Fix with the Meshtools Plugin](https://marketplace.ultimaker.com/app/cura/plugins/fieldofview/MeshTools)?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Add your .zip here ⬇️
|
||||
description: You can add the zip file and additional information that is relevant to the issue in the comments below.
|
||||
validations:
|
||||
required: true
|
||||
|
68
.github/ISSUE_TEMPLATE/bugreport.yaml
vendored
68
.github/ISSUE_TEMPLATE/bugreport.yaml
vendored
@ -1,40 +1,41 @@
|
||||
name: Bug Report
|
||||
name: 🪲 Bug Report
|
||||
description: Create a report to help us fix issues.
|
||||
labels: ["Type: Bug", "Status: Triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Thank you for using Cura and wanting to report a bug.**
|
||||
**Thank you for using Cura and wanting to report a bug. 🙏**
|
||||
|
||||
Before filing, please check if the issue already exists (either open or closed) by using the search bar on the issues page. If it does, comment there. Even if it's closed, we can reopen it based on your comment.
|
||||
Before filing, [please check if the issue already exists](https://github.com/Ultimaker/Cura/issues?q=is%3Aissue) by using the search bar on the issues page.
|
||||
If it does, comment there. Even if it's closed, we can reopen it based on your comment.
|
||||
|
||||
Also, please note the application version in the title of the issue "For example (3.2.1) Cannot connect to 3rd-party printer". Please do not write things like **Request** or **BUG** in the title, this is what labels are for.
|
||||
Please include the cura version in the title of the issue. For example, *"[5.4.0] Support Brim is missing in this model"*.
|
||||
- type: input
|
||||
attributes:
|
||||
label: Application Version
|
||||
label: Cura Version
|
||||
description: The version of Cura this issue occurs with.
|
||||
placeholder: 5.0.0
|
||||
placeholder: 5.4.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Platform
|
||||
label: Operating System
|
||||
description: Information about the operating system the issue occurs on. Include at least the operating system and maybe GPU.
|
||||
placeholder: Windows 10
|
||||
placeholder: Windows 11 / MacOS Catalina / MX Linux
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Printer
|
||||
description: Which printer was selected in Cura?
|
||||
placeholder: Ultimaker S5
|
||||
description: Which printer was selected in Cura? It also helps to mention if you made any firmware modifications to your printer.
|
||||
placeholder: Ultimaker S7 / Creality CR-10 with Klipper
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: Tell us what you did!
|
||||
description: Share what you did, so we can reproduce it
|
||||
placeholder: |
|
||||
1. Something you did
|
||||
2. Something you did next
|
||||
@ -43,40 +44,39 @@ body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual results
|
||||
description: What happens after the above steps have been followed.
|
||||
description: What happens after the above steps have been followed?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected results
|
||||
description: What should happen after the above steps have been followed.
|
||||
description: What should happen after the above steps have been followed?
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please be sure to add the following files:
|
||||
* For slicing issues, upload a **project file** that clearly shows the bug.
|
||||
To save a project file go to `File -> Save project`. Please make sure to .zip your project file. For big files you may need to use WeTransfer or similar file sharing sites.
|
||||
G-code files are not project files!
|
||||
* **Screenshots** of showing the problem, perhaps before/after images.
|
||||
* A **log file** for crashes and similar issues.
|
||||
You can find your log file here:
|
||||
Windows: `%APPDATA%\cura\<Cura version>\cura.log` or usually `C:\Users\\<your username>\AppData\Roaming\cura\<Cura version>\cura.log`
|
||||
MacOS: `$USER/Library/Application Support/cura/<Cura version>/cura.log`
|
||||
Ubuntu/Linux: `$USER/.local/share/cura/<Cura version>/cura.log`
|
||||
|
||||
If the Cura user interface still starts, you can also reach this directory from the application menu in Help -> Show settings folder
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist of files to include
|
||||
options:
|
||||
- label: Log file
|
||||
- label: Project file
|
||||
### Please add the following files when they are related to...
|
||||
* 🔵 **The quality of your print**
|
||||
Please add **a Project File**. It contains the printer and settings we need for troubleshooting.
|
||||
To save a project file go to File -> Save project.
|
||||
Please make sure to .zip your project file. For big files, you may need to use [WeTransfer](https://wetransfer.com/) or similar file-sharing sites.
|
||||
G-code files are not project files! Before you share, please think to yourself. Is this a model that can be shared?
|
||||

|
||||
* 🔵 **Using and interacting with Cura**
|
||||
Please add **screenshots** showing the issue.
|
||||
Before and after, and arrows can help here.
|
||||
* 🔵 **Unexpected crashes and behavior**
|
||||
Please add **a log file** with information on what your Cura is doing.
|
||||
You can find your log file here:
|
||||
Windows: `%APPDATA%\cura\<Cura version>\cura.log`
|
||||
MacOS: `$USER/Library/Application Support/cura/<Cura version>/cura.log`
|
||||
Ubuntu/Linux: `$USER/.local/share/cura/<Cura version>/cura.log`
|
||||
If the Cura user interface still starts, you can also reach this directory from the application menu in Help -> Show settings folder
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information & file uploads
|
||||
description: You can add these files and additional information that is relevant to the issue in the comments below.
|
||||
label: Add your .zip and screenshots here ⬇️
|
||||
description: You can add the zip file and additional information that is relevant to the issue in the comments below.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
2
.github/ISSUE_TEMPLATE/featurerequest.yaml
vendored
2
.github/ISSUE_TEMPLATE/featurerequest.yaml
vendored
@ -1,4 +1,4 @@
|
||||
name: Feature Request
|
||||
name: 💡 Feature Request
|
||||
description: Suggest an idea for this project.
|
||||
labels: ["Type: New Feature", "Status: Triage"]
|
||||
body:
|
||||
|
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -28,6 +28,6 @@ This fixes... OR This improves... -->
|
||||
<!-- Check if relevant -->
|
||||
|
||||
- [ ] My code follows the style guidelines of this project as described in [UltiMaker Meta](https://github.com/Ultimaker/Meta) and [Cura QML best practices](https://github.com/Ultimaker/Cura/wiki/QML-Best-Practices)
|
||||
- [ ] I have read the [Contribution guide](https://github.com/Ultimaker/Cura/blob/main/contributing.md)
|
||||
- [ ] I have read the [Contribution guide](https://github.com/Ultimaker/Cura/blob/main/CONTRIBUTING.md)
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have uploaded any files required to test this change
|
||||
- [ ] I have uploaded any files required to test this change
|
||||
|
243
.github/workflows/conan-package-create.yml
vendored
243
.github/workflows/conan-package-create.yml
vendored
@ -1,158 +1,153 @@
|
||||
name: Create and Upload Conan package
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
project_name:
|
||||
required: true
|
||||
type: string
|
||||
workflow_call:
|
||||
inputs:
|
||||
project_name:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
recipe_id_full:
|
||||
required: true
|
||||
type: string
|
||||
recipe_id_full:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
build_id:
|
||||
required: true
|
||||
type: number
|
||||
build_id:
|
||||
required: true
|
||||
type: number
|
||||
|
||||
build_info:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
build_info:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
recipe_id_latest:
|
||||
required: false
|
||||
type: string
|
||||
recipe_id_latest:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
runs_on:
|
||||
required: true
|
||||
type: string
|
||||
runs_on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
python_version:
|
||||
required: true
|
||||
type: string
|
||||
python_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
conan_config_branch:
|
||||
required: false
|
||||
type: string
|
||||
conan_config_branch:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
conan_logging_level:
|
||||
required: false
|
||||
type: string
|
||||
conan_logging_level:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
conan_clean_local_cache:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
conan_clean_local_cache:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
conan_upload_community:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
conan_upload_community:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
|
||||
jobs:
|
||||
conan-package-create:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
conan-package-create:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
|
||||
- name: Install Python requirements for runner
|
||||
run: pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt
|
||||
# Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo
|
||||
- name: 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 (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: Use Conan download cache (Powershell)
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
run: conan config set storage.download_cache="C:\Users\runneradmin\.conan\conan_download_cache"
|
||||
|
||||
- name: Cache Conan local repository packages (Bash)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
$HOME/.conan/data
|
||||
$HOME/.conan/conan_download_cache
|
||||
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
|
||||
- name: Cache Conan local repository packages (Bash)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
$HOME/.conan/data
|
||||
$HOME/.conan/conan_download_cache
|
||||
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
|
||||
|
||||
- name: Cache Conan local repository packages (Powershell)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
C:\Users\runneradmin\.conan\data
|
||||
C:\.conan
|
||||
C:\Users\runneradmin\.conan\conan_download_cache
|
||||
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
|
||||
- name: Cache Conan local repository packages (Powershell)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
C:\Users\runneradmin\.conan\data
|
||||
C:\.conan
|
||||
C:\Users\runneradmin\.conan\conan_download_cache
|
||||
key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache
|
||||
|
||||
- name: Install MacOS system requirements
|
||||
if: ${{ runner.os == 'Macos' }}
|
||||
run: brew install autoconf automake ninja
|
||||
- name: Install MacOS system requirements
|
||||
if: ${{ runner.os == 'Macos' }}
|
||||
run: brew install autoconf automake ninja
|
||||
|
||||
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
|
||||
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
|
||||
- name: Install Linux system requirements
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo rm /var/cache/debconf/config.dat
|
||||
sudo dpkg --configure -a
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison -y
|
||||
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
|
||||
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
|
||||
- name: Install Linux system requirements
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo rm /var/cache/debconf/config.dat
|
||||
sudo dpkg --configure -a
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison -y
|
||||
|
||||
- name: Install GCC-12 on ubuntu-22.04
|
||||
if: ${{ startsWith(inputs.runs_on, '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: Install GCC-132 on ubuntu
|
||||
if: ${{ startsWith(inputs.runs_on, 'ubuntu') }}
|
||||
run: |
|
||||
sudo apt install g++-13 gcc-13 -y
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||
|
||||
- name: 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
|
||||
run: conan profile new default --detect
|
||||
|
||||
- name: Create the default Conan profile
|
||||
run: conan profile new default --detect
|
||||
- name: Get Conan configuration from branch
|
||||
if: ${{ inputs.conan_config_branch != '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
|
||||
|
||||
- name: Get Conan configuration from branch
|
||||
if: ${{ inputs.conan_config_branch != '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
|
||||
- name: Get Conan configuration
|
||||
run: |
|
||||
conan config install https://github.com/Ultimaker/conan-config.git
|
||||
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
|
||||
|
||||
- name: Get Conan configuration
|
||||
if: ${{ inputs.conan_config_branch == '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
||||
- name: Add Cura private Artifactory remote
|
||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||
|
||||
- name: Add Cura private Artifactory remote
|
||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||
- name: Create the Packages
|
||||
run: conan install ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
|
||||
|
||||
- name: Create the Packages
|
||||
run: conan install ${{ inputs.recipe_id_full }} --build=missing --update
|
||||
- name: Upload the Package(s)
|
||||
if: ${{ always() && inputs.conan_upload_community }}
|
||||
run: conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
|
||||
|
||||
- name: Upload the Package(s)
|
||||
if: ${{ always() && inputs.conan_upload_community }}
|
||||
run: conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
|
||||
|
||||
- name: Upload the Package(s) to the private Artifactory
|
||||
if: ${{ always() && ! inputs.conan_upload_community }}
|
||||
run: conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c
|
||||
- name: Upload the Package(s) to the private Artifactory
|
||||
if: ${{ always() && ! inputs.conan_upload_community }}
|
||||
run: conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c
|
||||
|
31
.github/workflows/conan-package.yml
vendored
31
.github/workflows/conan-package.yml
vendored
@ -49,15 +49,15 @@ on:
|
||||
- '[1-9].[0-9][0-9].[0-9]*'
|
||||
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
|
||||
permissions: {}
|
||||
permissions: { }
|
||||
jobs:
|
||||
conan-recipe-version:
|
||||
permissions:
|
||||
@ -103,18 +103,23 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison g++-12 gcc-12 -y
|
||||
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: Install GCC-13
|
||||
run: |
|
||||
sudo apt install g++-13 gcc-13 -y
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||
|
||||
- name: Create the default Conan profile
|
||||
run: conan profile new default --detect --force
|
||||
|
||||
- name: Get Conan configuration
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
||||
run: |
|
||||
conan config install https://github.com/Ultimaker/conan-config.git
|
||||
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
|
||||
|
||||
- name: Create the Packages
|
||||
run: conan create . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o ${{ needs.conan-recipe-version.outputs.project_name }}:devtools=True
|
||||
run: conan create . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o ${{ needs.conan-recipe-version.outputs.project_name }}:devtools=True -c tools.build:skip_test=True
|
||||
|
||||
- name: Create the latest alias
|
||||
if: always()
|
||||
|
161
.github/workflows/conan-recipe-export.yml
vendored
161
.github/workflows/conan-recipe-export.yml
vendored
@ -1,106 +1,107 @@
|
||||
name: Export Conan Recipe to server
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
recipe_id_full:
|
||||
required: true
|
||||
type: string
|
||||
workflow_call:
|
||||
inputs:
|
||||
recipe_id_full:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
recipe_id_latest:
|
||||
required: false
|
||||
type: string
|
||||
recipe_id_latest:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
runs_on:
|
||||
required: true
|
||||
type: string
|
||||
runs_on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
python_version:
|
||||
required: true
|
||||
type: string
|
||||
python_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
conan_config_branch:
|
||||
required: false
|
||||
type: string
|
||||
conan_config_branch:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
conan_logging_level:
|
||||
required: false
|
||||
type: string
|
||||
conan_logging_level:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
conan_export_binaries:
|
||||
required: false
|
||||
type: boolean
|
||||
conan_export_binaries:
|
||||
required: false
|
||||
type: boolean
|
||||
|
||||
conan_upload_community:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
conan_upload_community:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }}
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
|
||||
jobs:
|
||||
package-export:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
package-export:
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
|
||||
steps:
|
||||
- name: Checkout project
|
||||
uses: actions/checkout@v3
|
||||
steps:
|
||||
- name: Checkout project
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
|
||||
- name: Install Python requirements and Create default Conan profile
|
||||
run: |
|
||||
pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt
|
||||
conan profile new default --detect
|
||||
# Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo
|
||||
- name: Install Python requirements and Create default Conan profile
|
||||
run: |
|
||||
pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt
|
||||
conan profile new default --detect
|
||||
# Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo
|
||||
|
||||
- name: Cache Conan local repository packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: $HOME/.conan/data
|
||||
key: ${{ runner.os }}-conan-export-cache
|
||||
- name: Cache Conan local repository packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: $HOME/.conan/data
|
||||
key: ${{ runner.os }}-conan-export-cache
|
||||
|
||||
- name: Get Conan configuration from branch
|
||||
if: ${{ inputs.conan_config_branch != '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
|
||||
- name: Get Conan configuration from branch
|
||||
if: ${{ inputs.conan_config_branch != '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}"
|
||||
|
||||
- name: Get Conan configuration
|
||||
if: ${{ inputs.conan_config_branch == '' }}
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
||||
- name: Get Conan configuration
|
||||
run: |
|
||||
conan config install https://github.com/Ultimaker/conan-config.git
|
||||
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
|
||||
|
||||
- name: Add Cura private Artifactory remote
|
||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||
- name: Add Cura private Artifactory remote
|
||||
run: conan remote add cura-private https://ultimaker.jfrog.io/artifactory/api/conan/cura-private True
|
||||
|
||||
- name: Export the Package (binaries)
|
||||
if: ${{ inputs.conan_export_binaries }}
|
||||
run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update
|
||||
- name: Export the Package (binaries)
|
||||
if: ${{ inputs.conan_export_binaries }}
|
||||
run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True
|
||||
|
||||
- name: Export the Package
|
||||
if: ${{ !inputs.conan_export_binaries }}
|
||||
run: conan export . ${{ inputs.recipe_id_full }}
|
||||
- name: Export the Package
|
||||
if: ${{ !inputs.conan_export_binaries }}
|
||||
run: conan export . ${{ inputs.recipe_id_full }}
|
||||
|
||||
- name: Create the latest alias
|
||||
if: always()
|
||||
run: conan alias ${{ inputs.recipe_id_latest }} ${{ inputs.recipe_id_full }}
|
||||
- name: Create the latest alias
|
||||
if: always()
|
||||
run: conan alias ${{ inputs.recipe_id_latest }} ${{ inputs.recipe_id_full }}
|
||||
|
||||
- name: Upload the Package(s)
|
||||
if: ${{ always() && inputs.conan_upload_community }}
|
||||
run: |
|
||||
conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
|
||||
conan upload ${{ inputs.recipe_id_latest }} -r cura -c
|
||||
- name: Upload the Package(s)
|
||||
if: ${{ always() && inputs.conan_upload_community }}
|
||||
run: |
|
||||
conan upload ${{ inputs.recipe_id_full }} -r cura --all -c
|
||||
conan upload ${{ inputs.recipe_id_latest }} -r cura -c
|
||||
|
||||
- name: Upload the Package(s) to the private Artifactory
|
||||
if: ${{ always() && ! inputs.conan_upload_community }}
|
||||
run: |
|
||||
conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c
|
||||
conan upload ${{ inputs.recipe_id_latest }} -r cura-private -c
|
||||
- name: Upload the Package(s) to the private Artifactory
|
||||
if: ${{ always() && ! inputs.conan_upload_community }}
|
||||
run: |
|
||||
conan upload ${{ inputs.recipe_id_full }} -r cura-private --all -c
|
||||
conan upload ${{ inputs.recipe_id_latest }} -r cura-private -c
|
||||
|
24
.github/workflows/conan-recipe-version.yml
vendored
24
.github/workflows/conan-recipe-version.yml
vendored
@ -77,7 +77,7 @@ jobs:
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10.x"
|
||||
python-version: "3.11.x"
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
|
||||
@ -146,25 +146,21 @@ jobs:
|
||||
|
||||
if latest_branch_tag:
|
||||
# %% Get the actual version
|
||||
no_commits = 0
|
||||
for commit in repo.iter_commits("HEAD"):
|
||||
if commit == latest_branch_tag.commit:
|
||||
break
|
||||
no_commits += 1
|
||||
sha_commit = repo.commit().hexsha[:6]
|
||||
latest_branch_version_prerelease = latest_branch_version.pre
|
||||
if latest_branch_version.pre and not "." in str(latest_branch_version.pre):
|
||||
# The prerealese did not contain a version number, default it to 1
|
||||
latest_branch_version_prerelease = f"{latest_branch_version.pre}.1"
|
||||
if event_name == "pull_request":
|
||||
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version_prerelease).lower()}+{buildmetadata}pr_{issue_number}_{no_commits}"
|
||||
channel_metadata = f"{channel}_{no_commits}"
|
||||
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version_prerelease).lower()}+{buildmetadata}pr_{issue_number}_{sha_commit}"
|
||||
channel_metadata = f"{channel}_{sha_commit}"
|
||||
else:
|
||||
if channel in ("stable", "_", ""):
|
||||
channel_metadata = f"{no_commits}"
|
||||
channel_metadata = f"{sha_commit}"
|
||||
else:
|
||||
channel_metadata = f"{channel}_{no_commits}"
|
||||
channel_metadata = f"{channel}_{sha_commit}"
|
||||
if is_release_branch:
|
||||
if latest_branch_version.pre == "" and branch_version > latest_branch_version:
|
||||
if (latest_branch_version.pre == "" or latest_branch_version.pre is None) and branch_version > latest_branch_version:
|
||||
actual_version = f"{branch_version.major}.{branch_version.minor}.0-beta.1+{buildmetadata}{channel_metadata}"
|
||||
elif latest_branch_version.pre == "":
|
||||
# An actual full release has been created, we are working on patch
|
||||
@ -178,18 +174,16 @@ jobs:
|
||||
actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version.pre).split('.')[0]}.{bump_up_release_tag}+{buildmetadata}{channel_metadata}"
|
||||
else:
|
||||
max_branches_version = Version("0.0.0")
|
||||
branches_no_commits = no_commits
|
||||
for branch in repo.references:
|
||||
try:
|
||||
if "remotes/origin" in branch.abspath:
|
||||
b_version = Version(branch.name.split("/")[-1])
|
||||
if b_version < Version("10.0.0") and b_version > max_branches_version:
|
||||
if b_version < Version("6.0.0") and b_version > max_branches_version:
|
||||
max_branches_version = b_version
|
||||
branches_no_commits = repo.commit().count() - branch.commit.count()
|
||||
except:
|
||||
pass
|
||||
if max_branches_version > latest_branch_version:
|
||||
actual_version = f"{max_branches_version.major}.{int(str(max_branches_version.minor)) + 1}.0-alpha+{buildmetadata}{channel}_{branches_no_commits}"
|
||||
actual_version = f"{max_branches_version.major}.{int(str(max_branches_version.minor)) + 1}.0-alpha+{buildmetadata}{channel}_{sha_commit}"
|
||||
else:
|
||||
actual_version = f"{latest_branch_version.major}.{int(str(latest_branch_version.minor)) + 1}.0-alpha+{buildmetadata}{channel_metadata}"
|
||||
|
||||
|
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
|
372
.github/workflows/cura-installer.yml
vendored
372
.github/workflows/cura-installer.yml
vendored
@ -1,372 +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 }} uses:\n")
|
||||
for dep in sorted_deps:
|
||||
f.writelines(f"`{dep}`\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
|
||||
|
37
.github/workflows/stale.yml
vendored
Normal file
37
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 9-17/4 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
days-before-pr-close: -1
|
||||
days-before-stale: 365
|
||||
days-before-close: 14
|
||||
operations-per-run: 3000
|
||||
ascending: true
|
||||
exempt-issue-labels: 'Status: Triage,Developer Environment :computer:,Status: On Backlog,PR: Community Contribution :crown:,PR: Printer Definitions :factory:,PR: Translations :books:'
|
||||
stale-issue-label: 'Status: Stale :hourglass:'
|
||||
labels-to-add-when-unstale: 'Status: Triage'
|
||||
only-labels: "Type: New Feature,Status: Deferred"
|
||||
stale-issue-message: |
|
||||
Hi 👋,
|
||||
We are cleaning our list of issues to improve our focus.
|
||||
This feature request seems to be older than a year, which is at least three major Cura releases ago.
|
||||
It also received the label Deferred indicating that we did not have time to work on it back then and haven't found time to work on it since.
|
||||
|
||||
If this is still something that you think can improve how you and others use Cura, can you please leave a comment?
|
||||
We will have a fresh set of eyes to look at it.
|
||||
|
||||
If it has been resolved or don't need it to be improved anymore, you don't have to do anything, and this issue will be automatically closed in 14 days.
|
||||
close-issue-message: |
|
||||
This issue was closed because it has been inactive for 14 days since being marked as stale.
|
||||
If you encounter this issue and still have a need for this, you are welcome to make a fresh new issue with an updated description.
|
||||
permissions:
|
||||
contents: write # only for delete-branch option
|
||||
issues: write
|
||||
pull-requests: write
|
275
.github/workflows/unit-test.yml
vendored
275
.github/workflows/unit-test.yml
vendored
@ -2,160 +2,165 @@
|
||||
name: unit-test
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/unit-test.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
branches:
|
||||
- main
|
||||
- 'CURA-*'
|
||||
- '[1-9]+.[0-9]+'
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+-beta'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/unit-test.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
branches:
|
||||
- main
|
||||
- '[1-9]+.[0-9]+'
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+-beta'
|
||||
push:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/unit-test.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
branches:
|
||||
- main
|
||||
- 'CURA-*'
|
||||
- '[1-9]+.[0-9]+'
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+-beta'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/unit-test.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
branches:
|
||||
- main
|
||||
- '[1-9]+.[0-9]+'
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+-beta'
|
||||
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: info
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }}
|
||||
CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }}
|
||||
CONAN_LOG_RUN_TO_OUTPUT: 1
|
||||
CONAN_LOGGING_LEVEL: info
|
||||
CONAN_NON_INTERACTIVE: 1
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
conan-recipe-version:
|
||||
uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main
|
||||
conan-recipe-version:
|
||||
uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main
|
||||
with:
|
||||
project_name: cura
|
||||
|
||||
testing:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [ conan-recipe-version ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
project_name: cura
|
||||
fetch-depth: 2
|
||||
|
||||
testing:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [ conan-recipe-version ]
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11.x'
|
||||
architecture: 'x64'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Install Python requirements and Create default Conan profile
|
||||
run: pip install -r requirements-conan-package.txt
|
||||
working-directory: .github/workflows/
|
||||
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10.x'
|
||||
architecture: 'x64'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
- name: Use Conan download cache (Bash)
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
|
||||
|
||||
- name: Install Python requirements and Create default Conan profile
|
||||
run: |
|
||||
pip install -r requirements-conan-package.txt
|
||||
conan profile new default --detect
|
||||
working-directory: .github/workflows/
|
||||
- name: Cache Conan local repository packages (Bash)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
$HOME/.conan/data
|
||||
$HOME/.conan/conan_download_cache
|
||||
key: conan-${{ runner.os }}-${{ runner.arch }}-unit-cache
|
||||
|
||||
- name: Use Conan download cache (Bash)
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache"
|
||||
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
|
||||
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
|
||||
- name: Install Linux system requirements
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo rm /var/cache/debconf/config.dat
|
||||
sudo dpkg --configure -a
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config -y
|
||||
|
||||
- name: Cache Conan local repository packages (Bash)
|
||||
uses: actions/cache@v3
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
with:
|
||||
path: |
|
||||
$HOME/.conan/data
|
||||
$HOME/.conan/conan_download_cache
|
||||
key: conan-${{ runner.os }}-${{ runner.arch }}-unit-cache
|
||||
- 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
|
||||
|
||||
# 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 apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config -y
|
||||
- name: 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 GCC-10 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: Get Conan profile
|
||||
run: conan profile new default --detect --force
|
||||
|
||||
- name: Get Conan configuration
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
||||
- name: Install dependencies
|
||||
run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o cura:devtools=True -g VirtualPythonEnv -if venv
|
||||
|
||||
- name: Install dependencies
|
||||
run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o cura:devtools=True -g VirtualPythonEnv -if venv
|
||||
- name: Upload the Dependency package(s)
|
||||
run: conan upload "*" -r cura --all -c
|
||||
|
||||
- name: Upload the Dependency package(s)
|
||||
run: conan upload "*" -r cura --all -c
|
||||
- name: Set Environment variables for Cura (bash)
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: |
|
||||
. ./venv/bin/activate_github_actions_env.sh
|
||||
|
||||
- name: Set Environment variables for Cura (bash)
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: |
|
||||
. ./venv/bin/activate_github_actions_env.sh
|
||||
- name: Run Unit Test
|
||||
id: run-test
|
||||
run: |
|
||||
pytest --junitxml=junit_cura.xml
|
||||
working-directory: tests
|
||||
|
||||
- name: Run Unit Test
|
||||
id: run-test
|
||||
run: |
|
||||
pytest --junitxml=junit_cura.xml
|
||||
working-directory: tests
|
||||
- name: Save PR metadata
|
||||
if: always()
|
||||
run: |
|
||||
echo ${{ github.event.number }} > pr-id.txt
|
||||
echo ${{ github.event.pull_request.head.repo.full_name }} > pr-head-repo.txt
|
||||
echo ${{ github.event.pull_request.head.ref }} > pr-head-ref.txt
|
||||
working-directory: tests
|
||||
|
||||
- name: Save PR metadata
|
||||
if: always()
|
||||
run: |
|
||||
echo ${{ github.event.number }} > pr-id.txt
|
||||
echo ${{ github.event.pull_request.head.repo.full_name }} > pr-head-repo.txt
|
||||
echo ${{ github.event.pull_request.head.ref }} > pr-head-ref.txt
|
||||
working-directory: tests
|
||||
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-result
|
||||
path: |
|
||||
tests/**/*.xml
|
||||
tests/pr-id.txt
|
||||
tests/pr-head-repo.txt
|
||||
tests/pr-head-ref.txt
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-result
|
||||
path: |
|
||||
tests/**/*.xml
|
||||
tests/pr-id.txt
|
||||
tests/pr-head-repo.txt
|
||||
tests/pr-head-ref.txt
|
||||
|
134
.github/workflows/update-translation.yml
vendored
134
.github/workflows/update-translation.yml
vendored
@ -1,75 +1,87 @@
|
||||
name: update-translations
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
push:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'resources/**'
|
||||
- 'cura/**'
|
||||
- 'icons/**'
|
||||
- 'tests/**'
|
||||
- 'packaging/**'
|
||||
- '.github/workflows/conan-*.yml'
|
||||
- '.github/workflows/notify.yml'
|
||||
- '.github/workflows/requirements-conan-package.txt'
|
||||
- 'requirements*.txt'
|
||||
- 'conanfile.py'
|
||||
- 'conandata.yml'
|
||||
- 'GitVersion.yml'
|
||||
- '*.jinja'
|
||||
branches:
|
||||
- '[1-9].[0-9]'
|
||||
- '[1-9].[0-9][0-9]'
|
||||
tags:
|
||||
- '[1-9].[0-9].[0-9]*'
|
||||
- '[1-9].[0-9].[0-9]'
|
||||
- '[1-9].[0-9][0-9].[0-9]*'
|
||||
|
||||
jobs:
|
||||
update-translations:
|
||||
name: Update translations
|
||||
update-translations:
|
||||
name: Update translations
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Cache Conan data
|
||||
id: cache-conan
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.conan
|
||||
key: ${{ runner.os }}-conan
|
||||
- name: Cache Conan data
|
||||
id: cache-conan
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.conan
|
||||
key: ${{ runner.os }}-conan
|
||||
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11.x
|
||||
cache: pip
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
- name: Setup Python and pip
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11.x
|
||||
cache: pip
|
||||
cache-dependency-path: .github/workflows/requirements-conan-package.txt
|
||||
|
||||
- name: Install Python requirements for runner
|
||||
run: pip install -r .github/workflows/requirements-conan-package.txt
|
||||
- name: Install Python requirements for runner
|
||||
run: pip install -r .github/workflows/requirements-conan-package.txt
|
||||
|
||||
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
|
||||
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
|
||||
- name: Install Linux system requirements
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo rm /var/cache/debconf/config.dat
|
||||
sudo dpkg --configure -a
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison g++-12 gcc-12 -y
|
||||
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
|
||||
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
|
||||
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
|
||||
- name: Install Linux system requirements
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo rm /var/cache/debconf/config.dat
|
||||
sudo dpkg --configure -a
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison g++-12 gcc-12 -y
|
||||
|
||||
- name: Create the default Conan profile
|
||||
run: conan profile new default --detect --force
|
||||
- name: Install GCC-13
|
||||
run: |
|
||||
sudo apt install g++-13 gcc-13 -y
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
||||
|
||||
- name: Get Conan configuration
|
||||
run: conan config install https://github.com/Ultimaker/conan-config.git
|
||||
- name: Create the default Conan profile
|
||||
run: conan profile new default --detect --force
|
||||
|
||||
- name: generate the files using Conan install
|
||||
run: conan install . --build=missing --update -o cura:devtools=True
|
||||
- name: Get Conan configuration
|
||||
run: |
|
||||
conan config install https://github.com/Ultimaker/conan-config.git
|
||||
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
file_pattern: resources/i18n/*.po resources/i18n/*.pot
|
||||
status_options: --untracked-files=no
|
||||
commit_message: update translations
|
||||
- name: generate the files using Conan install
|
||||
run: conan install . --build=missing --update -o cura:devtools=True
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
file_pattern: resources/i18n/*.po resources/i18n/*.pot
|
||||
status_options: --untracked-files=no
|
||||
commit_message: update translations
|
||||
|
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
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -101,3 +101,4 @@ graph_info.json
|
||||
Ultimaker-Cura.spec
|
||||
.run/
|
||||
/printer-linter/src/printerlinter.egg-info/
|
||||
/resources/qml/Dialogs/AboutDialogVersionsList.qml
|
||||
|
61
AboutDialogVersionsList.qml.jinja
Normal file
61
AboutDialogVersionsList.qml.jinja
Normal file
@ -0,0 +1,61 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 2.9
|
||||
|
||||
import UM 1.6 as UM
|
||||
import Cura 1.5 as Cura
|
||||
|
||||
|
||||
ListView
|
||||
{
|
||||
id: projectBuildInfoList
|
||||
visible: false
|
||||
anchors.top: creditsNotes.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height)
|
||||
|
||||
ScrollBar.vertical: UM.ScrollBar
|
||||
{
|
||||
id: projectBuildInfoListScrollBar
|
||||
}
|
||||
|
||||
delegate: Row
|
||||
{
|
||||
spacing: UM.Theme.getSize("narrow_margin").width
|
||||
UM.Label
|
||||
{
|
||||
text: (model.name)
|
||||
width: (projectBuildInfoList.width* 0.4) | 0
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
UM.Label
|
||||
{
|
||||
text: (model.version)
|
||||
width: (projectBuildInfoList.width *0.6) | 0
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
}
|
||||
model: ListModel
|
||||
{
|
||||
id: developerInfo
|
||||
}
|
||||
Component.onCompleted:
|
||||
{
|
||||
var conan_installs = {{ conan_installs }};
|
||||
var python_installs = {{ python_installs }};
|
||||
developerInfo.append({ name : "<H1>Conan Installs</H1>", version : '' });
|
||||
for (var n in conan_installs)
|
||||
{
|
||||
developerInfo.append({ name : conan_installs[n][0], version : conan_installs[n][1] });
|
||||
}
|
||||
developerInfo.append({ name : '', version : '' });
|
||||
developerInfo.append({ name : "<H1>Python Installs</H1>", version : '' });
|
||||
for (var n in python_installs)
|
||||
{
|
||||
developerInfo.append({ name : python_installs[n][0], version : python_installs[n][1] });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ url: "https://ultimaker.com/software/ultimaker-cura"
|
||||
repository-code: "https://github.com/Ultimaker/Cura"
|
||||
license: LGPL-3.0
|
||||
license-url: "https://github.com/Ultimaker/Cura/blob/main/LICENSE"
|
||||
version: 5.2.1
|
||||
date-released: "2022-10-19"
|
||||
version: 5.4.0
|
||||
date-released: "2023-07-04"
|
||||
keywords:
|
||||
- Ultimaker
|
||||
- Cura
|
||||
|
@ -1,6 +1,6 @@
|
||||
Submitting bug reports
|
||||
----------------------
|
||||
Please submit bug reports for all of Cura and CuraEngine to the [Cura repository](https://github.com/Ultimaker/Cura/issues). There will be a template there to fill in. Depending on the type of issue, we will usually ask for the [Cura log](Logging Issues) or a project file.
|
||||
Please submit bug reports for all of Cura and CuraEngine to the [Cura repository](https://github.com/Ultimaker/Cura/issues). There will be a template there to fill in. Depending on the type of issue, we will usually ask for the [Cura log](https://github.com/Ultimaker/Cura/wiki/Reporting#cura-log) or a project file.
|
||||
|
||||
If a bug report would contain private information, such as a proprietary 3D model, you may also e-mail us. Ask for contact information in the issue.
|
||||
|
||||
@ -8,14 +8,22 @@ Bugs related to supporting certain types of printers can usually not be solved b
|
||||
|
||||
Requesting features
|
||||
-------------------
|
||||
The issue template in the Cura repository does not apply to feature requests. You can ignore it.
|
||||
|
||||
When requesting a feature, please describe clearly what you need and why you think this is valuable to users or what problem it solves.
|
||||
|
||||
Making pull requests
|
||||
--------------------
|
||||
If you want to propose a change to Cura's source code, please create a pull request in the appropriate repository (being [Cura](https://github.com/Ultimaker/Cura), [Uranium](https://github.com/Ultimaker/Uranium), [CuraEngine](https://github.com/Ultimaker/CuraEngine), [fdm_materials](https://github.com/Ultimaker/fdm_materials), [libArcus](https://github.com/Ultimaker/libArcus), [cura-build](https://github.com/Ultimaker/cura-build), [cura-build-environment](https://github.com/Ultimaker/cura-build-environment), [libSavitar](https://github.com/Ultimaker/libSavitar), [libCharon](https://github.com/Ultimaker/libCharon) or [cura-binary-data](https://github.com/Ultimaker/cura-binary-data)) and if your change requires changes on multiple of these repositories, please link them together so that we know to merge them together.
|
||||
If you want to propose a change to Cura's source code, please create a pull request in the appropriate repository. Since Cura has multiple repositories that influence it, we've listed the most important ones below:
|
||||
* [Cura](https://github.com/Ultimaker/Cura)
|
||||
* [Uranium](https://github.com/Ultimaker/Uranium)
|
||||
* [CuraEngine](https://github.com/Ultimaker/CuraEngine)
|
||||
* [fdm_materials](https://github.com/Ultimaker/fdm_materials)
|
||||
* [libArcus](https://github.com/Ultimaker/libArcus)
|
||||
* [libSavitar](https://github.com/Ultimaker/libSavitar)
|
||||
* [libCharon](https://github.com/Ultimaker/libCharon)
|
||||
* [cura-binary-data](https://github.com/Ultimaker/cura-binary-data))
|
||||
|
||||
If your change requires changes on multiple of these repositories, please link them together so that we know to merge & review them together.
|
||||
|
||||
The style guide for code contributions to Cura and other Ultimaker projects can be found [here](https://github.com/Ultimaker/Meta/blob/master/general/generic_code_conventions.md).
|
||||
|
||||
Some of these repositories will have automated tests running when you create a pull request, indicated by green check marks or red crosses in the Github web page. If you see a red cross, that means that a test has failed. If the test doesn't fail on the Master branch but does fail on your branch, that indicates that you've probably made a mistake and you need to do that. Click on the cross for more details, or run the test locally by running `cmake . && ctest --verbose`.
|
||||
Some of these repositories will have automated tests running when you create a pull request, indicated by green check marks or red crosses in the Github web page. If you see a red cross, that means that a test has failed. If the test doesn't fail on the Main branch but does fail on your branch, that indicates that you've probably made a mistake and you need to do that. Click on the cross for more details, or run the test locally by running `cmake . && ctest --verbose`.
|
1
FUNDING.yml
Normal file
1
FUNDING.yml
Normal file
@ -0,0 +1 @@
|
||||
github: [ultimaker]
|
10
README.md
10
README.md
@ -1,10 +1,3 @@
|
||||
|
||||
> # Work with us!
|
||||
> If you're interested in working with us on Cura and Thingiverse, please apply to one of the open positions below.
|
||||
> - [Software Engineer C++ & Python](https://www.linkedin.com/jobs/view/3516545085) for [Cura](https://github.com/Ultimaker/Cura)
|
||||
> - [DevOps Engineer Community Software](https://www.linkedin.com/jobs/view/3516542580) for [Cura](https://github.com/Ultimaker/Cura) and [Thingiverse](https://www.thingiverse.com/)
|
||||
> - [QA / Test Engineer Cura (3D printing)](https://www.linkedin.com/jobs/view/3516538895) for [Cura](https://github.com/Ultimaker/Cura) and [Thingiverse](https://www.thingiverse.com/)
|
||||
|
||||
<br>
|
||||
|
||||
<div align = center>
|
||||
@ -19,7 +12,7 @@
|
||||
|
||||
[![Badge Test]][Test]
|
||||
[![Badge Conan]][Conan]
|
||||
|
||||
![Badge Downloads]
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@ -91,6 +84,7 @@
|
||||
[Badge Conan]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/conan-package?style=for-the-badge&logoColor=white&labelColor=6185aa&color=4c6987&logo=Conan&label=Conan%20Package
|
||||
[Badge Test]: https://img.shields.io/github/workflow/status/Ultimaker/Cura/unit-test?style=for-the-badge&logoColor=white&labelColor=4a999d&color=346c6e&logo=Codacy&label=Unit%20Test
|
||||
[Badge Size]: https://img.shields.io/github/repo-size/ultimaker/cura?style=for-the-badge&logoColor=white&labelColor=715a97&color=584674&logo=GoogleAnalytics
|
||||
[Badge Downloads]: https://img.shields.io/github/downloads-pre/Ultimaker/Cura/latest/total?style=for-the-badge
|
||||
|
||||
|
||||
<!---------------------------------[ Buttons ]--------------------------------->
|
||||
|
@ -1,3 +1,16 @@
|
||||
urls:
|
||||
default:
|
||||
cloud_api_root: "https://api.ultimaker.com"
|
||||
cloud_account_api_root: "https://account.ultimaker.com"
|
||||
marketplace_root: "https://marketplace.ultimaker.com"
|
||||
digital_factory_url: "https://digitalfactory.ultimaker.com"
|
||||
cura_latest_url: "https://software.ultimaker.com/latest.json"
|
||||
staging:
|
||||
cloud_api_root: "https://api-staging.ultimaker.com"
|
||||
cloud_account_api_root: "https://account-staging.ultimaker.com"
|
||||
marketplace_root: "https://marketplace-staging.ultimaker.com"
|
||||
digital_factory_url: "https://digitalfactory-staging.ultimaker.com"
|
||||
cura_latest_url: "https://software.ultimaker.com/latest.json"
|
||||
pyinstaller:
|
||||
runinfo:
|
||||
entrypoint: "cura_app.py"
|
||||
@ -12,8 +25,8 @@ pyinstaller:
|
||||
dst: "share/cura/resources"
|
||||
cura_private_data:
|
||||
package: "cura_private_data"
|
||||
src: "resources"
|
||||
dst: "share/cura/resources"
|
||||
src: "res"
|
||||
dst: "share/cura"
|
||||
internal: true
|
||||
uranium_plugins:
|
||||
package: "uranium"
|
||||
@ -41,7 +54,7 @@ pyinstaller:
|
||||
dst: "share/windows"
|
||||
fdm_materials:
|
||||
package: "fdm_materials"
|
||||
src: "materials"
|
||||
src: "res/resources/materials"
|
||||
dst: "share/cura/resources/materials"
|
||||
tcl:
|
||||
package: "tcl"
|
||||
|
218
conanfile.py
218
conanfile.py
@ -10,7 +10,7 @@ from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv
|
||||
from conan.tools.scm import Version
|
||||
from conan.errors import ConanInvalidConfiguration, ConanException
|
||||
|
||||
required_conan_version = "<=1.56.0"
|
||||
required_conan_version = ">=1.58.0 <2.0.0"
|
||||
|
||||
|
||||
class CuraConan(ConanFile):
|
||||
@ -21,9 +21,8 @@ class CuraConan(ConanFile):
|
||||
description = "3D printer / slicing GUI built on top of the Uranium framework"
|
||||
topics = ("conan", "python", "pyqt6", "qt", "qml", "3d-printing", "slicer")
|
||||
build_policy = "missing"
|
||||
exports = "LICENSE*", "UltiMaker-Cura.spec.jinja", "CuraVersion.py.jinja"
|
||||
exports = "LICENSE*", "UltiMaker-Cura.spec.jinja", "CuraVersion.py.jinja", "AboutDialogVersionsList.qml.jinja"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
no_copy_source = True # We won't build so no need to copy sources to the build folder
|
||||
|
||||
# FIXME: Remove specific branch once merged to main
|
||||
python_requires = "umbase/[>=0.1.7]@ultimaker/stable", "translationextractor/[>=2.1.1]@ultimaker/stable"
|
||||
@ -49,8 +48,8 @@ class CuraConan(ConanFile):
|
||||
}
|
||||
|
||||
def set_version(self):
|
||||
if self.version == "auto":
|
||||
self.version = "5.4.0-alpha"
|
||||
if not self.version:
|
||||
self.version = "5.5.0-alpha"
|
||||
|
||||
@property
|
||||
def _pycharm_targets(self):
|
||||
@ -74,10 +73,6 @@ class CuraConan(ConanFile):
|
||||
self._cura_env.define("QT_XKB_CONFIG_ROOT", "/usr/share/X11/xkb")
|
||||
return self._cura_env
|
||||
|
||||
@property
|
||||
def _staging(self):
|
||||
return self.options.staging in ["True", 'true']
|
||||
|
||||
@property
|
||||
def _enterprise(self):
|
||||
return self.options.enterprise in ["True", 'true']
|
||||
@ -89,24 +84,10 @@ class CuraConan(ConanFile):
|
||||
return str(self.options.display_name)
|
||||
|
||||
@property
|
||||
def _cloud_api_root(self):
|
||||
return "https://api-staging.ultimaker.com" if self._staging else "https://api.ultimaker.com"
|
||||
|
||||
@property
|
||||
def _cloud_account_api_root(self):
|
||||
return "https://account-staging.ultimaker.com" if self._staging else "https://account.ultimaker.com"
|
||||
|
||||
@property
|
||||
def _marketplace_root(self):
|
||||
return "https://marketplace-staging.ultimaker.com" if self._staging else "https://marketplace.ultimaker.com"
|
||||
|
||||
@property
|
||||
def _digital_factory_url(self):
|
||||
return "https://digitalfactory-staging.ultimaker.com" if self._staging else "https://digitalfactory.ultimaker.com"
|
||||
|
||||
@property
|
||||
def _cura_latest_url(self):
|
||||
return "https://software.ultimaker.com/latest.json"
|
||||
def _urls(self):
|
||||
if self.options.staging in ["True", 'true']:
|
||||
return "staging"
|
||||
return "default"
|
||||
|
||||
@property
|
||||
def requirements_txts(self):
|
||||
@ -157,6 +138,37 @@ class CuraConan(ConanFile):
|
||||
return "'x86_64'"
|
||||
return "None"
|
||||
|
||||
def _generate_about_versions(self, location):
|
||||
with open(os.path.join(self.recipe_folder, "AboutDialogVersionsList.qml.jinja"), "r") as f:
|
||||
cura_version_py = Template(f.read())
|
||||
|
||||
conan_installs = []
|
||||
python_installs = []
|
||||
|
||||
# list of conan installs
|
||||
for _, dependency in self.dependencies.host.items():
|
||||
conan_installs.append([dependency.ref.name,dependency.ref.version])
|
||||
|
||||
#list of python installs
|
||||
outer = '"' if self.settings.os == "Windows" else "'"
|
||||
inner = "'" if self.settings.os == "Windows" else '"'
|
||||
python_ins_cmd = f"python -c {outer}import pkg_resources; print({inner};{inner}.join([(s.key+{inner},{inner}+ s.version) for s in pkg_resources.working_set])){outer}"
|
||||
from six import StringIO
|
||||
buffer = StringIO()
|
||||
self.run(python_ins_cmd, run_environment= True, env = "conanrun", output=buffer)
|
||||
|
||||
packages = str(buffer.getvalue()).split("-----------------\n")
|
||||
package = packages[1].strip('\r\n').split(";")
|
||||
for pack in package:
|
||||
python_installs.append(pack.split(","))
|
||||
|
||||
with open(os.path.join(location, "AboutDialogVersionsList.qml"), "w") as f:
|
||||
f.write(cura_version_py.render(
|
||||
conan_installs = conan_installs,
|
||||
python_installs = python_installs
|
||||
))
|
||||
|
||||
|
||||
def _generate_cura_version(self, location):
|
||||
with open(os.path.join(self.recipe_folder, "CuraVersion.py.jinja"), "r") as f:
|
||||
cura_version_py = Template(f.read())
|
||||
@ -176,12 +188,12 @@ class CuraConan(ConanFile):
|
||||
cura_version = cura_version,
|
||||
cura_build_type = "Enterprise" if self._enterprise else "",
|
||||
cura_debug_mode = self.options.cura_debug_mode,
|
||||
cura_cloud_api_root = self._cloud_api_root,
|
||||
cura_cloud_api_root = self.conan_data["urls"][self._urls]["cloud_api_root"],
|
||||
cura_cloud_api_version = self.options.cloud_api_version,
|
||||
cura_cloud_account_api_root = self._cloud_account_api_root,
|
||||
cura_marketplace_root = self._marketplace_root,
|
||||
cura_digital_factory_url = self._digital_factory_url,
|
||||
cura_latest_url = self._cura_latest_url))
|
||||
cura_cloud_account_api_root = self.conan_data["urls"][self._urls]["cloud_account_api_root"],
|
||||
cura_marketplace_root = self.conan_data["urls"][self._urls]["marketplace_root"],
|
||||
cura_digital_factory_url = self.conan_data["urls"][self._urls]["digital_factory_url"],
|
||||
cura_latest_url = self.conan_data["urls"][self._urls]["cura_latest_url"]))
|
||||
|
||||
def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file):
|
||||
pyinstaller_metadata = self.conan_data["pyinstaller"]
|
||||
@ -274,8 +286,6 @@ class CuraConan(ConanFile):
|
||||
copy(self, "requirements.txt", self.recipe_folder, self.export_sources_folder)
|
||||
copy(self, "requirements-dev.txt", self.recipe_folder, self.export_sources_folder)
|
||||
copy(self, "requirements-ultimaker.txt", self.recipe_folder, self.export_sources_folder)
|
||||
copy(self, "UltiMaker-Cura.spec.jinja", self.recipe_folder, self.export_sources_folder)
|
||||
copy(self, "CuraVersion.py.jinja", self.recipe_folder, self.export_sources_folder)
|
||||
copy(self, "cura_app.py", self.recipe_folder, self.export_sources_folder)
|
||||
|
||||
def configure(self):
|
||||
@ -283,6 +293,7 @@ class CuraConan(ConanFile):
|
||||
self.options["pysavitar"].shared = True
|
||||
self.options["pynest2d"].shared = True
|
||||
self.options["cpython"].shared = True
|
||||
self.options["boost"].header_only = True
|
||||
|
||||
def validate(self):
|
||||
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
|
||||
@ -290,16 +301,19 @@ class CuraConan(ConanFile):
|
||||
raise ConanInvalidConfiguration("Only versions 5+ are support")
|
||||
|
||||
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("pysavitar/5.2.2")
|
||||
self.requires("pynest2d/5.2.2")
|
||||
self.requires("pysavitar/(latest)@ultimaker/cura_10951")
|
||||
self.requires("pynest2d/(latest)@ultimaker/cura_10951")
|
||||
self.requires("uranium/(latest)@ultimaker/testing")
|
||||
self.requires("fdm_materials/(latest)@{}/testing".format("internal" if self.options.internal else "ultimaker"))
|
||||
self.requires("cura_binary_data/(latest)@ultimaker/testing")
|
||||
self.requires("cpython/3.10.4")
|
||||
if self.options.internal:
|
||||
self.requires("cura_private_data/(latest)@ultimaker/testing")
|
||||
self.requires("fdm_materials/(latest)@internal/testing")
|
||||
else:
|
||||
self.requires("fdm_materials/(latest)@ultimaker/testing")
|
||||
|
||||
def build_requirements(self):
|
||||
if self.options.devtools:
|
||||
@ -326,6 +340,38 @@ class CuraConan(ConanFile):
|
||||
vr.generate()
|
||||
|
||||
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:
|
||||
entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements"))
|
||||
@ -355,88 +401,56 @@ class CuraConan(ConanFile):
|
||||
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)
|
||||
|
||||
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):
|
||||
# Copy CuraEngine.exe to bindirs of Virtual Python Environment
|
||||
# TODO: Fix source such that it will get the curaengine relative from the executable (Python bindir in this case)
|
||||
self.copy_deps("CuraEngine.exe", root_package = "curaengine", src = self.deps_cpp_info["curaengine"].bindirs[0],
|
||||
dst = self._base_dir,
|
||||
keep_path = False)
|
||||
self.copy_deps("CuraEngine", root_package = "curaengine", src = self.deps_cpp_info["curaengine"].bindirs[0], dst = self._base_dir,
|
||||
keep_path = False)
|
||||
curaengine = self.dependencies["curaengine"].cpp_info
|
||||
copy(self, "CuraEngine.exe", curaengine.bindirs[0], str(self._base_dir), keep_path = False)
|
||||
copy(self, "CuraEngine", curaengine.bindirs[0], str(self._base_dir), keep_path = False)
|
||||
|
||||
# Copy resources of Cura (keep folder structure)
|
||||
self.copy("*", src = self.cpp_info.bindirs[0], dst = self._base_dir, keep_path = False)
|
||||
self.copy("*", src = self.cpp_info.libdirs[0], dst = self._site_packages.joinpath("cura"), keep_path = True)
|
||||
self.copy("*", src = self.cpp_info.resdirs[0], dst = self._share_dir.joinpath("cura", "resources"), keep_path = True)
|
||||
self.copy("*", src = self.cpp_info.resdirs[1], dst = self._share_dir.joinpath("cura", "plugins"), keep_path = True)
|
||||
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.bindirs[0]), str(self._base_dir), keep_path = False)
|
||||
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.libdirs[0]), str(self._site_packages.joinpath("cura")), keep_path = True)
|
||||
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.resdirs[0]), str(self._share_dir.joinpath("cura", "resources")), keep_path = True)
|
||||
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.resdirs[1]), str(self._share_dir.joinpath("cura", "plugins")), keep_path = True)
|
||||
|
||||
# Copy materials (flat)
|
||||
self.copy_deps("*.fdm_material", root_package = "fdm_materials", src = self.deps_cpp_info["fdm_materials"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources", "materials"), keep_path = False)
|
||||
self.copy_deps("*.sig", root_package = "fdm_materials", src = self.deps_cpp_info["fdm_materials"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura", "resources", "materials"), keep_path = False)
|
||||
fdm_materials = self.dependencies["fdm_materials"].cpp_info
|
||||
copy(self, "*", fdm_materials.resdirs[0], str(self._share_dir.joinpath("cura")))
|
||||
|
||||
# Copy internal resources
|
||||
if self.options.internal:
|
||||
self.copy_deps("*", 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)
|
||||
self.copy_deps("*", root_package = "cura_private_data", src = self.deps_cpp_info["cura_private_data"].resdirs[1],
|
||||
dst = self._share_dir.joinpath("cura", "plugins"), keep_path = True)
|
||||
cura_private_data = self.dependencies["cura_private_data"].cpp_info
|
||||
copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura")))
|
||||
|
||||
# Copy resources of Uranium (keep folder structure)
|
||||
self.copy_deps("*", root_package = "uranium", src = self.deps_cpp_info["uranium"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("uranium", "resources"), keep_path = True)
|
||||
self.copy_deps("*", root_package = "uranium", src = self.deps_cpp_info["uranium"].resdirs[1],
|
||||
dst = self._share_dir.joinpath("uranium", "plugins"), keep_path = True)
|
||||
self.copy_deps("*", root_package = "uranium", src = self.deps_cpp_info["uranium"].libdirs[0],
|
||||
dst = self._site_packages.joinpath("UM"),
|
||||
keep_path = True)
|
||||
self.copy_deps("*", root_package = "uranium", src = str(os.path.join(self.deps_cpp_info["uranium"].libdirs[0], "Qt", "qml", "UM")),
|
||||
dst = self._site_packages.joinpath("PyQt6", "Qt6", "qml", "UM"),
|
||||
keep_path = True)
|
||||
uranium = self.dependencies["uranium"].cpp_info
|
||||
copy(self, "*", uranium.resdirs[0], str(self._share_dir.joinpath("uranium", "resources")), keep_path = True)
|
||||
copy(self, "*", uranium.resdirs[1], str(self._share_dir.joinpath("uranium", "plugins")), keep_path = True)
|
||||
copy(self, "*", uranium.libdirs[0], str(self._site_packages.joinpath("UM")), keep_path = True)
|
||||
|
||||
# TODO: figure out if this is still needed
|
||||
copy(self, "*", os.path.join(uranium.libdirs[0], "Qt", "qml", "UM"), str(self._site_packages.joinpath("PyQt6", "Qt6", "qml", "UM")), keep_path = True)
|
||||
|
||||
# Copy resources of cura_binary_data
|
||||
self.copy_deps("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[0],
|
||||
dst = self._share_dir.joinpath("cura"), keep_path = True)
|
||||
self.copy_deps("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[1],
|
||||
dst = self._share_dir.joinpath("uranium"), keep_path = True)
|
||||
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":
|
||||
self.copy_deps("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[2],
|
||||
dst = self._share_dir.joinpath("windows"), keep_path = True)
|
||||
copy(self, "*", cura_binary_data.resdirs[2], str(self._share_dir.joinpath("windows")), keep_path = True)
|
||||
|
||||
self.copy_deps("*.dll", src = "@bindirs", dst = self._site_packages)
|
||||
self.copy_deps("*.pyd", src = "@libdirs", dst = self._site_packages)
|
||||
self.copy_deps("*.pyi", src = "@libdirs", dst = self._site_packages)
|
||||
self.copy_deps("*.dylib", src = "@libdirs", dst = self._base_dir.joinpath("lib"))
|
||||
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 packaging scripts
|
||||
self.copy("*", src = self.cpp_info.resdirs[2], dst = self._base_dir.joinpath("packaging"))
|
||||
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.resdirs[2]), str(self._base_dir.joinpath("packaging")), keep_path = True)
|
||||
|
||||
# Copy requirements.txt's
|
||||
self.copy("*.txt", src = self.cpp_info.resdirs[-1], dst = self._base_dir.joinpath("pip_requirements"))
|
||||
copy(self, "*.txt", os.path.join(self.package_folder, self.cpp_info.resdirs[-1]), str(self._base_dir.joinpath("pip_requirements")), keep_path = False)
|
||||
|
||||
# Generate the GitHub Action version info Environment
|
||||
version = self.conf_info.get("user.cura:version", default = self.version, check_type = str)
|
||||
@ -460,6 +474,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
|
||||
save(self, os.path.join(self._script_dir, f"activate_github_actions_version_env{ext}"), activate_github_actions_version_env)
|
||||
|
||||
self._generate_cura_version(os.path.join(self._site_packages, "cura"))
|
||||
self._generate_about_versions(str(self._share_dir.joinpath("cura", "resources", "qml", "Dialogs")))
|
||||
|
||||
entitlements_file = "'{}'".format(Path(self.cpp_info.res_paths[2], "MacOS", "cura.entitlements"))
|
||||
self._generate_pyinstaller_spec(location = self._base_dir,
|
||||
@ -467,6 +482,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
|
||||
icon_path = "'{}'".format(os.path.join(self.package_folder, self.cpp_info.resdirs[2], self.conan_data["pyinstaller"]["icon"][str(self.settings.os)])).replace("\\", "\\\\"),
|
||||
entitlements_file = entitlements_file if self.settings.os == "Macos" else "None")
|
||||
|
||||
|
||||
def package(self):
|
||||
copy(self, "cura_app.py", src = self.source_folder, dst = os.path.join(self.package_folder, self.cpp.package.bindirs[0]))
|
||||
copy(self, "*", src = os.path.join(self.source_folder, "cura"), dst = os.path.join(self.package_folder, self.cpp.package.libdirs[0]))
|
||||
|
@ -14,7 +14,7 @@ DEFAULT_CURA_LATEST_URL = "https://software.ultimaker.com/latest.json"
|
||||
# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for
|
||||
# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the
|
||||
# CuraVersion.py.in template.
|
||||
CuraSDKVersion = "8.3.0"
|
||||
CuraSDKVersion = "8.4.0"
|
||||
|
||||
try:
|
||||
from cura.CuraVersion import CuraLatestURL
|
||||
|
@ -8,17 +8,20 @@ from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
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")
|
||||
|
||||
|
||||
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__()
|
||||
self._nodes = nodes
|
||||
self._fixed_nodes = fixed_nodes
|
||||
self._min_offset = min_offset
|
||||
self._grid_arrange = grid_arrange
|
||||
|
||||
def run(self):
|
||||
found_solution_for_all = False
|
||||
@ -29,10 +32,18 @@ class ArrangeObjectsJob(Job):
|
||||
title = i18n_catalog.i18nc("@info:title", "Finding Location"))
|
||||
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:
|
||||
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
|
||||
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()
|
||||
|
||||
|
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
|
347
cura/Arranging/GridArrange.py
Normal file
347
cura/Arranging/GridArrange.py
Normal file
@ -0,0 +1,347 @@
|
||||
import math
|
||||
from typing import List, TYPE_CHECKING, Tuple, Set, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from cura.BuildVolume import BuildVolume
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
from UM.Math.Polygon import Polygon
|
||||
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, this assures that new objects will
|
||||
# be placed on integer offsets from each other
|
||||
grid_precision = 10 # 1cm
|
||||
rounded_grid_width = math.ceil(self._grid_width / grid_precision) * grid_precision
|
||||
rounded_grid_height = math.ceil(self._grid_height / grid_precision) * grid_precision
|
||||
|
||||
# The space added by the "grid precision rounding up" of the grid size
|
||||
self._grid_round_margin_x = rounded_grid_width - self._grid_width
|
||||
self._grid_round_margin_y = rounded_grid_height - self._grid_height
|
||||
|
||||
self._grid_width = rounded_grid_width
|
||||
self._grid_height = rounded_grid_height
|
||||
|
||||
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._intersectingGridIdxInclusive(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,
|
||||
bounds: Union[AxisAlignedBox, Polygon],
|
||||
*,
|
||||
margin_x: float = 0.0,
|
||||
margin_y: float = 0.0
|
||||
) -> Tuple[float, float, float, float]:
|
||||
if isinstance(bounds, AxisAlignedBox):
|
||||
coord_x1 = bounds.left - margin_x
|
||||
coord_x2 = bounds.right + margin_x
|
||||
coord_y1 = bounds.back - margin_y
|
||||
coord_y2 = bounds.front + margin_y
|
||||
elif isinstance(bounds, Polygon):
|
||||
coord_x1 = float('inf')
|
||||
coord_y1 = float('inf')
|
||||
coord_x2 = float('-inf')
|
||||
coord_y2 = float('-inf')
|
||||
for x, y in bounds.getPoints():
|
||||
coord_x1 = min(coord_x1, x)
|
||||
coord_y1 = min(coord_y1, y)
|
||||
coord_x2 = max(coord_x2, x)
|
||||
coord_y2 = max(coord_y2, y)
|
||||
else:
|
||||
raise TypeError("bounds must be either an AxisAlignedBox or a Polygon")
|
||||
|
||||
coord_x1 -= margin_x
|
||||
coord_x2 += margin_x
|
||||
coord_y1 -= margin_y
|
||||
coord_y2 += margin_y
|
||||
|
||||
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 _intersectingGridIdxInclusive(self, bounds: Union[AxisAlignedBox, Polygon]) -> Set[Tuple[int, int]]:
|
||||
grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(
|
||||
bounds,
|
||||
margin_x=-(self._margin_x + self._grid_round_margin_x) * 0.5,
|
||||
margin_y=-(self._margin_y + self._grid_round_margin_y) * 0.5,
|
||||
)
|
||||
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, bounds: Union[AxisAlignedBox, Polygon]) -> Set[Tuple[int, int]]:
|
||||
grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(
|
||||
bounds,
|
||||
margin_x=(self._margin_x + self._grid_round_margin_x) * 0.5,
|
||||
margin_y=(self._margin_y + self._grid_round_margin_y) * 0.5,
|
||||
)
|
||||
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,148 +15,137 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.RotateOperation import RotateOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
|
||||
from cura.Arranging.Arranger import Arranger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
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]]:
|
||||
"""
|
||||
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 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 accurate we want it to be.
|
||||
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):
|
||||
"""
|
||||
: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 lock_rotation: If set to true the orientation of the object will remain the same
|
||||
"""
|
||||
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
|
||||
|
||||
: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.
|
||||
def findNodePlacement(self) -> Tuple[bool, List[Item]]:
|
||||
spacing = int(1.5 * self._factor) # 1.5mm spacing.
|
||||
|
||||
machine_width = build_volume.getWidth()
|
||||
machine_depth = build_volume.getDepth()
|
||||
build_plate_bounding_box = Box(int(machine_width * factor), int(machine_depth * factor))
|
||||
machine_width = self._build_volume.getWidth()
|
||||
machine_depth = self._build_volume.getDepth()
|
||||
build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor))
|
||||
|
||||
if fixed_nodes is None:
|
||||
fixed_nodes = []
|
||||
if self._fixed_nodes is None:
|
||||
self._fixed_nodes = []
|
||||
|
||||
# Add all the items we want to arrange
|
||||
node_items = []
|
||||
for node in nodes_to_arrange:
|
||||
hull_polygon = node.callDecoration("getConvexHull")
|
||||
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()))
|
||||
continue
|
||||
converted_points = []
|
||||
for point in hull_polygon.getPoints():
|
||||
converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
|
||||
item = Item(converted_points)
|
||||
node_items.append(item)
|
||||
|
||||
# Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas)
|
||||
half_machine_width = 0.5 * machine_width - 1
|
||||
half_machine_depth = 0.5 * machine_depth - 1
|
||||
build_plate_polygon = Polygon(numpy.array([
|
||||
[half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, half_machine_depth],
|
||||
[half_machine_width, half_machine_depth]
|
||||
], numpy.float32))
|
||||
|
||||
disallowed_areas = build_volume.getDisallowedAreas()
|
||||
num_disallowed_areas_added = 0
|
||||
for area in disallowed_areas:
|
||||
converted_points = []
|
||||
|
||||
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
||||
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
|
||||
for point in clipped_area.getPoints():
|
||||
converted_points.append(Point(int(point[0] * factor), int(point[1] * factor)))
|
||||
|
||||
disallowed_area = Item(converted_points)
|
||||
disallowed_area.markAsDisallowedAreaInBin(0)
|
||||
node_items.append(disallowed_area)
|
||||
num_disallowed_areas_added += 1
|
||||
|
||||
for node in fixed_nodes:
|
||||
converted_points = []
|
||||
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
|
||||
# Add all the items we want to arrange
|
||||
node_items = []
|
||||
for node in self._nodes_to_arrange:
|
||||
hull_polygon = node.callDecoration("getConvexHull")
|
||||
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()))
|
||||
continue
|
||||
converted_points = []
|
||||
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.markAsFixedInBin(0)
|
||||
node_items.append(item)
|
||||
num_disallowed_areas_added += 1
|
||||
|
||||
config = NfpConfig()
|
||||
config.accuracy = 1.0
|
||||
# Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas)
|
||||
half_machine_width = 0.5 * machine_width - 1
|
||||
half_machine_depth = 0.5 * machine_depth - 1
|
||||
build_plate_polygon = Polygon(numpy.array([
|
||||
[half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, half_machine_depth],
|
||||
[half_machine_width, half_machine_depth]
|
||||
], numpy.float32))
|
||||
|
||||
num_bins = nest(node_items, build_plate_bounding_box, spacing, config)
|
||||
disallowed_areas = self._build_volume.getDisallowedAreas()
|
||||
num_disallowed_areas_added = 0
|
||||
for area in disallowed_areas:
|
||||
converted_points = []
|
||||
|
||||
# Strip the fixed items (previously placed) and the disallowed areas from the results again.
|
||||
node_items = list(filter(lambda item: not item.isFixed(), node_items))
|
||||
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
||||
clipped_area = area.intersectionConvexHulls(build_plate_polygon)
|
||||
|
||||
found_solution_for_all = num_bins == 1
|
||||
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():
|
||||
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||
|
||||
return found_solution_for_all, node_items
|
||||
disallowed_area = Item(converted_points)
|
||||
disallowed_area.markAsDisallowedAreaInBin(0)
|
||||
node_items.append(disallowed_area)
|
||||
num_disallowed_areas_added += 1
|
||||
|
||||
for node in self._fixed_nodes:
|
||||
converted_points = []
|
||||
hull_polygon = node.callDecoration("getConvexHull")
|
||||
|
||||
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()
|
||||
found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor)
|
||||
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():
|
||||
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||
item = Item(converted_points)
|
||||
item.markAsFixedInBin(0)
|
||||
node_items.append(item)
|
||||
num_disallowed_areas_added += 1
|
||||
|
||||
not_fit_count = 0
|
||||
grouped_operation = GroupedOperation()
|
||||
for node, node_item in zip(nodes_to_arrange, node_items):
|
||||
if add_new_nodes_in_scene:
|
||||
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
||||
config = NfpConfig()
|
||||
config.accuracy = 1.0
|
||||
config.alignment = NfpConfig.Alignment.DONT_ALIGN
|
||||
if self._lock_rotation:
|
||||
config.rotations = [0.0]
|
||||
|
||||
if node_item.binId() == 0:
|
||||
# We found a spot for it
|
||||
rotation_matrix = Matrix()
|
||||
rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0))
|
||||
grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
|
||||
grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0,
|
||||
node_item.translation().y() / factor)))
|
||||
else:
|
||||
# We didn't find a spot
|
||||
grouped_operation.addOperation(
|
||||
TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True))
|
||||
not_fit_count += 1
|
||||
num_bins = nest(node_items, build_plate_bounding_box, spacing, config)
|
||||
|
||||
return grouped_operation, not_fit_count
|
||||
# Strip the fixed items (previously placed) and the disallowed areas from the results again.
|
||||
node_items = list(filter(lambda item: not item.isFixed(), node_items))
|
||||
|
||||
found_solution_for_all = num_bins == 1
|
||||
|
||||
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, node_items
|
||||
|
||||
:return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
||||
"""
|
||||
def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]:
|
||||
scene_root = Application.getInstance().getController().getScene().getRoot()
|
||||
found_solution_for_all, node_items = self.findNodePlacement()
|
||||
|
||||
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
|
||||
not_fit_count = 0
|
||||
grouped_operation = GroupedOperation()
|
||||
for node, node_item in zip(self._nodes_to_arrange, node_items):
|
||||
if add_new_nodes_in_scene:
|
||||
grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))
|
||||
|
||||
if node_item.binId() == 0:
|
||||
# We found a spot for it
|
||||
rotation_matrix = Matrix()
|
||||
rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0))
|
||||
grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
|
||||
grouped_operation.addOperation(
|
||||
TranslateOperation(node, Vector(node_item.translation().x() / self._factor, 0,
|
||||
node_item.translation().y() / self._factor)))
|
||||
else:
|
||||
# We didn't find a spot
|
||||
grouped_operation.addOperation(
|
||||
TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True))
|
||||
not_fit_count += 1
|
||||
|
||||
return grouped_operation, not_fit_count
|
||||
|
@ -203,6 +203,9 @@ class BuildVolume(SceneNode):
|
||||
if shape:
|
||||
self._shape = shape
|
||||
|
||||
def getShape(self) -> str:
|
||||
return self._shape
|
||||
|
||||
def getDiagonalSize(self) -> float:
|
||||
"""Get the length of the 3D diagonal through the build volume.
|
||||
|
||||
@ -648,11 +651,13 @@ class BuildVolume(SceneNode):
|
||||
self._width = self._global_container_stack.getProperty("machine_width", "value")
|
||||
machine_height = self._global_container_stack.getProperty("machine_height", "value")
|
||||
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
|
||||
self._height = min(self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z, machine_height)
|
||||
if self._height < (machine_height * self._scale_vector.z):
|
||||
new_height = min(self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z, machine_height)
|
||||
|
||||
if self._height > new_height:
|
||||
self._build_volume_message.show()
|
||||
else:
|
||||
elif self._height < new_height:
|
||||
self._build_volume_message.hide()
|
||||
self._height = new_height
|
||||
else:
|
||||
self._height = self._global_container_stack.getProperty("machine_height", "value")
|
||||
self._build_volume_message.hide()
|
||||
@ -690,11 +695,15 @@ class BuildVolume(SceneNode):
|
||||
if setting_key == "print_sequence":
|
||||
machine_height = self._global_container_stack.getProperty("machine_height", "value")
|
||||
if self._application.getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
|
||||
self._height = min(self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z, machine_height)
|
||||
if self._height < (machine_height * self._scale_vector.z):
|
||||
new_height = min(
|
||||
self._global_container_stack.getProperty("gantry_height", "value") * self._scale_vector.z,
|
||||
machine_height)
|
||||
|
||||
if self._height > new_height:
|
||||
self._build_volume_message.show()
|
||||
else:
|
||||
elif self._height < new_height:
|
||||
self._build_volume_message.hide()
|
||||
self._height = new_height
|
||||
else:
|
||||
self._height = self._global_container_stack.getProperty("machine_height", "value") * self._scale_vector.z
|
||||
self._build_volume_message.hide()
|
||||
|
@ -22,7 +22,7 @@ except ImportError:
|
||||
|
||||
from PyQt6.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QUrl
|
||||
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QCheckBox, QPushButton
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from PyQt6.QtGui import QDesktopServices, QTextCursor
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
@ -309,7 +309,7 @@ class CrashHandler:
|
||||
trace = "".join(trace_list)
|
||||
text_area.setText(trace)
|
||||
text_area.setReadOnly(True)
|
||||
|
||||
text_area.moveCursor(QTextCursor.MoveOperation.End) # Move cursor to end, so we see last bit of the exception
|
||||
layout.addWidget(text_area)
|
||||
group.setLayout(layout)
|
||||
|
||||
@ -400,7 +400,7 @@ class CrashHandler:
|
||||
|
||||
text_area.setText(logdata)
|
||||
text_area.setReadOnly(True)
|
||||
|
||||
text_area.moveCursor(QTextCursor.MoveOperation.End) # Move cursor to end, so we see last bit of the log
|
||||
layout.addWidget(text_area)
|
||||
group.setLayout(layout)
|
||||
|
||||
|
@ -1,15 +1,18 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2023 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt6.QtCore import QObject, QUrl
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from typing import List, cast
|
||||
|
||||
from PyQt6.QtCore import QObject, QUrl, QMimeData
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
|
||||
from UM.Event import CallFunctionEvent
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
@ -20,6 +23,10 @@ from cura.MultiplyObjectsJob import MultiplyObjectsJob
|
||||
from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
from cura.Arranging.GridArrange import GridArrange
|
||||
from cura.Arranging.Nest2DArrange import Nest2DArrange
|
||||
|
||||
|
||||
from cura.Operations.SetBuildPlateNumberOperation import SetBuildPlateNumberOperation
|
||||
|
||||
from UM.Logger import Logger
|
||||
@ -78,16 +85,25 @@ class CuraActions(QObject):
|
||||
center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position = True)
|
||||
operation.addOperation(center_operation)
|
||||
operation.push()
|
||||
|
||||
@pyqtSlot(int)
|
||||
def multiplySelection(self, count: int) -> None:
|
||||
"""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.
|
||||
"""
|
||||
|
||||
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()
|
||||
|
||||
@pyqtSlot()
|
||||
@ -181,5 +197,60 @@ class CuraActions(QObject):
|
||||
|
||||
Selection.clear()
|
||||
|
||||
@pyqtSlot()
|
||||
def cut(self) -> None:
|
||||
self.copy()
|
||||
self.deleteSelection()
|
||||
|
||||
@pyqtSlot()
|
||||
def copy(self) -> None:
|
||||
mesh_writer = cura.CuraApplication.CuraApplication.getInstance().getMeshFileHandler().getWriter("3MFWriter")
|
||||
if not mesh_writer:
|
||||
Logger.log("e", "No 3MF writer found, unable to copy.")
|
||||
return
|
||||
|
||||
# Get the selected nodes
|
||||
selected_objects = Selection.getAllSelectedObjects()
|
||||
# Serialize the nodes to a string
|
||||
scene_string = mesh_writer.sceneNodesToString(selected_objects)
|
||||
# Put the string on the clipboard
|
||||
QApplication.clipboard().setText(scene_string)
|
||||
|
||||
@pyqtSlot()
|
||||
def paste(self) -> None:
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
mesh_reader = application.getMeshFileHandler().getReaderForFile(".3mf")
|
||||
if not mesh_reader:
|
||||
Logger.log("e", "No 3MF reader found, unable to paste.")
|
||||
return
|
||||
|
||||
# Parse the scene from the clipboard
|
||||
scene_string = QApplication.clipboard().text()
|
||||
|
||||
nodes = mesh_reader.stringToSceneNodes(scene_string)
|
||||
|
||||
if not nodes:
|
||||
# Nothing to paste
|
||||
return
|
||||
|
||||
# Find all fixed nodes, these are the nodes that should be avoided when arranging
|
||||
fixed_nodes = []
|
||||
root = application.getController().getScene().getRoot()
|
||||
for node in DepthFirstIterator(root):
|
||||
# Only count sliceable objects
|
||||
if node.callDecoration("isSliceable"):
|
||||
fixed_nodes.append(node)
|
||||
# Add the new nodes to the scene, and arrange them
|
||||
|
||||
arranger = GridArrange(nodes, application.getBuildVolume(), fixed_nodes)
|
||||
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene = True)
|
||||
group_operation.push()
|
||||
|
||||
# deselect currently selected nodes, and select the new nodes
|
||||
for node in Selection.getAllSelectedObjects():
|
||||
Selection.remove(node)
|
||||
for node in nodes:
|
||||
Selection.add(node)
|
||||
|
||||
def _openUrl(self, url: QUrl) -> None:
|
||||
QDesktopServices.openUrl(url)
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Copyright (c) 2022 Ultimaker B.V.
|
||||
# Copyright (c) 2023 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
import enum
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import platform
|
||||
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict
|
||||
|
||||
import numpy
|
||||
@ -53,7 +54,6 @@ from cura import ApplicationMetadata
|
||||
from cura.API import CuraAPI
|
||||
from cura.API.Account import Account
|
||||
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
|
||||
from cura.Arranging.Nest2DArrange import arrange
|
||||
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
||||
from cura.Machines.Models.BuildPlateModel import BuildPlateModel
|
||||
from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel
|
||||
@ -114,6 +114,7 @@ from . import CameraAnimation
|
||||
from . import CuraActions
|
||||
from . import PlatformPhysics
|
||||
from . import PrintJobPreviewImageProvider
|
||||
from .Arranging.Nest2DArrange import Nest2DArrange
|
||||
from .AutoSave import AutoSave
|
||||
from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
||||
from .Machines.Models.MachineListModel import MachineListModel
|
||||
@ -130,7 +131,7 @@ class CuraApplication(QtApplication):
|
||||
# SettingVersion represents the set of settings available in the machine/extruder definitions.
|
||||
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
|
||||
# changes of the settings.
|
||||
SettingVersion = 21
|
||||
SettingVersion = 22
|
||||
|
||||
Created = False
|
||||
|
||||
@ -147,6 +148,7 @@ class CuraApplication(QtApplication):
|
||||
DefinitionChangesContainer = Resources.UserType + 10
|
||||
SettingVisibilityPreset = Resources.UserType + 11
|
||||
IntentInstanceContainer = Resources.UserType + 12
|
||||
ImageFiles = Resources.UserType + 13
|
||||
|
||||
pyqtEnum(ResourceTypes)
|
||||
|
||||
@ -407,6 +409,9 @@ class CuraApplication(QtApplication):
|
||||
|
||||
SettingFunction.registerOperator("extruderValue", self._cura_formula_functions.getValueInExtruder)
|
||||
SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders)
|
||||
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("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition)
|
||||
SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex)
|
||||
@ -425,6 +430,7 @@ class CuraApplication(QtApplication):
|
||||
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
||||
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
|
||||
Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent")
|
||||
Resources.addStorageType(self.ResourceTypes.ImageFiles, "images")
|
||||
|
||||
self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
|
||||
@ -435,6 +441,7 @@ class CuraApplication(QtApplication):
|
||||
self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent")
|
||||
self._container_registry.addResourceType(self.ResourceTypes.ImageFiles, "images")
|
||||
|
||||
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
||||
Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
||||
@ -490,6 +497,36 @@ class CuraApplication(QtApplication):
|
||||
def startSplashWindowPhase(self) -> None:
|
||||
"""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()
|
||||
|
||||
if not self.getIsHeadLess():
|
||||
@ -498,33 +535,7 @@ class CuraApplication(QtApplication):
|
||||
except FileNotFoundError:
|
||||
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._update_platform_activity_timer = QTimer()
|
||||
@ -824,6 +835,8 @@ class CuraApplication(QtApplication):
|
||||
def run(self):
|
||||
super().run()
|
||||
|
||||
self._log_hardware_info()
|
||||
|
||||
if len(ApplicationMetadata.DEPENDENCY_INFO) > 0:
|
||||
Logger.debug("Using Conan managed dependencies: " + ", ".join(
|
||||
[dep["recipe"]["id"] for dep in ApplicationMetadata.DEPENDENCY_INFO["installed"] if dep["recipe"]["version"] != "latest"]))
|
||||
@ -897,6 +910,14 @@ class CuraApplication(QtApplication):
|
||||
|
||||
self.exec()
|
||||
|
||||
def _log_hardware_info(self):
|
||||
hardware_info = platform.uname()
|
||||
Logger.info(f"System: {hardware_info.system}")
|
||||
Logger.info(f"Release: {hardware_info.release}")
|
||||
Logger.info(f"Version: {hardware_info.version}")
|
||||
Logger.info(f"Processor name: {hardware_info.processor}")
|
||||
Logger.info(f"CPU Cores: {os.cpu_count()}")
|
||||
|
||||
def __setUpSingleInstanceServer(self):
|
||||
if self._use_single_instance:
|
||||
self._single_instance.startServer()
|
||||
@ -1423,6 +1444,13 @@ class CuraApplication(QtApplication):
|
||||
# Single build plate
|
||||
@pyqtSlot()
|
||||
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 = []
|
||||
active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate
|
||||
locked_nodes = []
|
||||
@ -1452,17 +1480,17 @@ class CuraApplication(QtApplication):
|
||||
locked_nodes.append(node)
|
||||
else:
|
||||
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
|
||||
|
||||
:param nodes: nodes that we have to place
|
||||
: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
|
||||
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()
|
||||
|
||||
@pyqtSlot()
|
||||
@ -1949,7 +1977,8 @@ class CuraApplication(QtApplication):
|
||||
if select_models_on_load:
|
||||
Selection.add(node)
|
||||
try:
|
||||
arrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes)
|
||||
arranger = Nest2DArrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes)
|
||||
arranger.arrange()
|
||||
except:
|
||||
Logger.logException("e", "Failed to arrange the models")
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2023 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
import glob
|
||||
import os
|
||||
@ -55,7 +55,9 @@ class CuraPackageManager(PackageManager):
|
||||
def initialize(self) -> None:
|
||||
self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
|
||||
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
|
||||
self._installation_dirs_dict["variants"] = Resources.getStoragePath(CuraApplication.ResourceTypes.VariantInstanceContainer)
|
||||
self._installation_dirs_dict["variants"] = Resources.getStoragePath(
|
||||
CuraApplication.ResourceTypes.VariantInstanceContainer)
|
||||
self._installation_dirs_dict["images"] = Resources.getStoragePath(CuraApplication.ResourceTypes.ImageFiles)
|
||||
|
||||
# Due to a bug in Cura 5.1.0 we needed to change the directory structure of the curapackage on the server side (See SD-3871).
|
||||
# Although the material intent profiles will be installed in the `intent` folder, the curapackage from the server side will
|
||||
|
@ -14,6 +14,7 @@ from cura.Machines.QualityChangesGroup import QualityChangesGroup # To construc
|
||||
from cura.Machines.QualityGroup import QualityGroup # To construct groups of quality profiles that belong together.
|
||||
from cura.Machines.QualityNode import QualityNode
|
||||
from cura.Machines.VariantNode import VariantNode
|
||||
from cura.Machines.MaterialNode import MaterialNode
|
||||
import UM.FlameProfiler
|
||||
|
||||
|
||||
@ -167,13 +168,20 @@ class MachineNode(ContainerNode):
|
||||
|
||||
return self.global_qualities.get(self.preferred_quality_type, next(iter(self.global_qualities.values())))
|
||||
|
||||
def isExcludedMaterial(self, material: MaterialNode) -> bool:
|
||||
"""Returns whether the material should be excluded from the list of materials."""
|
||||
for exclude_material in self.exclude_materials:
|
||||
if exclude_material in material["id"]:
|
||||
return True
|
||||
return False
|
||||
|
||||
@UM.FlameProfiler.profile
|
||||
def _loadAll(self) -> None:
|
||||
"""(Re)loads all variants under this printer."""
|
||||
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
if not self.has_variants:
|
||||
self.variants["empty"] = VariantNode("empty_variant", machine = self)
|
||||
self.variants["empty"] = VariantNode("empty_variant", machine=self)
|
||||
self.variants["empty"].materialsChanged.connect(self.materialsChanged)
|
||||
else:
|
||||
# Find all the variants for this definition ID.
|
||||
|
@ -53,6 +53,12 @@ class IntentCategoryModel(ListModel):
|
||||
"name": catalog.i18nc("@label", "Draft"),
|
||||
"description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.")
|
||||
}
|
||||
cls._translations["annealing"] = {
|
||||
"name": catalog.i18nc("@label", "Annealing"),
|
||||
"description": catalog.i18nc("@text",
|
||||
"The annealing profile requires post-processing in an oven after the print is finished. This profile retains the dimensional accuracy of the printed part after annealing and improves strength, stiffness, and thermal resistance.")
|
||||
|
||||
}
|
||||
return cls._translations
|
||||
|
||||
def __init__(self, intent_category: str) -> None:
|
||||
|
@ -1,29 +1,32 @@
|
||||
# Copyright (c) 2022 Ultimaker B.V.
|
||||
# Copyright (c) 2023 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import collections
|
||||
from typing import OrderedDict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from PyQt6.QtCore import Qt, QTimer, QObject
|
||||
from PyQt6.QtCore import Qt, QTimer, QObject, QUrl
|
||||
|
||||
import cura
|
||||
from UM import i18nCatalog
|
||||
from UM.Logger import Logger
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.Resources import Resources
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.Interfaces import ContainerInterface
|
||||
|
||||
from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel
|
||||
from cura.Settings.IntentManager import IntentManager
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
||||
class IntentSelectionModel(ListModel):
|
||||
|
||||
NameRole = Qt.ItemDataRole.UserRole + 1
|
||||
IntentCategoryRole = Qt.ItemDataRole.UserRole + 2
|
||||
WeightRole = Qt.ItemDataRole.UserRole + 3
|
||||
DescriptionRole = Qt.ItemDataRole.UserRole + 4
|
||||
IconRole = Qt.ItemDataRole.UserRole + 5
|
||||
CustomIconRole = Qt.ItemDataRole.UserRole + 6
|
||||
|
||||
def __init__(self, parent: Optional[QObject] = None) -> None:
|
||||
super().__init__(parent)
|
||||
@ -33,6 +36,7 @@ class IntentSelectionModel(ListModel):
|
||||
self.addRoleName(self.WeightRole, "weight")
|
||||
self.addRoleName(self.DescriptionRole, "description")
|
||||
self.addRoleName(self.IconRole, "icon")
|
||||
self.addRoleName(self.CustomIconRole, "custom_icon")
|
||||
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
|
||||
@ -53,30 +57,8 @@ class IntentSelectionModel(ListModel):
|
||||
|
||||
self._onChange()
|
||||
|
||||
@staticmethod
|
||||
def _getDefaultProfileInformation() -> OrderedDict[str, dict]:
|
||||
""" Default information user-visible string. Ordered by weight. """
|
||||
default_profile_information = collections.OrderedDict()
|
||||
default_profile_information["default"] = {
|
||||
"name": catalog.i18nc("@label", "Default"),
|
||||
"icon": "GearCheck"
|
||||
}
|
||||
default_profile_information["visual"] = {
|
||||
"name": catalog.i18nc("@label", "Visual"),
|
||||
"description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality."),
|
||||
"icon" : "Visual"
|
||||
}
|
||||
default_profile_information["engineering"] = {
|
||||
"name": catalog.i18nc("@label", "Engineering"),
|
||||
"description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances."),
|
||||
"icon": "Nut"
|
||||
}
|
||||
default_profile_information["quick"] = {
|
||||
"name": catalog.i18nc("@label", "Draft"),
|
||||
"description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction."),
|
||||
"icon": "SpeedOMeter"
|
||||
}
|
||||
return default_profile_information
|
||||
_default_intent_categories = ["default", "visual", "engineering", "quick", "annealing"]
|
||||
_icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter", "annealing": "Anneal"}
|
||||
|
||||
def _onContainerChange(self, container: ContainerInterface) -> None:
|
||||
"""Updates the list of intents if an intent profile was added or removed."""
|
||||
@ -89,38 +71,63 @@ class IntentSelectionModel(ListModel):
|
||||
|
||||
def _update(self) -> None:
|
||||
Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
|
||||
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
cura_application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
global_stack = cura_application.getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
self.setItems([])
|
||||
Logger.log("d", "No active GlobalStack, set quality profile model as empty.")
|
||||
return
|
||||
|
||||
# Check for material compatibility
|
||||
if not cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMaterialsCompatible():
|
||||
if not cura_application.getMachineManager().activeMaterialsCompatible():
|
||||
Logger.log("d", "No active material compatibility, set quality profile model as empty.")
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
default_profile_info = self._getDefaultProfileInformation()
|
||||
|
||||
available_categories = IntentManager.getInstance().currentAvailableIntentCategories()
|
||||
|
||||
result = []
|
||||
for i, category in enumerate(available_categories):
|
||||
profile_info = default_profile_info.get(category, {})
|
||||
for category in available_categories:
|
||||
|
||||
try:
|
||||
weight = list(default_profile_info.keys()).index(category)
|
||||
except ValueError:
|
||||
weight = len(available_categories) + i
|
||||
if category in self._default_intent_categories:
|
||||
result.append({
|
||||
"name": IntentCategoryModel.translation(category, "name", category.title()),
|
||||
"description": IntentCategoryModel.translation(category, "description", None),
|
||||
"icon": self._icons[category],
|
||||
"custom_icon": None,
|
||||
"intent_category": category,
|
||||
"weight": self._default_intent_categories.index(category),
|
||||
})
|
||||
else:
|
||||
# There can be multiple intents with the same category, use one of these
|
||||
# intent-metadata's for the icon/description defintions for the intent
|
||||
|
||||
result.append({
|
||||
"name": profile_info.get("name", category.title()),
|
||||
"description": profile_info.get("description", None),
|
||||
"icon" : profile_info.get("icon", ""),
|
||||
"intent_category": category,
|
||||
"weight": weight,
|
||||
})
|
||||
|
||||
|
||||
intent_metadata = cura_application.getContainerRegistry().findContainersMetadata(type="intent",
|
||||
definition=global_stack.findInstanceContainerDefinitionId(global_stack.definition),
|
||||
intent_category=category)[0]
|
||||
|
||||
intent_name = intent_metadata.get("name", category.title())
|
||||
icon = intent_metadata.get("icon", None)
|
||||
description = intent_metadata.get("description", None)
|
||||
|
||||
if icon is not None and icon != '':
|
||||
try:
|
||||
icon = QUrl.fromLocalFile(
|
||||
Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.ImageFiles, icon))
|
||||
except (FileNotFoundError, NotADirectoryError, PermissionError):
|
||||
Logger.log("e", f"Icon file for intent {intent_name} not found.")
|
||||
icon = None
|
||||
|
||||
result.append({
|
||||
"name": intent_name,
|
||||
"description": description,
|
||||
"custom_icon": icon,
|
||||
"icon": None,
|
||||
"intent_category": category,
|
||||
"weight": 5,
|
||||
})
|
||||
|
||||
result.sort(key=lambda k: k["weight"])
|
||||
|
||||
|
@ -110,22 +110,22 @@ class MachineListModel(ListModel):
|
||||
|
||||
for abstract_machine in abstract_machine_stacks:
|
||||
definition_id = abstract_machine.definition.getId()
|
||||
online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True)
|
||||
connected_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = False)
|
||||
|
||||
online_machine_stacks = list(filter(lambda machine: machine.hasNetworkedConnection(), online_machine_stacks))
|
||||
online_machine_stacks.sort(key=lambda machine: machine.getName().upper())
|
||||
connected_machine_stacks = list(filter(lambda machine: machine.hasNetworkedConnection(), connected_machine_stacks))
|
||||
connected_machine_stacks.sort(key=lambda machine: machine.getName().upper())
|
||||
|
||||
if abstract_machine in other_machine_stacks:
|
||||
other_machine_stacks.remove(abstract_machine)
|
||||
|
||||
if abstract_machine in online_machine_stacks:
|
||||
online_machine_stacks.remove(abstract_machine)
|
||||
if abstract_machine in connected_machine_stacks:
|
||||
connected_machine_stacks.remove(abstract_machine)
|
||||
|
||||
# Create a list item for abstract machine
|
||||
self.addItem(abstract_machine, True, len(online_machine_stacks))
|
||||
self.addItem(abstract_machine, True, len(connected_machine_stacks))
|
||||
|
||||
# Create list of machines that are children of the abstract machine
|
||||
for stack in online_machine_stacks:
|
||||
for stack in connected_machine_stacks:
|
||||
if self._show_cloud_printers:
|
||||
self.addItem(stack, True)
|
||||
# Remove this machine from the other stack list
|
||||
|
@ -60,7 +60,7 @@ class VariantNode(ContainerNode):
|
||||
materials = list(materials_per_base_file.values())
|
||||
|
||||
# Filter materials based on the exclude_materials property.
|
||||
filtered_materials = [material for material in materials if material["id"] not in self.machine.exclude_materials]
|
||||
filtered_materials = [material for material in materials if not self.machine.isExcludedMaterial(material)]
|
||||
|
||||
for material in filtered_materials:
|
||||
base_file = material["base_file"]
|
||||
|
@ -14,17 +14,19 @@ from UM.Operations.TranslateOperation import TranslateOperation
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
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")
|
||||
|
||||
|
||||
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__()
|
||||
self._objects = objects
|
||||
self._count = count
|
||||
self._min_offset = min_offset
|
||||
self._count: int = count
|
||||
self._min_offset: int = min_offset
|
||||
self._grid_arrange: bool = grid_arrange
|
||||
|
||||
def run(self) -> None:
|
||||
status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0,
|
||||
@ -39,7 +41,7 @@ class MultiplyObjectsJob(Job):
|
||||
|
||||
root = scene.getRoot()
|
||||
|
||||
processed_nodes = [] # type: List[SceneNode]
|
||||
processed_nodes: List[SceneNode] = []
|
||||
nodes = []
|
||||
|
||||
fixed_nodes = []
|
||||
@ -76,12 +78,12 @@ class MultiplyObjectsJob(Job):
|
||||
found_solution_for_all = True
|
||||
group_operation = GroupedOperation()
|
||||
if nodes:
|
||||
group_operation, not_fit_count = createGroupOperationForArrange(nodes,
|
||||
Application.getInstance().getBuildVolume(),
|
||||
fixed_nodes,
|
||||
factor = 10000,
|
||||
add_new_nodes_in_scene = True)
|
||||
found_solution_for_all = not_fit_count == 0
|
||||
if self._grid_arrange:
|
||||
arranger = GridArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes)
|
||||
else:
|
||||
arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000)
|
||||
|
||||
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True)
|
||||
|
||||
if nodes_to_add_without_arrange:
|
||||
for nested_node in nodes_to_add_without_arrange:
|
||||
|
@ -6,6 +6,7 @@ from threading import Lock # To turn an asynchronous call synchronous.
|
||||
from typing import Optional, Callable, Tuple, Dict, Any, List, TYPE_CHECKING
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from UM.Logger import Logger
|
||||
from cura.OAuth2.Models import AuthenticationResponse, ResponseData, HTTP_STATUS
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
@ -70,11 +71,13 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
|
||||
code = self._queryGet(query, "code")
|
||||
state = self._queryGet(query, "state")
|
||||
if state != self.state:
|
||||
Logger.log("w", f"The provided state was not correct. Got {state} and expected {self.state}")
|
||||
token_response = AuthenticationResponse(
|
||||
success = False,
|
||||
err_message = catalog.i18nc("@message", "The provided state is not correct.")
|
||||
)
|
||||
elif code and self.authorization_helpers is not None and self.verification_code is not None:
|
||||
Logger.log("d", "Timeout when authenticating with the account server.")
|
||||
token_response = AuthenticationResponse(
|
||||
success = False,
|
||||
err_message = catalog.i18nc("@message", "Timeout when authenticating with the account server.")
|
||||
@ -92,6 +95,7 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
elif self._queryGet(query, "error_code") == "user_denied":
|
||||
# Otherwise we show an error message (probably the user clicked "Deny" in the auth dialog).
|
||||
Logger.log("d", "User did not give the required permission when authorizing this application")
|
||||
token_response = AuthenticationResponse(
|
||||
success = False,
|
||||
err_message = catalog.i18nc("@message", "Please give the required permissions when authorizing this application.")
|
||||
@ -99,6 +103,7 @@ class AuthorizationRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
else:
|
||||
# We don't know what went wrong here, so instruct the user to check the logs.
|
||||
Logger.log("w", f"Unexpected error when logging in. Error_code: {self._queryGet(query, 'error_code')}, State: {state}")
|
||||
token_response = AuthenticationResponse(
|
||||
success = False,
|
||||
error_message = catalog.i18nc("@message", "Something unexpected happened when trying to log in, please try again.")
|
||||
|
@ -111,11 +111,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
|
||||
# Parent can be None if node is just loaded.
|
||||
if self._isSingularOneAtATimeNode():
|
||||
hull = self.getConvexHullHeadFull()
|
||||
if hull is None:
|
||||
return None
|
||||
hull = self._add2DAdhesionMargin(hull)
|
||||
return hull
|
||||
return self.getConvexHullHeadFull()
|
||||
|
||||
return self._compute2DConvexHull()
|
||||
|
||||
@ -323,6 +319,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
|
||||
def _compute2DConvexHeadFull(self) -> Optional[Polygon]:
|
||||
convex_hull = self._compute2DConvexHull()
|
||||
convex_hull = self._add2DAdhesionMargin(convex_hull)
|
||||
if convex_hull:
|
||||
return convex_hull.getMinkowskiHull(self._getHeadAndFans())
|
||||
return None
|
||||
|
@ -359,7 +359,7 @@ class CuraContainerStack(ContainerStack):
|
||||
return self.definition
|
||||
|
||||
@classmethod
|
||||
def _findInstanceContainerDefinitionId(cls, machine_definition: DefinitionContainerInterface) -> str:
|
||||
def findInstanceContainerDefinitionId(cls, machine_definition: DefinitionContainerInterface) -> str:
|
||||
"""Find the ID that should be used when searching for instance containers for a specified definition.
|
||||
|
||||
This handles the situation where the definition specifies we should use a different definition when
|
||||
@ -379,7 +379,7 @@ class CuraContainerStack(ContainerStack):
|
||||
Logger.log("w", "Unable to find parent definition {parent} for machine {machine}", parent = quality_definition, machine = machine_definition.id) #type: ignore
|
||||
return machine_definition.id #type: ignore
|
||||
|
||||
return cls._findInstanceContainerDefinitionId(definitions[0])
|
||||
return cls.findInstanceContainerDefinitionId(definitions[0])
|
||||
|
||||
def getExtruderPositionValueWithDefault(self, key):
|
||||
"""getProperty for extruder positions, with translation from -1 to default extruder number"""
|
||||
|
@ -58,9 +58,7 @@ class CuraFormulaFunctions:
|
||||
|
||||
return value
|
||||
|
||||
# Gets all extruder values as a list for the given property.
|
||||
def getValuesInAllExtruders(self, property_key: str,
|
||||
context: Optional["PropertyEvaluationContext"] = None) -> List[Any]:
|
||||
def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = None) -> List[str]:
|
||||
machine_manager = self._application.getMachineManager()
|
||||
extruder_manager = self._application.getExtruderManager()
|
||||
|
||||
@ -73,7 +71,17 @@ class CuraFormulaFunctions:
|
||||
# only include values from extruders that are "active" for the current machine instance
|
||||
if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context):
|
||||
continue
|
||||
result.append(extruder)
|
||||
|
||||
return result
|
||||
|
||||
# Gets all extruder values as a list for the given property.
|
||||
def getValuesInAllExtruders(self, property_key: str,
|
||||
context: Optional["PropertyEvaluationContext"] = None) -> List[Any]:
|
||||
global_stack = self._application.getMachineManager().activeMachine
|
||||
|
||||
result = []
|
||||
for extruder in self._getActiveExtruders(context):
|
||||
value = extruder.getRawProperty(property_key, "value", context = context)
|
||||
|
||||
if value is None:
|
||||
@ -89,6 +97,25 @@ class CuraFormulaFunctions:
|
||||
|
||||
return result
|
||||
|
||||
# Get the first extruder that adheres to a specific (boolean) property, like 'material_is_support_material'.
|
||||
def getAnyExtruderPositionWithOrDefault(self, filter_key: str,
|
||||
context: Optional["PropertyEvaluationContext"] = None) -> str:
|
||||
for extruder in self._getActiveExtruders(context):
|
||||
value = extruder.getRawProperty(filter_key, "value", context=context)
|
||||
if value is None or not value:
|
||||
continue
|
||||
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()
|
||||
|
||||
# Get the resolve value or value for a given key.
|
||||
def getResolveOrValue(self, property_key: str, context: Optional["PropertyEvaluationContext"] = None) -> Any:
|
||||
machine_manager = self._application.getMachineManager()
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Copyright (c) 2023 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.Settings.SQLQueryFactory import SQLQueryFactory
|
||||
@ -10,8 +10,8 @@ class IntentDatabaseHandler(DatabaseMetadataContainerController):
|
||||
"""The Database handler for Intent containers"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(SQLQueryFactory(table = "intent",
|
||||
fields = {
|
||||
super().__init__(SQLQueryFactory(table="intent",
|
||||
fields={
|
||||
"id": "text",
|
||||
"name": "text",
|
||||
"quality_type": "text",
|
||||
@ -20,6 +20,8 @@ class IntentDatabaseHandler(DatabaseMetadataContainerController):
|
||||
"definition": "text",
|
||||
"material": "text",
|
||||
"version": "text",
|
||||
"setting_version": "text"
|
||||
"setting_version": "text",
|
||||
"icon": "text",
|
||||
"description": "text",
|
||||
}))
|
||||
self._container_type = InstanceContainer
|
||||
|
@ -54,8 +54,12 @@ 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 `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 `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 `valueFromExtruderContainer(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.
|
||||
|
||||
CuraEngine
|
||||
----
|
||||
|
@ -30,6 +30,10 @@ def copy_metadata_files(dist_path, version):
|
||||
Copy metadata files for the metadata of the AppImage.
|
||||
"""
|
||||
copied_files = {
|
||||
os.path.join("..", "icons", "cura-icon.svg"): os.path.join("usr", "share", "icons", "hicolor", "scalable", "apps", "cura-icon.svg"),
|
||||
os.path.join("..", "icons", "cura-icon_64x64.png"): os.path.join("usr", "share", "icons", "hicolor", "64x64", "apps", "cura-icon.png"),
|
||||
os.path.join("..", "icons", "cura-icon_128x128.png"): os.path.join("usr", "share", "icons", "hicolor", "128x128", "apps", "cura-icon.png"),
|
||||
os.path.join("..", "icons", "cura-icon_256x256.png"): os.path.join("usr", "share", "icons", "hicolor", "256x256", "apps", "cura-icon.png"),
|
||||
os.path.join("..", "icons", "cura-icon_256x256.png"): "cura-icon.png",
|
||||
"cura.appdata.xml": "cura.appdata.xml",
|
||||
"AppRun": "AppRun"
|
||||
@ -37,8 +41,9 @@ def copy_metadata_files(dist_path, version):
|
||||
|
||||
packaging_dir = os.path.dirname(__file__)
|
||||
for source, dest in copied_files.items():
|
||||
print("Copying", os.path.join(packaging_dir, source), "to", os.path.join(dist_path, dest))
|
||||
shutil.copyfile(os.path.join(packaging_dir, source), os.path.join(dist_path, dest))
|
||||
dest_file_path = os.path.join(dist_path, dest)
|
||||
os.makedirs(os.path.dirname(dest_file_path), exist_ok=True)
|
||||
shutil.copyfile(os.path.join(packaging_dir, source), dest_file_path)
|
||||
|
||||
# Ensure that AppRun has the proper permissions: 755 (user reads, writes and executes, group reads and executes, world reads and executes).
|
||||
print("Changing permissions for AppRun")
|
||||
|
@ -21,6 +21,7 @@ def build_dmg(source_path: str, dist_path: str, filename: str, app_name: str) ->
|
||||
"--icon", app_name, "169", "272",
|
||||
"--eula", f"{source_path}/packaging/cura_license.txt",
|
||||
"--background", f"{source_path}/packaging/MacOs/cura_background_dmg.png",
|
||||
"--hdiutil-quiet",
|
||||
f"{dist_path}/{filename}",
|
||||
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__":
|
||||
parser = argparse.ArgumentParser(description = "Create installer for Cura.")
|
||||
parser.add_argument("source_path", type = str, help = "Path to Pyinstaller source folder")
|
||||
parser.add_argument("dist_path", type = str, help = "Path to Pyinstaller dist folder")
|
||||
parser.add_argument("cura_conan_version", 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("app_name", type = str, help = "Filename of the .app that will be contained within the dmg/pkg")
|
||||
parser.add_argument("--source_path", required = True, type = str, help = "Path to Pyinstaller source folder")
|
||||
parser.add_argument("--dist_path", required = True, type = str, help = "Path to Pyinstaller dist folder")
|
||||
parser.add_argument("--cura_conan_version", required = True, type = str, help = "The version of cura")
|
||||
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("--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()
|
||||
|
||||
cura_version = args.cura_conan_version.split("/")[-1]
|
||||
|
||||
app_name = f"{args.app_name}.app"
|
||||
|
||||
if Path(args.filename).suffix == ".pkg":
|
||||
create_pkg_installer(args.filename, args.dist_path, cura_version, app_name)
|
||||
else:
|
||||
create_dmg(args.filename, args.dist_path, args.source_path, app_name)
|
||||
if args.build_pkg:
|
||||
create_pkg_installer(f"{args.filename}.pkg", args.dist_path, cura_version, app_name)
|
||||
if args.build_dmg:
|
||||
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 |
36
packaging/icons/cura-icon.svg
Normal file
36
packaging/icons/cura-icon.svg
Normal file
@ -0,0 +1,36 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1923_105419)">
|
||||
<g filter="url(#filter0_i_1923_105419)">
|
||||
<path d="M461.002 364.531L364.531 461.002H51V147.471L147.471 51H461.002V364.531Z" fill="#196EF0"/>
|
||||
</g>
|
||||
<path d="M452 60V360.917L360.917 452H60V151.083L151.083 60H452Z" stroke="#FAFAFA" stroke-width="20"/>
|
||||
<g filter="url(#filter1_d_1923_105419)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M193.027 188.44C212.068 170.759 237.671 161 264.154 161H338V191H264.154C244.939 191 226.714 198.098 213.441 210.423C200.205 222.714 193 239.135 193 256C193 272.865 200.205 289.286 213.441 301.577C226.714 313.902 244.939 321 264.154 321H338V351H264.154C237.671 351 212.068 341.241 193.027 323.561C173.949 305.845 163 281.569 163 256C163 230.431 173.949 206.155 193.027 188.44Z" fill="#FAFAFA"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_i_1923_105419" x="51" y="51" width="410.002" height="410.002" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="50"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1923_105419"/>
|
||||
</filter>
|
||||
<filter id="filter1_d_1923_105419" x="123" y="121" width="255" height="270" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="20"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1923_105419"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1923_105419" result="shape"/>
|
||||
</filter>
|
||||
<clipPath id="clip0_1923_105419">
|
||||
<rect width="512" height="512" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
@ -56,7 +56,8 @@ class ThreeMFReader(MeshReader):
|
||||
def emptyFileHintSet(self) -> bool:
|
||||
return self._empty_project
|
||||
|
||||
def _createMatrixFromTransformationString(self, transformation: str) -> Matrix:
|
||||
@staticmethod
|
||||
def _createMatrixFromTransformationString(transformation: str) -> Matrix:
|
||||
if transformation == "":
|
||||
return Matrix()
|
||||
|
||||
@ -90,7 +91,8 @@ class ThreeMFReader(MeshReader):
|
||||
|
||||
return temp_mat
|
||||
|
||||
def _convertSavitarNodeToUMNode(self, savitar_node: Savitar.SceneNode, file_name: str = "") -> Optional[SceneNode]:
|
||||
@staticmethod
|
||||
def _convertSavitarNodeToUMNode(savitar_node: Savitar.SceneNode, file_name: str = "") -> Optional[SceneNode]:
|
||||
"""Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node.
|
||||
|
||||
:returns: Scene node.
|
||||
@ -119,7 +121,7 @@ class ThreeMFReader(MeshReader):
|
||||
pass
|
||||
um_node.setName(node_name)
|
||||
um_node.setId(node_id)
|
||||
transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation())
|
||||
transformation = ThreeMFReader._createMatrixFromTransformationString(savitar_node.getTransformation())
|
||||
um_node.setTransformation(transformation)
|
||||
mesh_builder = MeshBuilder()
|
||||
|
||||
@ -138,7 +140,7 @@ class ThreeMFReader(MeshReader):
|
||||
um_node.setMeshData(mesh_data)
|
||||
|
||||
for child in savitar_node.getChildren():
|
||||
child_node = self._convertSavitarNodeToUMNode(child)
|
||||
child_node = ThreeMFReader._convertSavitarNodeToUMNode(child)
|
||||
if child_node:
|
||||
um_node.addChild(child_node)
|
||||
|
||||
@ -214,7 +216,7 @@ class ThreeMFReader(MeshReader):
|
||||
CuraApplication.getInstance().getController().getScene().setMetaDataEntry(key, value)
|
||||
|
||||
for node in scene_3mf.getSceneNodes():
|
||||
um_node = self._convertSavitarNodeToUMNode(node, file_name)
|
||||
um_node = ThreeMFReader._convertSavitarNodeToUMNode(node, file_name)
|
||||
if um_node is None:
|
||||
continue
|
||||
|
||||
@ -300,8 +302,23 @@ class ThreeMFReader(MeshReader):
|
||||
if unit is None:
|
||||
unit = "millimeter"
|
||||
elif unit not in conversion_to_mm:
|
||||
Logger.log("w", "Unrecognised unit {unit} used. Assuming mm instead.".format(unit = unit))
|
||||
Logger.log("w", "Unrecognised unit {unit} used. Assuming mm instead.".format(unit=unit))
|
||||
unit = "millimeter"
|
||||
|
||||
scale = conversion_to_mm[unit]
|
||||
return Vector(scale, scale, scale)
|
||||
|
||||
@staticmethod
|
||||
def stringToSceneNodes(scene_string: str) -> List[SceneNode]:
|
||||
parser = Savitar.ThreeMFParser()
|
||||
scene = parser.parse(scene_string)
|
||||
|
||||
# Convert the scene to scene nodes
|
||||
nodes = []
|
||||
for savitar_node in scene.getSceneNodes():
|
||||
scene_node = ThreeMFReader._convertSavitarNodeToUMNode(savitar_node, "file_name")
|
||||
if scene_node is None:
|
||||
continue
|
||||
nodes.append(scene_node)
|
||||
|
||||
return nodes
|
||||
|
@ -40,7 +40,9 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
|
||||
|
||||
# Indicate that the 3mf mesh writer should not close the archive just yet (we still need to add stuff to it).
|
||||
mesh_writer.setStoreArchive(True)
|
||||
mesh_writer.write(stream, nodes, mode)
|
||||
if not mesh_writer.write(stream, nodes, mode):
|
||||
self.setInformation(mesh_writer.getInformation())
|
||||
return False
|
||||
|
||||
archive = mesh_writer.getArchive()
|
||||
if archive is None: # This happens if there was no mesh data to write.
|
||||
@ -98,7 +100,7 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
|
||||
Logger.error("No permission to write workspace to this stream.")
|
||||
return False
|
||||
except EnvironmentError as e:
|
||||
self.setInformation(catalog.i18nc("@error:zip", "The operating system does not allow saving a project file to this location or with this file name."))
|
||||
self.setInformation(catalog.i18nc("@error:zip", str(e)))
|
||||
Logger.error("EnvironmentError when writing workspace to this stream: {err}".format(err = str(e)))
|
||||
return False
|
||||
mesh_writer.setStoreArchive(False)
|
||||
|
@ -55,11 +55,12 @@ class ThreeMFWriter(MeshWriter):
|
||||
"cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10"
|
||||
}
|
||||
|
||||
self._unit_matrix_string = self._convertMatrixToString(Matrix())
|
||||
self._unit_matrix_string = ThreeMFWriter._convertMatrixToString(Matrix())
|
||||
self._archive: Optional[zipfile.ZipFile] = None
|
||||
self._store_archive = False
|
||||
|
||||
def _convertMatrixToString(self, matrix):
|
||||
@staticmethod
|
||||
def _convertMatrixToString(matrix):
|
||||
result = ""
|
||||
result += str(matrix._data[0, 0]) + " "
|
||||
result += str(matrix._data[1, 0]) + " "
|
||||
@ -83,7 +84,8 @@ class ThreeMFWriter(MeshWriter):
|
||||
"""
|
||||
self._store_archive = store_archive
|
||||
|
||||
def _convertUMNodeToSavitarNode(self, um_node, transformation = Matrix()):
|
||||
@staticmethod
|
||||
def _convertUMNodeToSavitarNode(um_node, transformation=Matrix()):
|
||||
"""Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
|
||||
|
||||
:returns: Uranium Scene node.
|
||||
@ -100,7 +102,7 @@ class ThreeMFWriter(MeshWriter):
|
||||
|
||||
node_matrix = um_node.getLocalTransformation()
|
||||
|
||||
matrix_string = self._convertMatrixToString(node_matrix.preMultiply(transformation))
|
||||
matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix.preMultiply(transformation))
|
||||
|
||||
savitar_node.setTransformation(matrix_string)
|
||||
mesh_data = um_node.getMeshData()
|
||||
@ -133,7 +135,7 @@ class ThreeMFWriter(MeshWriter):
|
||||
# only save the nodes on the active build plate
|
||||
if child_node.callDecoration("getBuildPlateNumber") != active_build_plate_nr:
|
||||
continue
|
||||
savitar_child_node = self._convertUMNodeToSavitarNode(child_node)
|
||||
savitar_child_node = ThreeMFWriter._convertUMNodeToSavitarNode(child_node)
|
||||
if savitar_child_node is not None:
|
||||
savitar_node.addChild(savitar_child_node)
|
||||
|
||||
@ -221,7 +223,7 @@ class ThreeMFWriter(MeshWriter):
|
||||
for node in nodes:
|
||||
if node == root_node:
|
||||
for root_child in node.getChildren():
|
||||
savitar_node = self._convertUMNodeToSavitarNode(root_child, transformation_matrix)
|
||||
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(root_child, transformation_matrix)
|
||||
if savitar_node:
|
||||
savitar_scene.addSceneNode(savitar_node)
|
||||
else:
|
||||
@ -235,9 +237,9 @@ class ThreeMFWriter(MeshWriter):
|
||||
archive.writestr(model_file, scene_string)
|
||||
archive.writestr(content_types_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(content_types))
|
||||
archive.writestr(relations_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(relations_element))
|
||||
except Exception as e:
|
||||
except Exception as error:
|
||||
Logger.logException("e", "Error writing zip file")
|
||||
self.setInformation(catalog.i18nc("@error:zip", "Error writing 3mf file."))
|
||||
self.setInformation(str(error))
|
||||
return False
|
||||
finally:
|
||||
if not self._store_archive:
|
||||
@ -303,9 +305,19 @@ class ThreeMFWriter(MeshWriter):
|
||||
Logger.log("w", "Can't create snapshot when renderer not initialized.")
|
||||
return None
|
||||
try:
|
||||
snapshot = Snapshot.snapshot(width = 300, height = 300)
|
||||
snapshot = Snapshot.snapshot(width=300, height=300)
|
||||
except:
|
||||
Logger.logException("w", "Failed to create snapshot image")
|
||||
return None
|
||||
|
||||
return snapshot
|
||||
|
||||
@staticmethod
|
||||
def sceneNodesToString(scene_nodes: [SceneNode]) -> str:
|
||||
savitar_scene = Savitar.Scene()
|
||||
for scene_node in scene_nodes:
|
||||
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(scene_node)
|
||||
savitar_scene.addSceneNode(savitar_node)
|
||||
parser = Savitar.ThreeMFParser()
|
||||
scene_string = parser.sceneToString(savitar_scene)
|
||||
return scene_string
|
||||
|
@ -21,6 +21,7 @@ catalog = i18nCatalog("cura")
|
||||
|
||||
class RemotePackageList(PackageList):
|
||||
ITEMS_PER_PAGE = 20 # Pagination of number of elements to download at once.
|
||||
SORT_TYPE = "last_updated" # Default value to send for sort_by filter.
|
||||
|
||||
def __init__(self, parent: Optional["QObject"] = None) -> None:
|
||||
super().__init__(parent)
|
||||
@ -28,6 +29,7 @@ class RemotePackageList(PackageList):
|
||||
self._package_type_filter = ""
|
||||
self._requested_search_string = ""
|
||||
self._current_search_string = ""
|
||||
self._search_sort = "sort_by"
|
||||
self._search_type = "search"
|
||||
self._request_url = self._initialRequestUrl()
|
||||
self._ongoing_requests["get_packages"] = None
|
||||
@ -102,6 +104,8 @@ class RemotePackageList(PackageList):
|
||||
request_url += f"&package_type={self._package_type_filter}"
|
||||
if self._current_search_string != "":
|
||||
request_url += f"&{self._search_type}={self._current_search_string}"
|
||||
if self.SORT_TYPE:
|
||||
request_url += f"&{self._search_sort}={self.SORT_TYPE}"
|
||||
return request_url
|
||||
|
||||
def _parseResponse(self, reply: "QNetworkReply") -> None:
|
||||
|
@ -280,7 +280,7 @@ Window
|
||||
onClicked:
|
||||
{
|
||||
marketplaceDialog.hide();
|
||||
CuraApplication.closeApplication();
|
||||
CuraApplication.checkAndExitApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,11 +167,7 @@ Item
|
||||
|
||||
onActivated:
|
||||
{
|
||||
if (index == 0){
|
||||
setMeshType(infillMeshType)
|
||||
} else {
|
||||
setMeshType(cuttingMeshType)
|
||||
}
|
||||
setMeshType(index === 0 ? infillMeshType : cuttingMeshType);
|
||||
}
|
||||
|
||||
Binding
|
||||
@ -204,21 +200,21 @@ Item
|
||||
model: UM.SettingDefinitionsModel
|
||||
{
|
||||
id: addedSettingsModel
|
||||
containerId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.definition.id: ""
|
||||
expanded: [ "*" ]
|
||||
containerId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.definition.id: ""
|
||||
expanded: ["*"]
|
||||
filter:
|
||||
{
|
||||
if (printSequencePropertyProvider.properties.value == "one_at_a_time")
|
||||
if (printSequencePropertyProvider.properties.value === "one_at_a_time")
|
||||
{
|
||||
return {"settable_per_meshgroup": true}
|
||||
return { settable_per_meshgroup: true }
|
||||
}
|
||||
return {"settable_per_mesh": true}
|
||||
return { settable_per_meshgroup: true }
|
||||
}
|
||||
exclude:
|
||||
{
|
||||
var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]
|
||||
const excluded_settings = ["support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh"]
|
||||
|
||||
if (currentMeshType == "support_mesh")
|
||||
if (currentMeshType === "support_mesh")
|
||||
{
|
||||
excluded_settings = excluded_settings.concat(base.allCategoriesExceptSupport)
|
||||
}
|
||||
@ -246,7 +242,6 @@ Item
|
||||
{
|
||||
id: settingLoader
|
||||
width: UM.Theme.getSize("setting").width - removeButton.width - scrollBar.width
|
||||
height: UM.Theme.getSize("section").height + UM.Theme.getSize("narrow_margin").height
|
||||
enabled: provider.properties.enabled === "True"
|
||||
property var definition: model
|
||||
property var settingDefinitionsModel: addedSettingsModel
|
||||
@ -257,7 +252,7 @@ Item
|
||||
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
|
||||
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
|
||||
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
|
||||
asynchronous: model.type != "enum" && model.type != "extruder"
|
||||
asynchronous: model.type !== "enum" && model.type !== "extruder"
|
||||
|
||||
onLoaded:
|
||||
{
|
||||
@ -266,6 +261,7 @@ Item
|
||||
settingLoader.item.showLinkedSettingIcon = false
|
||||
settingLoader.item.doDepthIndentation = false
|
||||
settingLoader.item.doQualityUserSettingEmphasis = false
|
||||
settingLoader.item.height = UM.Theme.getSize("setting").height + UM.Theme.getSize("narrow_margin").height
|
||||
}
|
||||
|
||||
sourceComponent:
|
||||
@ -362,11 +358,11 @@ Item
|
||||
if (typeof UM.ActiveTool.properties.getValue("ContainerID") !== "undefined")
|
||||
{
|
||||
const containerId = UM.ActiveTool.properties.getValue("ContainerID")
|
||||
if (provider.containerStackId != containerId)
|
||||
if (provider.containerStackId !== containerId)
|
||||
{
|
||||
provider.containerStackId = containerId
|
||||
}
|
||||
if (inheritStackProvider.containerStackId != containerId)
|
||||
if (inheritStackProvider.containerStackId !== containerId)
|
||||
{
|
||||
inheritStackProvider.containerStackId = containerId
|
||||
}
|
||||
@ -388,13 +384,13 @@ Item
|
||||
onClicked:
|
||||
{
|
||||
settingPickDialog.visible = true;
|
||||
if (currentMeshType == "support_mesh")
|
||||
if (currentMeshType === "support_mesh")
|
||||
{
|
||||
settingPickDialog.additional_excluded_settings = base.allCategoriesExceptSupport;
|
||||
}
|
||||
else
|
||||
{
|
||||
settingPickDialog.additional_excluded_settings = []
|
||||
settingPickDialog.additional_excluded_settings = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,7 +408,7 @@ Item
|
||||
|
||||
containerStack: Cura.MachineManager.activeMachine
|
||||
key: "machine_extruder_count"
|
||||
watchedProperties: [ "value" ]
|
||||
watchedProperties: ["value"]
|
||||
storeIndex: 0
|
||||
}
|
||||
|
||||
@ -422,56 +418,15 @@ Item
|
||||
|
||||
containerStack: Cura.MachineManager.activeMachine
|
||||
key: "print_sequence"
|
||||
watchedProperties: [ "value" ]
|
||||
watchedProperties: ["value"]
|
||||
storeIndex: 0
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingTextField
|
||||
|
||||
Cura.SettingTextField { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingComboBox
|
||||
|
||||
Cura.SettingComboBox { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingExtruder
|
||||
|
||||
Cura.SettingExtruder { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingOptionalExtruder
|
||||
|
||||
Cura.SettingOptionalExtruder { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingCheckBox
|
||||
|
||||
Cura.SettingCheckBox { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingCategory
|
||||
|
||||
Cura.SettingCategory { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingUnknown
|
||||
|
||||
Cura.SettingUnknown { }
|
||||
}
|
||||
Component { id: settingTextField; Cura.SettingTextField { } }
|
||||
Component { id: settingComboBox; Cura.SettingComboBox { } }
|
||||
Component { id: settingExtruder; Cura.SettingExtruder { } }
|
||||
Component { id: settingOptionalExtruder; Cura.SettingOptionalExtruder { } }
|
||||
Component { id: settingCheckBox; Cura.SettingCheckBox { } }
|
||||
Component { id: settingCategory; Cura.SettingCategory { } }
|
||||
Component { id: settingUnknown; Cura.SettingUnknown { } }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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 importlib.util
|
||||
@ -139,22 +139,28 @@ class PostProcessingPlugin(QObject, Extension):
|
||||
if self._loaded_scripts: # Already loaded.
|
||||
return
|
||||
|
||||
# The PostProcessingPlugin path is for built-in scripts.
|
||||
# The Resources path is where the user should store custom scripts.
|
||||
# The Preferences path is legacy, where the user may previously have stored scripts.
|
||||
resource_folders = [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]
|
||||
resource_folders.extend(Resources.getAllPathsForType(Resources.Resources))
|
||||
for root in resource_folders:
|
||||
if root is None:
|
||||
continue
|
||||
path = os.path.join(root, "scripts")
|
||||
# Make sure a "scripts" folder exists in the main configuration folder and the preferences folder.
|
||||
# On some platforms the resources and preferences folders resolve to the same folder,
|
||||
# but on Linux they can be different.
|
||||
for path in set([os.path.join(Resources.getStoragePath(r), "scripts") for r in [Resources.Resources, Resources.Preferences]]):
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
Logger.log("w", "Unable to create a folder for scripts: " + path)
|
||||
continue
|
||||
|
||||
# The PostProcessingPlugin path is for built-in scripts.
|
||||
# The Resources path is where the user should store custom scripts.
|
||||
# The Preferences path is legacy, where the user may previously have stored scripts.
|
||||
resource_folders = [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]
|
||||
resource_folders.extend(Resources.getAllPathsForType(Resources.Resources))
|
||||
|
||||
for root in resource_folders:
|
||||
if root is None:
|
||||
continue
|
||||
path = os.path.join(root, "scripts")
|
||||
if not os.path.isdir(path):
|
||||
continue
|
||||
self.loadScripts(path)
|
||||
|
||||
def loadScripts(self, path: str) -> None:
|
||||
|
@ -1,5 +1,5 @@
|
||||
// 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.Controls 2.15
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Copyright (c) 2015 Jaime van Kessel
|
||||
# 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 UM.Signal import Signal, signalemitter
|
||||
|
@ -1,7 +1,7 @@
|
||||
# ChangeAtZ script - Change printing parameters at a given height
|
||||
# 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 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
|
||||
|
||||
# Authors of the ChangeAtZ plugin / script:
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
# 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
|
||||
|
||||
#Authors of the 2-1 ColorMix plug-in / script:
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
||||
# Copyright (c) 2023 Ultimaker B.V.
|
||||
# The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
# Modification 06.09.2020
|
||||
# add checkbox, now you can choose and use configuration from the firmware itself.
|
||||
@ -199,7 +199,7 @@ class FilamentChange(Script):
|
||||
if enable_before_macro:
|
||||
color_change = color_change + before_macro + "\n"
|
||||
|
||||
color_change = color_change + "M600\n"
|
||||
color_change = color_change + "M600"
|
||||
|
||||
if not firmware_config:
|
||||
if initial_retract is not None and initial_retract > 0.:
|
||||
@ -213,13 +213,15 @@ class FilamentChange(Script):
|
||||
|
||||
if x_pos is not None:
|
||||
color_change = color_change + (" X%.2f" % x_pos)
|
||||
|
||||
|
||||
if y_pos is not None:
|
||||
color_change = color_change + (" Y%.2f" % y_pos)
|
||||
|
||||
|
||||
if z_pos is not None and z_pos > 0.:
|
||||
color_change = color_change + (" Z%.2f" % z_pos)
|
||||
|
||||
color_change = color_change + "\n"
|
||||
|
||||
if enable_after_macro:
|
||||
color_change = color_change + after_macro + "\n"
|
||||
|
||||
|
@ -67,7 +67,7 @@ class PauseAtHeight(Script):
|
||||
"label": "Keep motors engaged",
|
||||
"description": "Keep the steppers engaged to allow change of filament without moving the head. Applying too much force will move the head/bed anyway",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"default_value": false,
|
||||
"enabled": "pause_method != \\\"griffin\\\""
|
||||
},
|
||||
"disarm_timeout":
|
||||
@ -218,7 +218,7 @@ class PauseAtHeight(Script):
|
||||
"label": "Beep at pause",
|
||||
"description": "Make a beep when pausing",
|
||||
"type": "bool",
|
||||
"default_value": true
|
||||
"default_value": false
|
||||
},
|
||||
"beep_length":
|
||||
{
|
||||
@ -338,7 +338,7 @@ class PauseAtHeight(Script):
|
||||
nbr_negative_layers += 1
|
||||
|
||||
#Track the latest printing temperature in order to resume at the correct temperature.
|
||||
if line.startswith("T"):
|
||||
if re.match("T(\d*)", line):
|
||||
current_t = self.getValue(line, "T")
|
||||
m = self.getValue(line, "M")
|
||||
if m is not None and (m == 104 or m == 109) and self.getValue(line, "S") is not None:
|
||||
@ -478,10 +478,11 @@ class PauseAtHeight(Script):
|
||||
prepend_gcode += "M117 " + display_text + "\n"
|
||||
|
||||
# Set the disarm timeout
|
||||
if hold_steppers_on:
|
||||
prepend_gcode += self.putValue(M = 84, S = 3600) + " ; Keep steppers engaged for 1h\n"
|
||||
elif disarm_timeout > 0:
|
||||
prepend_gcode += self.putValue(M = 84, S = disarm_timeout) + " ; Set the disarm timeout\n"
|
||||
if pause_method != "griffin":
|
||||
if hold_steppers_on:
|
||||
prepend_gcode += self.putValue(M = 84, S = 3600) + " ; Keep steppers engaged for 1h\n"
|
||||
elif disarm_timeout > 0:
|
||||
prepend_gcode += self.putValue(M = 84, S = disarm_timeout) + " ; Set the disarm timeout\n"
|
||||
|
||||
# Beep at pause
|
||||
if beep_at_pause:
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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.
|
||||
|
||||
|
@ -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
|
||||
Python implementation of https://github.com/electrocbd/post_stretch
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from UM.Application import Application
|
||||
@ -143,38 +144,44 @@ class RemovableDriveOutputDevice(OutputDevice):
|
||||
|
||||
def _onFinished(self, job):
|
||||
if self._stream:
|
||||
# Explicitly closing the stream flushes the write-buffer
|
||||
error = job.getError()
|
||||
try:
|
||||
# Explicitly closing the stream flushes the write-buffer
|
||||
self._stream.close()
|
||||
self._stream = None
|
||||
except:
|
||||
Logger.logException("w", "An exception occurred while trying to write to removable drive.")
|
||||
message = Message(catalog.i18nc("@info:status", "Could not save to removable drive {0}: {1}").format(self.getName(),str(job.getError())),
|
||||
title = catalog.i18nc("@info:title", "Error"),
|
||||
message_type = Message.MessageType.ERROR)
|
||||
except Exception as e:
|
||||
if not error:
|
||||
# Only log new error if there was no previous one
|
||||
error = e
|
||||
|
||||
self._stream = None
|
||||
self._writing = False
|
||||
self.writeFinished.emit(self)
|
||||
|
||||
if not error:
|
||||
message = Message(
|
||||
catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").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.show()
|
||||
self.writeSuccess.emit(self)
|
||||
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",
|
||||
"Could not save to removable drive {0}: {1}").format(self.getName(),
|
||||
str(job.getError())),
|
||||
title=catalog.i18nc("@info:title", "Error"),
|
||||
message_type=Message.MessageType.ERROR)
|
||||
message.show()
|
||||
self.writeError.emit(self)
|
||||
return
|
||||
|
||||
self._writing = False
|
||||
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())),
|
||||
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.show()
|
||||
self.writeSuccess.emit(self)
|
||||
else:
|
||||
message = Message(catalog.i18nc("@info:status",
|
||||
"Could not save to removable drive {0}: {1}").format(self.getName(),
|
||||
str(job.getError())),
|
||||
title = catalog.i18nc("@info:title", "Error"),
|
||||
message_type = Message.MessageType.ERROR)
|
||||
message.show()
|
||||
self.writeError.emit(self)
|
||||
job.getStream().close()
|
||||
|
||||
def _onActionTriggered(self, message, action):
|
||||
if action == "eject":
|
||||
|
@ -96,6 +96,9 @@ class AbstractCloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||
|
||||
@pyqtSlot(str)
|
||||
def printerSelected(self, unique_id: str):
|
||||
# The device that it defers the actual write to isn't hooked up correctly. So we should emit the write signal
|
||||
# here.
|
||||
self.writeStarted.emit(self)
|
||||
self._request_write_callback(unique_id, self._nodes)
|
||||
if self._on_print_dialog:
|
||||
self._on_print_dialog.close()
|
||||
|
@ -37,24 +37,13 @@ class NewPrinterDetectedMessage(Message):
|
||||
|
||||
def finalize(self, new_devices_added, new_output_devices):
|
||||
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:
|
||||
message_text = self.i18n_catalog.i18nc("info:status",
|
||||
"Printers added from Digital Factory:") + f"<ul>{device_names}</ul>"
|
||||
device_names = ""
|
||||
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)
|
||||
else:
|
||||
self.hide()
|
||||
|
@ -10,6 +10,7 @@ from PyQt6.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject
|
||||
from PyQt6.QtNetwork import QNetworkReply
|
||||
|
||||
from UM.FileHandler.FileHandler import FileHandler
|
||||
from UM.Version import Version
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Logger import Logger
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
@ -86,7 +87,10 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
|
||||
|
||||
@pyqtSlot(name="openPrinterControlPanel")
|
||||
def openPrinterControlPanel(self) -> None:
|
||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
||||
if Version(self.firmwareVersion) >= Version("7.0.2"):
|
||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
||||
else:
|
||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
||||
|
||||
@pyqtSlot(str, name="sendJobToTop")
|
||||
def sendJobToTop(self, print_job_uuid: str) -> None:
|
||||
|
@ -21,7 +21,7 @@ class AutoDetectBaudJob(Job):
|
||||
self._all_baud_rates = [115200, 250000, 500000, 230400, 76800, 57600, 38400, 19200, 9600]
|
||||
|
||||
def run(self) -> None:
|
||||
Logger.log("d", "Auto detect baud rate started.")
|
||||
Logger.debug(f"Auto detect baud rate started for {self._serial_port}")
|
||||
wait_response_timeouts = [3, 15, 30]
|
||||
wait_bootloader_times = [1.5, 5, 15]
|
||||
write_timeout = 3
|
||||
@ -46,8 +46,7 @@ class AutoDetectBaudJob(Job):
|
||||
wait_bootloader = wait_bootloader_times[retry]
|
||||
else:
|
||||
wait_bootloader = wait_bootloader_times[-1]
|
||||
Logger.log("d", "Checking {serial} if baud rate {baud_rate} works. Retry nr: {retry}. Wait timeout: {timeout}".format(
|
||||
serial = self._serial_port, baud_rate = baud_rate, retry = retry, timeout = wait_response_timeout))
|
||||
Logger.debug(f"Checking {self._serial_port} if baud rate {baud_rate} works. Retry nr: {retry}. Wait timeout: {wait_response_timeout}")
|
||||
|
||||
if serial is None:
|
||||
try:
|
||||
@ -61,7 +60,9 @@ class AutoDetectBaudJob(Job):
|
||||
serial.baudrate = baud_rate
|
||||
except ValueError:
|
||||
continue
|
||||
sleep(wait_bootloader) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
|
||||
|
||||
# Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
|
||||
sleep(wait_bootloader)
|
||||
|
||||
serial.write(b"\n") # Ensure we clear out previous responses
|
||||
serial.write(b"M105\n")
|
||||
@ -83,4 +84,5 @@ class AutoDetectBaudJob(Job):
|
||||
|
||||
serial.write(b"M105\n")
|
||||
sleep(15) # Give the printer some time to init and try again.
|
||||
Logger.debug(f"Unable to find a working baudrate for {serial}")
|
||||
self.setResult(None) # Unable to detect the correct baudrate.
|
||||
|
@ -31,6 +31,46 @@ _REMOVED_SETTINGS = {
|
||||
"wireframe_roof_drag_along",
|
||||
"wireframe_roof_outer_delay",
|
||||
"wireframe_nozzle_clearance",
|
||||
"support_tree_branch_distance",
|
||||
"support_tree_collision_resolution",
|
||||
}
|
||||
|
||||
_RENAMED_PROFILES = {
|
||||
"abs_040012": "elegoo_abs_nozzle_0.40_layer_0.10",
|
||||
"abs_040016": "elegoo_abs_nozzle_0.40_layer_0.15",
|
||||
"abs_040020": "elegoo_abs_nozzle_0.40_layer_0.20",
|
||||
"abs_040024": "elegoo_abs_nozzle_0.40_layer_0.20",
|
||||
"abs_040028": "elegoo_abs_nozzle_0.40_layer_0.30",
|
||||
|
||||
"asa_040012": "elegoo_asa_nozzle_0.40_layer_0.10",
|
||||
"asa_040016": "elegoo_asa_nozzle_0.40_layer_0.15",
|
||||
"asa_040020": "elegoo_asa_nozzle_0.40_layer_0.20",
|
||||
"asa_040024": "elegoo_asa_nozzle_0.40_layer_0.20",
|
||||
"asa_040028": "elegoo_asa_nozzle_0.40_layer_0.30",
|
||||
|
||||
"petg_040012": "elegoo_petg_nozzle_0.40_layer_0.10",
|
||||
"petg_040016": "elegoo_petg_nozzle_0.40_layer_0.15",
|
||||
"petg_040020": "elegoo_petg_nozzle_0.40_layer_0.20",
|
||||
"petg_040024": "elegoo_petg_nozzle_0.40_layer_0.20",
|
||||
"petg_040028": "elegoo_petg_nozzle_0.40_layer_0.30",
|
||||
|
||||
"pla_040012": "elegoo_pla_nozzle_0.40_layer_0.10",
|
||||
"pla_040016": "elegoo_pla_nozzle_0.40_layer_0.15",
|
||||
"pla_040020": "elegoo_pla_nozzle_0.40_layer_0.20",
|
||||
"pla_040024": "elegoo_pla_nozzle_0.40_layer_0.20",
|
||||
"pla_040028": "elegoo_pla_nozzle_0.40_layer_0.30",
|
||||
|
||||
"tpu_040012": "elegoo_tpu_nozzle_0.40_layer_0.10",
|
||||
"tpu_040016": "elegoo_tpu_nozzle_0.40_layer_0.15",
|
||||
"tpu_040020": "elegoo_tpu_nozzle_0.40_layer_0.20",
|
||||
"tpu_040024": "elegoo_tpu_nozzle_0.40_layer_0.20",
|
||||
"tpu_040028": "elegoo_tpu_nozzle_0.40_layer_0.30",
|
||||
|
||||
"elegoo_global_012_high": "elegoo_layer_0.10",
|
||||
"elegoo_global_016_normal": "elegoo_layer_0.15",
|
||||
"elegoo_global_020_fine": "elegoo_layer_0.20",
|
||||
"elegoo_global_024_medium": "elegoo_layer_0.20",
|
||||
"elegoo_global_028_draft": "elegoo_layer_0.30",
|
||||
}
|
||||
|
||||
|
||||
@ -112,6 +152,9 @@ class VersionUpgrade53to54(VersionUpgrade):
|
||||
|
||||
parser["metadata"]["setting_version"] = "22"
|
||||
|
||||
for container in parser['containers']:
|
||||
parser['containers'][container] = _RENAMED_PROFILES.get(parser['containers'][container], parser['containers'][container])
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
|
103
requirements.txt
103
requirements.txt
@ -36,29 +36,28 @@ PyQt6-NetworkAuth-Qt6==6.4.2 \
|
||||
--hash=sha256:1de6abbb5fa6585b97ae49d3f64b0dfad40bd56b1a31744d9775ff26247241c8 \
|
||||
--hash=sha256:79ec4b0fc9450bbedbff03541b93b10d1c7e761cd2cc16ce70d2b09dcdf8c720 \
|
||||
--hash=sha256:d96d557fe61edb9b68d189f270f0393d6579c8d308e6b0d41bc0699371d7cb4e
|
||||
certifi==2021.10.8 \
|
||||
--hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872 \
|
||||
--hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
|
||||
cryptography==3.4.8; \
|
||||
--hash=sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e \
|
||||
--hash=sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b \
|
||||
--hash=sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7 \
|
||||
--hash=sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085 \
|
||||
--hash=sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc \
|
||||
--hash=sha256:3c4129fc3fdc0fa8e40861b5ac0c673315b3c902bbdc05fc176764815b43dd1d \
|
||||
--hash=sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a \
|
||||
--hash=sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498 \
|
||||
--hash=sha256:695104a9223a7239d155d7627ad912953b540929ef97ae0c34c7b8bf30857e89 \
|
||||
--hash=sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9 \
|
||||
--hash=sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c \
|
||||
--hash=sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7 \
|
||||
--hash=sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb \
|
||||
--hash=sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14 \
|
||||
--hash=sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af \
|
||||
--hash=sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e \
|
||||
--hash=sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5 \
|
||||
--hash=sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06 \
|
||||
--hash=sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7
|
||||
certifi==2023.5.7; \
|
||||
--hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
|
||||
cryptography==41.0.1 \
|
||||
--hash=sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db \
|
||||
--hash=sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a \
|
||||
--hash=sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039 \
|
||||
--hash=sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c \
|
||||
--hash=sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3 \
|
||||
--hash=sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485 \
|
||||
--hash=sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c \
|
||||
--hash=sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca \
|
||||
--hash=sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5 \
|
||||
--hash=sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5 \
|
||||
--hash=sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3 \
|
||||
--hash=sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb \
|
||||
--hash=sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43 \
|
||||
--hash=sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31 \
|
||||
--hash=sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc \
|
||||
--hash=sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b \
|
||||
--hash=sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006 \
|
||||
--hash=sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a \
|
||||
--hash=sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699
|
||||
zeroconf==0.31.0 \
|
||||
--hash=sha256:53a180248471c6f81bd1fffcbce03ed93d7d8eaf10905c9121ac1ea996d19844 \
|
||||
--hash=sha256:5a468da018bc3f04bbce77ae247924d802df7aeb4c291bbbb5a9616d128800b0
|
||||
@ -252,19 +251,45 @@ python-utils==2.3.0 \
|
||||
six==1.12.0 \
|
||||
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
|
||||
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
|
||||
shapely==1.8.2 \
|
||||
--hash=sha256:572af9d5006fd5e3213e37ee548912b0341fb26724d6dc8a4e3950c10197ebb6 \
|
||||
--hash=sha256:c60f3758212ec480675b820b13035dda8af8f7cc560d2cc67999b2717fb8faef \
|
||||
--hash=sha256:6bdc7728f1e5df430d8c588661f79f1eed4a2728c8b689e12707cfec217f68f8 \
|
||||
--hash=sha256:ce0b5c5f7acbccf98b3460eecaa40e9b18272b2a734f74fcddf1d7696e047e95 \
|
||||
--hash=sha256:7c9e3400b716c51ba43eea1678c28272580114e009b6c78cdd00c44df3e325fa \
|
||||
--hash=sha256:3423299254deec075e79fb7dc7909d702104e4167149de7f45510c3a6342eeea \
|
||||
--hash=sha256:3423299254deec075e79fb7dc7909d702104e4167149de7f45510c3a6342eeea \
|
||||
--hash=sha256:44d2832c1b706bf43101fda92831a083467cc4b4923a7ed17319ab599c1025d8 \
|
||||
--hash=sha256:44d2832c1b706bf43101fda92831a083467cc4b4923a7ed17319ab599c1025d8 \
|
||||
--hash=sha256:75042e8039c79dd01f102bb288beace9dc2f49fc44a2dea875f9b697aa8cd30d \
|
||||
--hash=sha256:75042e8039c79dd01f102bb288beace9dc2f49fc44a2dea875f9b697aa8cd30d \
|
||||
--hash=sha256:5254240eefc44139ab0d128faf671635d8bdd9c23955ee063d4d6b8f20073ae0
|
||||
shapely==2.0.1 \
|
||||
--hash=sha256:01224899ff692a62929ef1a3f5fe389043e262698a708ab7569f43a99a48ae82 \
|
||||
--hash=sha256:05c51a29336e604c084fb43ae5dbbfa2c0ef9bd6fedeae0a0d02c7b57a56ba46 \
|
||||
--hash=sha256:09d6c7763b1bee0d0a2b84bb32a4c25c6359ad1ac582a62d8b211e89de986154 \
|
||||
--hash=sha256:193a398d81c97a62fc3634a1a33798a58fd1dcf4aead254d080b273efbb7e3ff \
|
||||
--hash=sha256:1a34a23d6266ca162499e4a22b79159dc0052f4973d16f16f990baa4d29e58b6 \
|
||||
--hash=sha256:2569a4b91caeef54dd5ae9091ae6f63526d8ca0b376b5bb9fd1a3195d047d7d4 \
|
||||
--hash=sha256:33403b8896e1d98aaa3a52110d828b18985d740cc9f34f198922018b1e0f8afe \
|
||||
--hash=sha256:3ad81f292fffbd568ae71828e6c387da7eb5384a79db9b4fde14dd9fdeffca9a \
|
||||
--hash=sha256:3cb256ae0c01b17f7bc68ee2ffdd45aebf42af8992484ea55c29a6151abe4386 \
|
||||
--hash=sha256:45b4833235b90bc87ee26c6537438fa77559d994d2d3be5190dd2e54d31b2820 \
|
||||
--hash=sha256:4641325e065fd3e07d55677849c9ddfd0cf3ee98f96475126942e746d55b17c8 \
|
||||
--hash=sha256:502e0a607f1dcc6dee0125aeee886379be5242c854500ea5fd2e7ac076b9ce6d \
|
||||
--hash=sha256:66a6b1a3e72ece97fc85536a281476f9b7794de2e646ca8a4517e2e3c1446893 \
|
||||
--hash=sha256:70a18fc7d6418e5aea76ac55dce33f98e75bd413c6eb39cfed6a1ba36469d7d4 \
|
||||
--hash=sha256:7d3bbeefd8a6a1a1017265d2d36f8ff2d79d0162d8c141aa0d37a87063525656 \
|
||||
--hash=sha256:83a8ec0ee0192b6e3feee9f6a499d1377e9c295af74d7f81ecba5a42a6b195b7 \
|
||||
--hash=sha256:865bc3d7cc0ea63189d11a0b1120d1307ed7a64720a8bfa5be2fde5fc6d0d33f \
|
||||
--hash=sha256:90cfa4144ff189a3c3de62e2f3669283c98fb760cfa2e82ff70df40f11cadb39 \
|
||||
--hash=sha256:91575d97fd67391b85686573d758896ed2fc7476321c9d2e2b0c398b628b961c \
|
||||
--hash=sha256:9a6ac34c16f4d5d3c174c76c9d7614ec8fe735f8f82b6cc97a46b54f386a86bf \
|
||||
--hash=sha256:a529218e72a3dbdc83676198e610485fdfa31178f4be5b519a8ae12ea688db14 \
|
||||
--hash=sha256:a70a614791ff65f5e283feed747e1cc3d9e6c6ba91556e640636bbb0a1e32a71 \
|
||||
--hash=sha256:ac1dfc397475d1de485e76de0c3c91cc9d79bd39012a84bb0f5e8a199fc17bef \
|
||||
--hash=sha256:b06d031bc64149e340448fea25eee01360a58936c89985cf584134171e05863f \
|
||||
--hash=sha256:b4f0711cc83734c6fad94fc8d4ec30f3d52c1787b17d9dca261dc841d4731c64 \
|
||||
--hash=sha256:b50c401b64883e61556a90b89948297f1714dbac29243d17ed9284a47e6dd731 \
|
||||
--hash=sha256:b519cf3726ddb6c67f6a951d1bb1d29691111eaa67ea19ddca4d454fbe35949c \
|
||||
--hash=sha256:bca57b683e3d94d0919e2f31e4d70fdfbb7059650ef1b431d9f4e045690edcd5 \
|
||||
--hash=sha256:c43755d2c46b75a7b74ac6226d2cc9fa2a76c3263c5ae70c195c6fb4e7b08e79 \
|
||||
--hash=sha256:c7eed1fb3008a8a4a56425334b7eb82651a51f9e9a9c2f72844a2fb394f38a6c \
|
||||
--hash=sha256:c8b0d834b11be97d5ab2b4dceada20ae8e07bcccbc0f55d71df6729965f406ad \
|
||||
--hash=sha256:ce88ec79df55430e37178a191ad8df45cae90b0f6972d46d867bf6ebbb58cc4d \
|
||||
--hash=sha256:d173d24e85e51510e658fb108513d5bc11e3fd2820db6b1bd0522266ddd11f51 \
|
||||
--hash=sha256:d8f55f355be7821dade839df785a49dc9f16d1af363134d07eb11e9207e0b189 \
|
||||
--hash=sha256:da71de5bf552d83dcc21b78cc0020e86f8d0feea43e202110973987ffa781c21 \
|
||||
--hash=sha256:e55698e0ed95a70fe9ff9a23c763acfe0bf335b02df12142f74e4543095e9a9b \
|
||||
--hash=sha256:f32a748703e7bf6e92dfa3d2936b2fbfe76f8ce5f756e24f49ef72d17d26ad02 \
|
||||
--hash=sha256:f470a130d6ddb05b810fc1776d918659407f8d025b7f56d2742a596b6dffa6c7
|
||||
cython==0.29.26 \
|
||||
--hash=sha256:af377d543a762867da11fcf6e558f7a4a535ff8693f30cce123fab10c00fa312 \
|
||||
--hash=sha256:f5e15ff892c8afad64931ee3dd723c4755c2c516606f9aae7613bebfac62b0f6 \
|
||||
@ -356,9 +381,9 @@ typing-extensions==3.10.0.2 \
|
||||
jeepney==0.7.1; \
|
||||
--hash=sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac \
|
||||
--hash=sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f
|
||||
SecretStorage==3.3.1 \
|
||||
--hash=sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f \
|
||||
--hash=sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195
|
||||
SecretStorage==3.3.3 \
|
||||
--hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \
|
||||
--hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99
|
||||
keyring==23.0.1 \
|
||||
--hash=sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8 \
|
||||
--hash=sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48
|
||||
|
@ -6,7 +6,7 @@
|
||||
"display_name": "3MF Reader",
|
||||
"description": "Provides support for reading 3MF files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -23,7 +23,7 @@
|
||||
"display_name": "3MF Writer",
|
||||
"description": "Provides support for writing 3MF files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -40,7 +40,7 @@
|
||||
"display_name": "AMF Reader",
|
||||
"description": "Provides support for reading AMF files.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "fieldOfView",
|
||||
@ -57,7 +57,7 @@
|
||||
"display_name": "Cura Backups",
|
||||
"description": "Backup and restore your configuration.",
|
||||
"package_version": "1.2.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -74,7 +74,7 @@
|
||||
"display_name": "CuraEngine Backend",
|
||||
"description": "Provides the link to the CuraEngine slicing backend.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -91,7 +91,7 @@
|
||||
"display_name": "Cura Profile Reader",
|
||||
"description": "Provides support for importing Cura profiles.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -108,7 +108,7 @@
|
||||
"display_name": "Cura Profile Writer",
|
||||
"description": "Provides support for exporting Cura profiles.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -125,7 +125,7 @@
|
||||
"display_name": "Ultimaker Digital Library",
|
||||
"description": "Connects to the Digital Library, allowing Cura to open files from and save files to the Digital Library.",
|
||||
"package_version": "1.1.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -142,7 +142,7 @@
|
||||
"display_name": "Firmware Update Checker",
|
||||
"description": "Checks for firmware updates.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -159,7 +159,7 @@
|
||||
"display_name": "Firmware Updater",
|
||||
"description": "Provides a machine actions for updating firmware.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -176,7 +176,7 @@
|
||||
"display_name": "Compressed G-code Reader",
|
||||
"description": "Reads g-code from a compressed archive.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -193,7 +193,7 @@
|
||||
"display_name": "Compressed G-code Writer",
|
||||
"description": "Writes g-code to a compressed archive.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -210,7 +210,7 @@
|
||||
"display_name": "G-Code Profile Reader",
|
||||
"description": "Provides support for importing profiles from g-code files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -227,7 +227,7 @@
|
||||
"display_name": "G-Code Reader",
|
||||
"description": "Allows loading and displaying G-code files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "VictorLarchenko",
|
||||
@ -244,7 +244,7 @@
|
||||
"display_name": "G-Code Writer",
|
||||
"description": "Writes g-code to a file.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -261,7 +261,7 @@
|
||||
"display_name": "Image Reader",
|
||||
"description": "Enables ability to generate printable geometry from 2D image files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -278,7 +278,7 @@
|
||||
"display_name": "Legacy Cura Profile Reader",
|
||||
"description": "Provides support for importing profiles from legacy Cura versions.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -295,7 +295,7 @@
|
||||
"display_name": "Machine Settings Action",
|
||||
"description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "fieldOfView",
|
||||
@ -312,7 +312,7 @@
|
||||
"display_name": "Model Checker",
|
||||
"description": "Checks models and print configuration for possible printing issues and give suggestions.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -329,7 +329,7 @@
|
||||
"display_name": "Monitor Stage",
|
||||
"description": "Provides a monitor stage in Cura.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -346,7 +346,7 @@
|
||||
"display_name": "Per-Object Settings Tool",
|
||||
"description": "Provides the per-model settings.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -363,7 +363,7 @@
|
||||
"display_name": "Post Processing",
|
||||
"description": "Extension that allows for user created scripts for post processing.",
|
||||
"package_version": "2.2.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -380,7 +380,7 @@
|
||||
"display_name": "Prepare Stage",
|
||||
"description": "Provides a prepare stage in Cura.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -397,7 +397,7 @@
|
||||
"display_name": "Preview Stage",
|
||||
"description": "Provides a preview stage in Cura.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -414,7 +414,7 @@
|
||||
"display_name": "Removable Drive Output Device",
|
||||
"description": "Provides removable drive hotplugging and writing support.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -431,7 +431,7 @@
|
||||
"display_name": "Sentry Logger",
|
||||
"description": "Logs certain events so that they can be used by the crash reporter",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -448,7 +448,7 @@
|
||||
"display_name": "Simulation View",
|
||||
"description": "Provides the Simulation view.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -465,7 +465,7 @@
|
||||
"display_name": "Slice Info",
|
||||
"description": "Submits anonymous slice info. Can be disabled through preferences.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -482,7 +482,7 @@
|
||||
"display_name": "Solid View",
|
||||
"description": "Provides a normal solid mesh view.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -499,7 +499,7 @@
|
||||
"display_name": "Support Eraser Tool",
|
||||
"description": "Creates an eraser mesh to block the printing of support in certain places.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -516,7 +516,7 @@
|
||||
"display_name": "Trimesh Reader",
|
||||
"description": "Provides support for reading model files.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -533,7 +533,7 @@
|
||||
"display_name": "Marketplace",
|
||||
"description": "Find, manage and install new Cura packages.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -550,7 +550,7 @@
|
||||
"display_name": "UFP Reader",
|
||||
"description": "Provides support for reading Ultimaker Format Packages.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -567,7 +567,7 @@
|
||||
"display_name": "UFP Writer",
|
||||
"description": "Provides support for writing Ultimaker Format Packages.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -584,7 +584,7 @@
|
||||
"display_name": "Ultimaker Machine Actions",
|
||||
"description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -601,7 +601,7 @@
|
||||
"display_name": "UM3 Network Printing",
|
||||
"description": "Manages network connections to Ultimaker 3 printers.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -618,7 +618,7 @@
|
||||
"display_name": "USB Printing",
|
||||
"description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.",
|
||||
"package_version": "1.0.2",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -635,7 +635,7 @@
|
||||
"display_name": "Version Upgrade 2.1 to 2.2",
|
||||
"description": "Upgrades configurations from Cura 2.1 to Cura 2.2.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -652,7 +652,7 @@
|
||||
"display_name": "Version Upgrade 2.2 to 2.4",
|
||||
"description": "Upgrades configurations from Cura 2.2 to Cura 2.4.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -669,7 +669,7 @@
|
||||
"display_name": "Version Upgrade 2.5 to 2.6",
|
||||
"description": "Upgrades configurations from Cura 2.5 to Cura 2.6.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -686,7 +686,7 @@
|
||||
"display_name": "Version Upgrade 2.6 to 2.7",
|
||||
"description": "Upgrades configurations from Cura 2.6 to Cura 2.7.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -703,7 +703,7 @@
|
||||
"display_name": "Version Upgrade 2.7 to 3.0",
|
||||
"description": "Upgrades configurations from Cura 2.7 to Cura 3.0.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -720,7 +720,7 @@
|
||||
"display_name": "Version Upgrade 3.0 to 3.1",
|
||||
"description": "Upgrades configurations from Cura 3.0 to Cura 3.1.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -737,7 +737,7 @@
|
||||
"display_name": "Version Upgrade 3.2 to 3.3",
|
||||
"description": "Upgrades configurations from Cura 3.2 to Cura 3.3.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -754,7 +754,7 @@
|
||||
"display_name": "Version Upgrade 3.3 to 3.4",
|
||||
"description": "Upgrades configurations from Cura 3.3 to Cura 3.4.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -771,7 +771,7 @@
|
||||
"display_name": "Version Upgrade 3.4 to 3.5",
|
||||
"description": "Upgrades configurations from Cura 3.4 to Cura 3.5.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -788,7 +788,7 @@
|
||||
"display_name": "Version Upgrade 3.5 to 4.0",
|
||||
"description": "Upgrades configurations from Cura 3.5 to Cura 4.0.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -805,7 +805,7 @@
|
||||
"display_name": "Version Upgrade 4.0 to 4.1",
|
||||
"description": "Upgrades configurations from Cura 4.0 to Cura 4.1.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -822,7 +822,7 @@
|
||||
"display_name": "Version Upgrade 4.1 to 4.2",
|
||||
"description": "Upgrades configurations from Cura 4.1 to Cura 4.2.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -839,7 +839,7 @@
|
||||
"display_name": "Version Upgrade 4.2 to 4.3",
|
||||
"description": "Upgrades configurations from Cura 4.2 to Cura 4.3.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -856,7 +856,7 @@
|
||||
"display_name": "Version Upgrade 4.3 to 4.4",
|
||||
"description": "Upgrades configurations from Cura 4.3 to Cura 4.4.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -873,7 +873,7 @@
|
||||
"display_name": "Version Upgrade 4.4 to 4.5",
|
||||
"description": "Upgrades configurations from Cura 4.4 to Cura 4.5.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -890,7 +890,7 @@
|
||||
"display_name": "Version Upgrade 4.5 to 4.6",
|
||||
"description": "Upgrades configurations from Cura 4.5 to Cura 4.6.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -907,7 +907,7 @@
|
||||
"display_name": "Version Upgrade 4.6.0 to 4.6.2",
|
||||
"description": "Upgrades configurations from Cura 4.6.0 to Cura 4.6.2.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -924,7 +924,7 @@
|
||||
"display_name": "Version Upgrade 4.6.2 to 4.7",
|
||||
"description": "Upgrades configurations from Cura 4.6.2 to Cura 4.7.",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -941,7 +941,7 @@
|
||||
"display_name": "Version Upgrade 4.7.0 to 4.8.0",
|
||||
"description": "Upgrades configurations from Cura 4.7.0 to Cura 4.8.0",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -958,7 +958,7 @@
|
||||
"display_name": "Version Upgrade 4.8.0 to 4.9.0",
|
||||
"description": "Upgrades configurations from Cura 4.8.0 to Cura 4.9.0",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -975,7 +975,7 @@
|
||||
"display_name": "Version Upgrade 4.9 to 4.10",
|
||||
"description": "Upgrades configurations from Cura 4.9 to Cura 4.10",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -992,7 +992,7 @@
|
||||
"display_name": "Version Upgrade 4.11 to 4.12",
|
||||
"description": "Upgrades configurations from Cura 4.11 to Cura 4.12",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"sdk_version_semver": "7.7.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
@ -1010,7 +1010,7 @@
|
||||
"display_name": "Version Upgrade 4.13 to 5.0",
|
||||
"description": "Upgrades configurations from Cura 4.13 to Cura 5.0",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1027,7 +1027,7 @@
|
||||
"display_name": "Version Upgrade 5.2 to 5.3",
|
||||
"description": "Upgrades configurations from Cura 5.2 to Cura 5.3",
|
||||
"package_version": "1.0.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1044,7 +1044,7 @@
|
||||
"display_name": "X3D Reader",
|
||||
"description": "Provides support for reading X3D files.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "SevaAlekseyev",
|
||||
@ -1061,7 +1061,7 @@
|
||||
"display_name": "XML Material Profiles",
|
||||
"description": "Provides capabilities to read and write XML-based material profiles.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1078,7 +1078,7 @@
|
||||
"display_name": "X-Ray View",
|
||||
"description": "Provides the X-Ray view.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1095,7 +1095,7 @@
|
||||
"display_name": "Generic ABS",
|
||||
"description": "The generic ABS profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1113,7 +1113,7 @@
|
||||
"display_name": "Generic BAM",
|
||||
"description": "The generic BAM profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1131,7 +1131,7 @@
|
||||
"display_name": "Generic CFF CPE",
|
||||
"description": "The generic CFF CPE profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1149,7 +1149,7 @@
|
||||
"display_name": "Generic CFF PA",
|
||||
"description": "The generic CFF PA profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1167,7 +1167,7 @@
|
||||
"display_name": "Generic CPE",
|
||||
"description": "The generic CPE profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1185,7 +1185,7 @@
|
||||
"display_name": "Generic CPE+",
|
||||
"description": "The generic CPE+ profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1203,7 +1203,7 @@
|
||||
"display_name": "Generic GFF CPE",
|
||||
"description": "The generic GFF CPE profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1221,7 +1221,7 @@
|
||||
"display_name": "Generic GFF PA",
|
||||
"description": "The generic GFF PA profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1239,7 +1239,7 @@
|
||||
"display_name": "Generic HIPS",
|
||||
"description": "The generic HIPS profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1257,7 +1257,7 @@
|
||||
"display_name": "Generic Nylon",
|
||||
"description": "The generic Nylon profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1275,7 +1275,7 @@
|
||||
"display_name": "Generic PC",
|
||||
"description": "The generic PC profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1293,7 +1293,7 @@
|
||||
"display_name": "Generic PETG",
|
||||
"description": "The generic PETG profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1311,7 +1311,7 @@
|
||||
"display_name": "Generic PLA",
|
||||
"description": "The generic PLA profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1329,7 +1329,7 @@
|
||||
"display_name": "Generic PP",
|
||||
"description": "The generic PP profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1347,7 +1347,7 @@
|
||||
"display_name": "Generic PVA",
|
||||
"description": "The generic PVA profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1365,7 +1365,7 @@
|
||||
"display_name": "Generic Tough PLA",
|
||||
"description": "The generic Tough PLA profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1383,7 +1383,7 @@
|
||||
"display_name": "Generic TPU",
|
||||
"description": "The generic TPU profile which other profiles can be based upon.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://github.com/Ultimaker/fdm_materials",
|
||||
"author": {
|
||||
"author_id": "Generic",
|
||||
@ -1401,7 +1401,7 @@
|
||||
"display_name": "Dagoma Chromatik PLA",
|
||||
"description": "Filament testé et approuvé pour les imprimantes 3D Dagoma. Chromatik est l'idéal pour débuter et suivre les tutoriels premiers pas. Il vous offre qualité et résistance pour chacune de vos impressions.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://dagoma.fr/boutique/filaments.html",
|
||||
"author": {
|
||||
"author_id": "Dagoma",
|
||||
@ -1418,7 +1418,7 @@
|
||||
"display_name": "FABtotum ABS",
|
||||
"description": "This material is easy to be extruded but it is not the simplest to use. It is one of the most used in 3D printing to get very well finished objects. It is not sustainable and its smoke can be dangerous if inhaled. The reason to prefer this filament to PLA is mainly because of its precision and mechanical specs. ABS (for plastic) stands for Acrylonitrile Butadiene Styrene and it is a thermoplastic which is widely used in everyday objects. It can be printed with any FFF 3D printer which can get to high temperatures as it must be extruded in a range between 220° and 245°, so it’s compatible with all versions of the FABtotum Personal fabricator.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=40",
|
||||
"author": {
|
||||
"author_id": "FABtotum",
|
||||
@ -1435,7 +1435,7 @@
|
||||
"display_name": "FABtotum Nylon",
|
||||
"description": "When 3D printing started this material was not listed among the extrudable filaments. It is flexible as well as resistant to tractions. It is well known for its uses in textile but also in industries which require a strong and flexible material. There are different kinds of Nylon: 3D printing mostly uses Nylon 6 and Nylon 6.6, which are the most common. It requires higher temperatures to be printed, so a 3D printer must be able to reach them (around 240°C): the FABtotum, of course, can.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=53",
|
||||
"author": {
|
||||
"author_id": "FABtotum",
|
||||
@ -1452,7 +1452,7 @@
|
||||
"display_name": "FABtotum PLA",
|
||||
"description": "It is the most common filament used for 3D printing. It is studied to be bio-degradable as it comes from corn starch’s sugar mainly. It is completely made of renewable sources and has no footprint on polluting. PLA stands for PolyLactic Acid and it is a thermoplastic that today is still considered the easiest material to be 3D printed. It can be extruded at lower temperatures: the standard range of FABtotum’s one is between 185° and 195°.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=39",
|
||||
"author": {
|
||||
"author_id": "FABtotum",
|
||||
@ -1469,7 +1469,7 @@
|
||||
"display_name": "FABtotum TPU Shore 98A",
|
||||
"description": "",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=66",
|
||||
"author": {
|
||||
"author_id": "FABtotum",
|
||||
@ -1486,7 +1486,7 @@
|
||||
"display_name": "Fiberlogy HD PLA",
|
||||
"description": "With our HD PLA you have many more options. You can use this material in two ways. Choose the one you like best. You can use it as a normal PLA and get prints characterized by a very good adhesion between the layers and high precision. You can also make your prints acquire similar properties to that of ABS – better impact resistance and high temperature resistance. All you need is an oven. Yes, an oven! By annealing our HD PLA in an oven, in accordance with the manual, you will avoid all the inconveniences of printing with ABS, such as unpleasant odour or hazardous fumes.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://fiberlogy.com/en/fiberlogy-filaments/filament-hd-pla/",
|
||||
"author": {
|
||||
"author_id": "Fiberlogy",
|
||||
@ -1503,7 +1503,7 @@
|
||||
"display_name": "Filo3D PLA",
|
||||
"description": "Fast, safe and reliable printing. PLA is ideal for the fast and reliable printing of parts and prototypes with a great surface quality.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://dagoma.fr",
|
||||
"author": {
|
||||
"author_id": "Dagoma",
|
||||
@ -1520,7 +1520,7 @@
|
||||
"display_name": "IMADE3D JellyBOX PETG",
|
||||
"description": "",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://shop.imade3d.com/filament.html",
|
||||
"author": {
|
||||
"author_id": "IMADE3D",
|
||||
@ -1537,7 +1537,7 @@
|
||||
"display_name": "IMADE3D JellyBOX PLA",
|
||||
"description": "",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://shop.imade3d.com/filament.html",
|
||||
"author": {
|
||||
"author_id": "IMADE3D",
|
||||
@ -1554,7 +1554,7 @@
|
||||
"display_name": "Octofiber PLA",
|
||||
"description": "PLA material from Octofiber.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://nl.octofiber.com/3d-printing-filament/pla.html",
|
||||
"author": {
|
||||
"author_id": "Octofiber",
|
||||
@ -1571,7 +1571,7 @@
|
||||
"display_name": "PolyFlex™ PLA",
|
||||
"description": "PolyFlex™ is a highly flexible yet easy to print 3D printing material. Featuring good elasticity and a large strain-to- failure, PolyFlex™ opens up a completely new realm of applications.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://www.polymaker.com/shop/polyflex/",
|
||||
"author": {
|
||||
"author_id": "Polymaker",
|
||||
@ -1588,7 +1588,7 @@
|
||||
"display_name": "PolyMax™ PLA",
|
||||
"description": "PolyMax™ PLA is a 3D printing material with excellent mechanical properties and printing quality. PolyMax™ PLA has an impact resistance of up to nine times that of regular PLA, and better overall mechanical properties than ABS.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://www.polymaker.com/shop/polymax/",
|
||||
"author": {
|
||||
"author_id": "Polymaker",
|
||||
@ -1605,7 +1605,7 @@
|
||||
"display_name": "PolyPlus™ PLA True Colour",
|
||||
"description": "PolyPlus™ PLA is a premium PLA designed for all desktop FDM/FFF 3D printers. It is produced with our patented Jam-Free™ technology that ensures consistent extrusion and prevents jams.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://www.polymaker.com/shop/polyplus-true-colour/",
|
||||
"author": {
|
||||
"author_id": "Polymaker",
|
||||
@ -1622,7 +1622,7 @@
|
||||
"display_name": "PolyWood™ PLA",
|
||||
"description": "PolyWood™ is a wood mimic printing material that contains no actual wood ensuring a clean Jam-Free™ printing experience.",
|
||||
"package_version": "1.0.1",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "http://www.polymaker.com/shop/polywood/",
|
||||
"author": {
|
||||
"author_id": "Polymaker",
|
||||
@ -1639,7 +1639,7 @@
|
||||
"display_name": "Ultimaker ABS",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/abs",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1658,7 +1658,7 @@
|
||||
"display_name": "Ultimaker Breakaway",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/breakaway",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1677,7 +1677,7 @@
|
||||
"display_name": "Ultimaker CPE",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/abs",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1696,7 +1696,7 @@
|
||||
"display_name": "Ultimaker CPE+",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/cpe",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1715,7 +1715,7 @@
|
||||
"display_name": "Ultimaker Nylon",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/abs",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1734,7 +1734,7 @@
|
||||
"display_name": "Ultimaker PC",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/pc",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1753,7 +1753,7 @@
|
||||
"display_name": "Ultimaker PLA",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/abs",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1772,7 +1772,7 @@
|
||||
"display_name": "Ultimaker PP",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/pp",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1791,7 +1791,7 @@
|
||||
"display_name": "Ultimaker PVA",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/abs",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1810,7 +1810,7 @@
|
||||
"display_name": "Ultimaker TPU 95A",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/tpu-95a",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1829,7 +1829,7 @@
|
||||
"display_name": "Ultimaker Tough PLA",
|
||||
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://ultimaker.com/products/materials/tough-pla",
|
||||
"author": {
|
||||
"author_id": "UltimakerPackages",
|
||||
@ -1848,7 +1848,7 @@
|
||||
"display_name": "Vertex Delta ABS",
|
||||
"description": "ABS material and quality files for the Delta Vertex K8800.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://vertex3dprinter.eu",
|
||||
"author": {
|
||||
"author_id": "Velleman",
|
||||
@ -1865,7 +1865,7 @@
|
||||
"display_name": "Vertex Delta PET",
|
||||
"description": "ABS material and quality files for the Delta Vertex K8800.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://vertex3dprinter.eu",
|
||||
"author": {
|
||||
"author_id": "Velleman",
|
||||
@ -1882,7 +1882,7 @@
|
||||
"display_name": "Vertex Delta PLA",
|
||||
"description": "ABS material and quality files for the Delta Vertex K8800.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://vertex3dprinter.eu",
|
||||
"author": {
|
||||
"author_id": "Velleman",
|
||||
@ -1899,7 +1899,7 @@
|
||||
"display_name": "Vertex Delta TPU",
|
||||
"description": "ABS material and quality files for the Delta Vertex K8800.",
|
||||
"package_version": "1.4.0",
|
||||
"sdk_version": "8.2.0",
|
||||
"sdk_version": "8.4.0",
|
||||
"website": "https://vertex3dprinter.eu",
|
||||
"author": {
|
||||
"author_id": "Velleman",
|
||||
|
@ -81,7 +81,7 @@
|
||||
"value": "material_print_temperature + 5"
|
||||
},
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": true },
|
||||
"prime_tower_brim_enable": { "value": true },
|
||||
"prime_tower_min_volume":
|
||||
|
@ -82,7 +82,7 @@
|
||||
"value": "material_print_temperature + 5"
|
||||
},
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": true },
|
||||
"prime_tower_brim_enable": { "value": true },
|
||||
"prime_tower_min_volume":
|
||||
|
@ -76,7 +76,7 @@
|
||||
"value": "material_print_temperature + 5"
|
||||
},
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": true },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'all'" },
|
||||
"retraction_combing_max_distance": { "value": 30 },
|
||||
|
@ -59,7 +59,7 @@
|
||||
"machine_width": { "default_value": 280 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||
"prime_tower_min_volume": { "value": "((reveOrValue('layer_height'))/2" },
|
||||
"prime_tower_min_volume": { "value": "((resolveOrValue('layer_height'))/2" },
|
||||
"prime_tower_position_x": { "value": "240" },
|
||||
"prime_tower_position_y": { "value": "190" },
|
||||
"prime_tower_size": { "value": "30" },
|
||||
|
@ -10,57 +10,18 @@
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "alya_platform.3mf",
|
||||
"exclude_materials": [
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"dsm_arnitel2045",
|
||||
"dsm_novamid1070",
|
||||
"generic_abs",
|
||||
"generic_abs_175",
|
||||
"generic_bam",
|
||||
"generic_cpe",
|
||||
"generic_cpe_175",
|
||||
"generic_cpe_plus",
|
||||
"generic_hips",
|
||||
"generic_hips_175",
|
||||
"generic_nylon",
|
||||
"generic_nylon_175",
|
||||
"generic_pc",
|
||||
"generic_pc_175",
|
||||
"generic_petg",
|
||||
"generic_petg_175",
|
||||
"generic_pp",
|
||||
"generic_pva",
|
||||
"generic_pva_175",
|
||||
"generic_tough_pla",
|
||||
"generic_tpu",
|
||||
"generic_tpu_175",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"innofill_innoflex60_175",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"verbatim_bvoh_175",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla",
|
||||
"tizyx_pla",
|
||||
"tizyx_abs",
|
||||
"tizyx_pla_bois"
|
||||
"innofill_innoflex60",
|
||||
"verbatim_bvoh"
|
||||
],
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
|
@ -10,57 +10,18 @@
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "alya_nx_platform.3mf",
|
||||
"exclude_materials": [
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"generic_abs",
|
||||
"generic_abs_175",
|
||||
"generic_bam",
|
||||
"generic_cpe",
|
||||
"generic_cpe_175",
|
||||
"generic_cpe_plus",
|
||||
"generic_hips",
|
||||
"generic_hips_175",
|
||||
"generic_nylon",
|
||||
"generic_nylon_175",
|
||||
"generic_pc",
|
||||
"generic_pc_175",
|
||||
"generic_petg",
|
||||
"generic_petg_175",
|
||||
"generic_pp",
|
||||
"generic_pva",
|
||||
"generic_pva_175",
|
||||
"generic_tough_pla",
|
||||
"generic_tpu",
|
||||
"generic_tpu_175",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"innofill_innoflex60_175",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"verbatim_bvoh_175",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla",
|
||||
"tizyx_pla",
|
||||
"tizyx_abs",
|
||||
"tizyx_pla_bois"
|
||||
"verbatim_bvoh_175"
|
||||
],
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
|
@ -17,7 +17,7 @@
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"acceleration_enabled": { "value": "true" },
|
||||
"acceleration_enabled": { "value": "True" },
|
||||
"acceleration_infill": { "maximum_value_warning": "2500" },
|
||||
"acceleration_layer_0": { "maximum_value_warning": "2500" },
|
||||
"acceleration_prime_tower": { "maximum_value_warning": "2500" },
|
||||
@ -74,7 +74,7 @@
|
||||
"value": "material_print_temperature + 5"
|
||||
},
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"retraction_amount": { "default_value": 1.5 },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'infill'" },
|
||||
"retraction_hop": { "value": 0.2 },
|
||||
|
@ -68,7 +68,7 @@
|
||||
},
|
||||
"meshfix_maximum_deviation": { "value": 0.05 },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": "True" },
|
||||
"retraction_amount": { "value": 6 },
|
||||
"retraction_combing": { "value": "'off'" },
|
||||
@ -110,12 +110,9 @@
|
||||
"support_interface_enable": { "value": true },
|
||||
"support_interface_height": { "value": "layer_height * 4" },
|
||||
"support_interface_pattern": { "value": "'grid'" },
|
||||
"support_interface_skip_height": { "value": 0.2 },
|
||||
"support_pattern": { "value": "'zigzag'" },
|
||||
"support_structure": { "value": "'tree'" },
|
||||
"support_top_distance": { "value": "extruderValue(support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr, 'support_z_distance') + (layer_height if support_structure == 'tree' else 0)" },
|
||||
"support_type": { "value": "'buildplate' if support_structure == 'tree' else 'everywhere'" },
|
||||
"support_wall_count": { "value": 1 },
|
||||
"support_xy_distance": { "value": "wall_line_width_0 * 2" },
|
||||
"support_xy_distance_overhang": { "value": "wall_line_width_0" },
|
||||
"support_xy_overrides_z": { "value": "'xy_overrides_z'" },
|
||||
|
29
resources/definitions/anycubic_kobra_plus.def.json
Normal file
29
resources/definitions/anycubic_kobra_plus.def.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Anycubic Kobra Plus",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata":
|
||||
{
|
||||
"visible": true,
|
||||
"author": "Jordon Brooks",
|
||||
"manufacturer": "Anycubic",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
"machine_extruder_trains": { "0": "anycubic_kobra_plus_extruder_0" },
|
||||
"preferred_material": "generic_pla",
|
||||
"preferred_quality_type": "normal",
|
||||
"quality_definition": "anycubic_kobra_plus"
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"machine_depth": { "default_value": 302 },
|
||||
"machine_end_gcode": { "default_value": "M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84\nM355 S0; led off" },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_height": { "default_value": 352 },
|
||||
"machine_name": { "default_value": "Anycubic Kobra Plus" },
|
||||
"machine_start_gcode": { "default_value": "G28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\n;Prime the extruder\nG92 E0\nM355 S1; Turn LED on\n; Add Custom purge lines\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X1.0 Y30 Z0.3 F5000.0 ; Move to start position\nG1 X1.0 Y100.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X1.3 Y100.0 Z0.3 F5000.0 ; Move to side a little\nG1 X1.3 Y30 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 E-2 F500 ; Retract a little \nG1 X50 F500 ; wipe away from the filament line\nG1 X100 F9000 ; Quickly wipe away from the filament line\nG1 Z5.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\n; End custom purge lines" },
|
||||
"machine_width": { "default_value": 302 }
|
||||
}
|
||||
}
|
@ -18,51 +18,6 @@
|
||||
{
|
||||
"machine_center_is_zero": { "default_value": true },
|
||||
"machine_depth": { "default_value": 180 },
|
||||
"machine_disallowed_areas":
|
||||
{
|
||||
"default_value": [
|
||||
[
|
||||
[-50, -85],
|
||||
[-85, -85],
|
||||
[-90, -90]
|
||||
],
|
||||
[
|
||||
[-85, -85],
|
||||
[-85, -50],
|
||||
[-90, -90]
|
||||
],
|
||||
[
|
||||
[50, -85],
|
||||
[85, -85],
|
||||
[90, -90]
|
||||
],
|
||||
[
|
||||
[85, -85],
|
||||
[85, -50],
|
||||
[90, -90]
|
||||
],
|
||||
[
|
||||
[-50, 85],
|
||||
[-85, 85],
|
||||
[-90, 90]
|
||||
],
|
||||
[
|
||||
[-85, 85],
|
||||
[-85, 50],
|
||||
[-90, 90]
|
||||
],
|
||||
[
|
||||
[50, 85],
|
||||
[85, 85],
|
||||
[90, 90]
|
||||
],
|
||||
[
|
||||
[85, 85],
|
||||
[85, 50],
|
||||
[90, 90]
|
||||
]
|
||||
]
|
||||
},
|
||||
"machine_end_gcode": { "default_value": "M400 ;Free buffer\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 F{speed_travel} Z+1 E-5 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off\nM107 ;fan off\nM84 ;steppers off\nG28 ;move to endstop\nM84 ;steppers off" },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
|
@ -16,51 +16,6 @@
|
||||
"overrides":
|
||||
{
|
||||
"machine_depth": { "default_value": 240 },
|
||||
"machine_disallowed_areas":
|
||||
{
|
||||
"default_value": [
|
||||
[
|
||||
[-50, -115],
|
||||
[-115, -115],
|
||||
[-90, -90]
|
||||
],
|
||||
[
|
||||
[-115, -115],
|
||||
[-115, -50],
|
||||
[-90, -90]
|
||||
],
|
||||
[
|
||||
[50, -115],
|
||||
[115, -115],
|
||||
[90, -90]
|
||||
],
|
||||
[
|
||||
[115, -115],
|
||||
[115, -50],
|
||||
[90, -90]
|
||||
],
|
||||
[
|
||||
[-50, 115],
|
||||
[-115, 115],
|
||||
[-90, 90]
|
||||
],
|
||||
[
|
||||
[-115, 115],
|
||||
[-115, 50],
|
||||
[-90, 90]
|
||||
],
|
||||
[
|
||||
[50, 115],
|
||||
[115, 115],
|
||||
[90, 90]
|
||||
],
|
||||
[
|
||||
[115, 115],
|
||||
[115, 50],
|
||||
[90, 90]
|
||||
]
|
||||
]
|
||||
},
|
||||
"machine_name": { "default_value": "Anycubic Kossel Linear Plus" },
|
||||
"machine_width": { "default_value": 240 }
|
||||
}
|
||||
|
@ -9,51 +9,10 @@
|
||||
"manufacturer": "Artillery",
|
||||
"file_formats": "text/x-gcode",
|
||||
"exclude_materials": [
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"generic_bam",
|
||||
"generic_cffcpe",
|
||||
"generic_cffpa",
|
||||
"generic_cpe",
|
||||
"generic_cpe_plus",
|
||||
"generic_gffcpe",
|
||||
"generic_gffpa",
|
||||
"generic_hips",
|
||||
"generic_nylon",
|
||||
"generic_pc",
|
||||
"generic_pp",
|
||||
"generic_pva",
|
||||
"generic_tough_pla",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"innofill_innoflex60_175",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"structur3d_dap100silicone",
|
||||
"tizyx_abs",
|
||||
"tizyx_pla",
|
||||
"tizyx_pla_bois",
|
||||
"verbatim_bvoh_175",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla"
|
||||
"verbatim_bvoh_175"
|
||||
],
|
||||
"first_start_actions": [ "MachineSettingsAction" ],
|
||||
"has_machine_quality": true,
|
||||
@ -110,7 +69,7 @@
|
||||
"meshfix_maximum_resolution": { "value": "0.25" },
|
||||
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": true },
|
||||
"retraction_amount": { "value": 2 },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'infill'" },
|
||||
|
@ -9,73 +9,13 @@
|
||||
"manufacturer": "ATMAT sp. z o.o.",
|
||||
"file_formats": "text/x-gcode",
|
||||
"exclude_materials": [
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"emotiontech_abs",
|
||||
"emotiontech_petg",
|
||||
"emotiontech_pla",
|
||||
"emotiontech_pva-m",
|
||||
"emotiontech_pva-oks",
|
||||
"emotiontech_pva-s",
|
||||
"emotiontech_tpu98a",
|
||||
"emotiontech_asax",
|
||||
"emotiontech_hips",
|
||||
"fiberlogy_hd_pla",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"generic_abs",
|
||||
"generic_bam",
|
||||
"generic_cffcpe",
|
||||
"generic_cffpa",
|
||||
"dsm_arnitel2045",
|
||||
"dsm_novamid1070",
|
||||
"generic_cpe",
|
||||
"generic_cpe_plus",
|
||||
"generic_gffcpe",
|
||||
"generic_gffpa",
|
||||
"generic_hips",
|
||||
"generic_nylon",
|
||||
"generic_pc",
|
||||
"generic_petg",
|
||||
"generic_pla",
|
||||
"generic_pp",
|
||||
"generic_pva",
|
||||
"generic_tough_pla",
|
||||
"generic_tpu",
|
||||
"generic_cpe_175",
|
||||
"imade3d_petg_175",
|
||||
"imade3d_pla_175",
|
||||
"innofill_innoflex60_175",
|
||||
"leapfrog_abs_natural",
|
||||
"leapfrog_epla_natural",
|
||||
"leapfrog_pva_natural",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"structur3d_dap100silicone",
|
||||
"tizyx_abs",
|
||||
"tizyx_flex",
|
||||
"tizyx_petg",
|
||||
"tizyx_pla",
|
||||
"tizyx_pla_bois",
|
||||
"tizyx_pva",
|
||||
"verbatim_bvoh_175",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_PLA_Glitter",
|
||||
"Vertex_Delta_PLA_Mat",
|
||||
"Vertex_Delta_PLA_Satin",
|
||||
"Vertex_Delta_PLA_Wood",
|
||||
"Vertex_Delta_TPU",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla"
|
||||
"imade3d_petg",
|
||||
"imade3d_pla",
|
||||
"innofill_innoflex60",
|
||||
"verbatim_bvoh"
|
||||
],
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
|
@ -63,7 +63,7 @@
|
||||
"meshfix_maximum_resolution": { "value": "0.25" },
|
||||
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": "True" },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'noskin'" },
|
||||
"retraction_combing_max_distance": { "value": 30 },
|
||||
|
@ -55,7 +55,7 @@
|
||||
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_polygon_circumference": { "default_value": 0.2 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": "True" },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'noskin'" },
|
||||
"retraction_combing_max_distance": { "value": 30 },
|
||||
|
@ -9,55 +9,10 @@
|
||||
"manufacturer": "Creality3D",
|
||||
"file_formats": "text/x-gcode",
|
||||
"exclude_materials": [
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"generic_abs",
|
||||
"generic_bam",
|
||||
"generic_cffcpe",
|
||||
"generic_cffpa",
|
||||
"generic_cpe",
|
||||
"generic_cpe_plus",
|
||||
"generic_gffcpe",
|
||||
"generic_gffpa",
|
||||
"generic_hips",
|
||||
"generic_nylon",
|
||||
"generic_pc",
|
||||
"generic_petg",
|
||||
"generic_pla",
|
||||
"generic_pp",
|
||||
"generic_pva",
|
||||
"generic_tough_pla",
|
||||
"generic_tpu",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"innofill_innoflex60_175",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"structur3d_dap100silicone",
|
||||
"tizyx_abs",
|
||||
"tizyx_pla",
|
||||
"tizyx_pla_bois",
|
||||
"verbatim_bvoh_175",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla"
|
||||
"dsm_arnitel2045",
|
||||
"dsm_novamid1070",
|
||||
"innofill_innoflex60",
|
||||
"verbatim_bvoh"
|
||||
],
|
||||
"first_start_actions": [ "MachineSettingsAction" ],
|
||||
"has_machine_quality": true,
|
||||
@ -113,7 +68,7 @@
|
||||
"meshfix_maximum_resolution": { "value": "0.25" },
|
||||
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||
"minimum_interface_area": { "value": 10 },
|
||||
"minimum_support_area": { "value": 2 },
|
||||
"minimum_support_area": { "value": "2 if support_structure == 'normal' else 0" },
|
||||
"optimize_wall_printing_order": { "value": "True" },
|
||||
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'noskin'" },
|
||||
"retraction_combing_max_distance": { "value": 30 },
|
||||
@ -157,10 +112,7 @@
|
||||
"support_interface_enable": { "value": true },
|
||||
"support_interface_height": { "value": "layer_height * 4" },
|
||||
"support_interface_pattern": { "value": "'grid'" },
|
||||
"support_interface_skip_height": { "value": 0.2 },
|
||||
"support_pattern": { "value": "'zigzag'" },
|
||||
"support_top_distance": { "value": "extruderValue(support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr, 'support_z_distance') + (layer_height if support_structure == 'tree' else 0)" },
|
||||
"support_wall_count": { "value": 1 },
|
||||
"support_xy_distance": { "value": "wall_line_width_0 * 2" },
|
||||
"support_xy_distance_overhang": { "value": "wall_line_width_0" },
|
||||
"support_xy_overrides_z": { "value": "'xy_overrides_z'" },
|
||||
|
@ -23,7 +23,7 @@
|
||||
},
|
||||
"machine_height": { "default_value": 250 },
|
||||
"machine_name": { "default_value": "Creality Ender-3 Pro" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 Custom Start G-code\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nM104 S{material_standby_temperature} ; Start heating up the nozzle most of the way\nM190 S{material_bed_temperature_layer_0} ; Start heating the bed, wait until target temperature reached\nM109 S{material_print_temperature_layer_0} ; Finish heating the nozzle\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 Custom Start G-code\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nG1 Z5.0 F3000 ; Move Z Axis up a bit during heating to not damage bed\nM104 S{material_standby_temperature} ; Start heating up the nozzle most of the way\nM190 S{material_bed_temperature_layer_0} ; Start heating the bed, wait until target temperature reached\nM109 S{material_print_temperature_layer_0} ; Finish heating the nozzle\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish" },
|
||||
"machine_width": { "default_value": 220 }
|
||||
}
|
||||
}
|
@ -24,13 +24,13 @@
|
||||
},
|
||||
"machine_height": { "default_value": 270 },
|
||||
"machine_name": { "default_value": "Creality Ender-3 S1" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Start G-code\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nG1 Z10.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0 Y0\n\nM104 S{material_print_temperature_layer_0}\nM190 S{material_bed_temperature_layer_0}\nM109 S{material_print_temperature_layer_0}\n\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish\n" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Start G-code\n; M413 S0 ; Disable power loss recovery\nG92 E0 ; Reset Extruder\n\n; Prep surfaces before auto home for better accuracy\nM140 S{material_bed_temperature_layer_0}\nM104 S{material_print_temperature_layer_0}\n\nG28 ; Home all axes\nG1 Z10.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0 Y0\n\nM190 S{material_bed_temperature_layer_0}\nM109 S{material_print_temperature_layer_0}\n\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish\n" },
|
||||
"machine_width": { "default_value": 220 },
|
||||
"retraction_amount": { "value": 0.8 },
|
||||
"retraction_extrusion_window": { "value": 1.5 },
|
||||
"retraction_speed": { "default_value": 40 },
|
||||
"speed_layer_0": { "value": 25 },
|
||||
"speed_print": { "value": 50 },
|
||||
"speed_travel": { "value": 150 }
|
||||
"speed_print": { "value": 60 },
|
||||
"speed_travel": { "value": "120.0 if speed_print < 60 else 250.0 if speed_print > 100 else speed_print * 2.5" }
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"acceleration_enabled": { "value": true },
|
||||
"acceleration_travel": { "value": 2000 },
|
||||
"gantry_height": { "value": 25 },
|
||||
"machine_depth": { "default_value": 300 },
|
||||
"machine_head_with_fans_polygon":
|
||||
@ -22,11 +24,13 @@
|
||||
},
|
||||
"machine_height": { "default_value": 300 },
|
||||
"machine_name": { "default_value": "Creality Ender-3 S1 Plus" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Plus Start G-code\nG28 ;Home\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\n" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Plus Start G-code\n; M413 S0 ; Disable power loss recovery\nG92 E0 ; Reset Extruder\n\n; Prep surfaces before auto home for better accuracy\nM140 S{material_bed_temperature_layer_0}\nM104 S{material_print_temperature_layer_0}\n\nG28 ; Home all axes\nG1 Z10.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0 Y0\n\nM190 S{material_bed_temperature_layer_0}\nM109 S{material_print_temperature_layer_0}\n\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish\n" },
|
||||
"machine_width": { "default_value": 300 },
|
||||
"retraction_amount": { "value": 0.8 },
|
||||
"retraction_extrusion_window": { "value": 1.5 },
|
||||
"retraction_speed": { "default_value": 40 },
|
||||
"speed_layer_0": { "value": 25 },
|
||||
"speed_print": { "value": 60 },
|
||||
"speed_travel": { "value": "120.0 if speed_print < 60 else 250.0 if speed_print > 100 else speed_print * 2.5" }
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"acceleration_enabled": { "value": true },
|
||||
"acceleration_travel": { "value": 2000 },
|
||||
"gantry_height": { "value": 25 },
|
||||
"machine_depth": { "default_value": 220 },
|
||||
"machine_head_with_fans_polygon":
|
||||
@ -22,10 +24,13 @@
|
||||
},
|
||||
"machine_height": { "default_value": 270 },
|
||||
"machine_name": { "default_value": "Creality Ender-3 S1 Pro" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Pro Start G-code\nG28 ;Home\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\n" },
|
||||
"machine_start_gcode": { "default_value": "; Ender 3 S1 Pro Start G-code\n; M413 S0 ; Disable power loss recovery\nG92 E0 ; Reset Extruder\n\n; Prep surfaces before auto home for better accuracy\nM140 S{material_bed_temperature_layer_0}\nM104 S{material_print_temperature_layer_0}\n\nG28 ; Home all axes\nG1 Z10.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0 Y0\n\nM190 S{material_bed_temperature_layer_0}\nM109 S{material_print_temperature_layer_0}\n\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish\n" },
|
||||
"machine_width": { "default_value": 220 },
|
||||
"retraction_amount": { "value": 0.8 },
|
||||
"retraction_extrusion_window": { "value": 1.5 },
|
||||
"retraction_speed": { "default_value": 40 },
|
||||
"speed_layer_0": { "value": 25 },
|
||||
"speed_print": { "value": 60 },
|
||||
"speed_travel": { "value": "120.0 if speed_print < 60 else 250.0 if speed_print > 100 else speed_print * 2.5" }
|
||||
}
|
||||
}
|
37
resources/definitions/creality_ender5s1.def.json
Normal file
37
resources/definitions/creality_ender5s1.def.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Creality Ender-5 S1",
|
||||
"inherits": "creality_base",
|
||||
"metadata":
|
||||
{
|
||||
"visible": true,
|
||||
"quality_definition": "creality_base"
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"build_volume_temperature": { "value": 195 },
|
||||
"cool_min_layer_time": { "value": 5 },
|
||||
"gantry_height": { "value": 25 },
|
||||
"machine_depth": { "default_value": 225 },
|
||||
"machine_end_gcode": { "default_value": "G91 ;Relative positionning\nG1 E-2 F2700 ;Retract a bit\nG1 E-2 Z0.2 F2400 ;Retract and raise Z\nG1 X5 Y5 F3000 ;Wipe out\nG1 Z10 ;Raise Z more\nG90 ;Absolute positionning\n\nG1 X0 Y0 ;Present print\nM106 S0 ;Turn-off fan\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\n\nM84 X Y E ;Disable all steppers but Z\n" },
|
||||
"machine_head_with_fans_polygon":
|
||||
{
|
||||
"default_value": [
|
||||
[-26, 34],
|
||||
[-26, -32],
|
||||
[32, -32],
|
||||
[32, 34]
|
||||
]
|
||||
},
|
||||
"machine_height": { "default_value": 305 },
|
||||
"machine_name": { "default_value": "Creality Ender-5 S1" },
|
||||
"machine_width": { "default_value": 225 },
|
||||
"material_bed_temperature": { "value": 60 },
|
||||
"retraction_amount": { "value": 2 },
|
||||
"retraction_speed": { "value": 45 },
|
||||
"speed_print": { "value": 80.0 },
|
||||
"support_z_distance": { "value": 0.25 },
|
||||
"wall_thickness": { "value": "line_width * 3" },
|
||||
"z_seam_type": { "value": "'sharpest_corner'" }
|
||||
}
|
||||
}
|
@ -9,28 +9,17 @@
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "elegoo_platform.3mf",
|
||||
"exclude_materials": [
|
||||
"generic_nylon_175",
|
||||
"generic_nylon",
|
||||
"generic_hips_175",
|
||||
"generic_hips",
|
||||
"generic_gffcpe",
|
||||
"generic_bvoh_175",
|
||||
"generic_ccfpe",
|
||||
"generic_cffcpe",
|
||||
"generic_cpe_plus",
|
||||
"generic_cpe_175",
|
||||
"generic_bvoh",
|
||||
"generic_cpe",
|
||||
"generic_tpu",
|
||||
"generic_pp",
|
||||
"generic_pc",
|
||||
"generic_pc_175",
|
||||
"generic_pvc",
|
||||
"generic_pva",
|
||||
"generic_pva_175",
|
||||
"generic_pvc_175",
|
||||
"generic_pp"
|
||||
"generic_pvc"
|
||||
],
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
"has_variants": true,
|
||||
"machine_extruder_trains": { "0": "elegoo_extruder_0" },
|
||||
"platform_offset": [
|
||||
-2.2,
|
||||
@ -38,7 +27,9 @@
|
||||
-31
|
||||
],
|
||||
"preferred_material": "generic_pla_175",
|
||||
"preferred_quality_type": "fine"
|
||||
"preferred_quality_type": "Elegoo_layer_020",
|
||||
"preferred_variant_name": "0.40mm_Elegoo_Nozzle",
|
||||
"variants_name": "Nozzle Size"
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
@ -78,7 +69,7 @@
|
||||
"material_print_temperature_layer_0": { "value": "210 if material_print_temperature < 210 else material_print_temperature" },
|
||||
"min_infill_area": { "value": "5" },
|
||||
"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 },
|
||||
"prime_tower_brim_enable": { "default_value": true },
|
||||
"prime_tower_min_volume": { "value": "(layer_height) * (prime_tower_size / 2)**2 * 3 * 0.5 " },
|
||||
@ -114,11 +105,7 @@
|
||||
"support_angle": { "value": "45 if speed_print > 99.9 else 50" },
|
||||
"support_bottom_offset": { "value": "-0.4" },
|
||||
"support_brim_enable": { "value": "support_structure == 'normal' or support_structure == 'tree'" },
|
||||
"support_brim_width":
|
||||
{
|
||||
"default_value": 3,
|
||||
"value": "6 if support_structure == 'tree' else line_width * initial_layer_line_width_factor * 0.02 "
|
||||
},
|
||||
"support_brim_width": { "value": "6 if support_structure == 'tree' else line_width * initial_layer_line_width_factor * 0.02 " },
|
||||
"support_infill_angles": { "default_value": "[65]" },
|
||||
"support_interface_density": { "default_value": 33.333 },
|
||||
"support_interface_pattern": { "default_value": "lines" },
|
||||
@ -134,6 +121,6 @@
|
||||
"z_seam_corner": { "default_value": "z_seam_corner_weighted" },
|
||||
"z_seam_position": { "default_value": "left" },
|
||||
"z_seam_type": { "default_value": "back" },
|
||||
"zig_zaggify_infill": { "value": "infill_pattern == 'cross' or infill_pattern == 'cross_3d' or infill_sparse_density < 30 " }
|
||||
"zig_zaggify_infill": { "value": "resolveOrValue('infill_pattern') == 'cross' or resolveOrValue('infill_pattern') == 'cross_3d' or resolveOrValue('infill_sparse_density') < 30 " }
|
||||
}
|
||||
}
|
200
resources/definitions/entina_tina2.def.json
Normal file
200
resources/definitions/entina_tina2.def.json
Normal file
@ -0,0 +1,200 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "ENTINA TINA2",
|
||||
"inherits": "weedo_base",
|
||||
"metadata":
|
||||
{
|
||||
"visible": true,
|
||||
"author": "ENTINA",
|
||||
"manufacturer": "ENTINA",
|
||||
"file_formats": "text/x-gcode",
|
||||
"exclude_materials": [
|
||||
"3D-Fuel_PLA_PRO_Black",
|
||||
"3D-Fuel_PLA_SnapSupport",
|
||||
"bestfilament_abs_skyblue",
|
||||
"bestfilament_petg_orange",
|
||||
"bestfilament_pla_green",
|
||||
"leapfrog_abs_natural",
|
||||
"leapfrog_epla_natural",
|
||||
"leapfrog_pva_natural",
|
||||
"generic_abs_175",
|
||||
"generic_asa_175",
|
||||
"generic_bvoh_175",
|
||||
"generic_cpe_175",
|
||||
"generic_hips_175",
|
||||
"generic_nylon_175",
|
||||
"generic_pc_175",
|
||||
"generic_petg_175",
|
||||
"generic_pva_175",
|
||||
"goofoo_abs",
|
||||
"goofoo_asa",
|
||||
"goofoo_bronze_pla",
|
||||
"goofoo_emarble_pla",
|
||||
"goofoo_esilk_pla",
|
||||
"goofoo_hips",
|
||||
"goofoo_pa_cf",
|
||||
"goofoo_pa",
|
||||
"goofoo_pc",
|
||||
"goofoo_peek",
|
||||
"goofoo_petg",
|
||||
"goofoo_pla",
|
||||
"goofoo_pva",
|
||||
"goofoo_tpe_83a",
|
||||
"goofoo_tpu_87a",
|
||||
"goofoo_tpu_95a",
|
||||
"goofoo_wood_pla",
|
||||
"emotiontech_abs",
|
||||
"emotiontech_absx",
|
||||
"emotiontech_acetate",
|
||||
"emotiontech_asax",
|
||||
"emotiontech_bvoh",
|
||||
"emotiontech_copa",
|
||||
"emotiontech_hips",
|
||||
"emotiontech_nylon_1030",
|
||||
"emotiontech_nylon_1030cf",
|
||||
"emotiontech_nylon_1070",
|
||||
"emotiontech_pc",
|
||||
"emotiontech_pekk",
|
||||
"emotiontech_petg",
|
||||
"emotiontech_pla",
|
||||
"emotiontech_pla_hr_870",
|
||||
"emotiontech_pva-m",
|
||||
"emotiontech_pva-s",
|
||||
"emotiontech_tpu98a",
|
||||
"eryone_petg",
|
||||
"eryone_pla_glow",
|
||||
"eryone_pla_matte",
|
||||
"eryone_pla_wood",
|
||||
"eryone_pla",
|
||||
"eryone_tpu",
|
||||
"eSUN_PETG_Black",
|
||||
"eSUN_PETG_Grey",
|
||||
"eSUN_PETG_Purple",
|
||||
"eSUN_PLA_PRO_Black",
|
||||
"eSUN_PLA_PRO_Grey",
|
||||
"eSUN_PLA_PRO_Purple",
|
||||
"eSUN_PLA_PRO_White",
|
||||
"Extrudr_GreenTECPro_Anthracite_175",
|
||||
"Extrudr_GreenTECPro_Black_175",
|
||||
"Extrudr_GreenTECPro_Blue_175",
|
||||
"Extrudr_GreenTECPro_Nature_175",
|
||||
"Extrudr_GreenTECPro_Red_175",
|
||||
"Extrudr_GreenTECPro_Silver_175",
|
||||
"Extrudr_GreenTECPro_White_175",
|
||||
"verbatim_bvoh_175",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fdplast_abs_tomato",
|
||||
"fdplast_petg_gray",
|
||||
"fdplast_pla_olive",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"imade3d_petg_175",
|
||||
"imade3d_pla_175",
|
||||
"innofill_innoflex60_175",
|
||||
"layer_one_black_pla",
|
||||
"layer_one_dark_gray_pla",
|
||||
"layer_one_white_pla",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"redd_abs",
|
||||
"redd_asa",
|
||||
"redd_hips",
|
||||
"redd_nylon",
|
||||
"redd_petg",
|
||||
"redd_pla",
|
||||
"redd_tpe",
|
||||
"tizyx_abs",
|
||||
"tizyx_flex",
|
||||
"tizyx_petg",
|
||||
"tizyx_pla_bois",
|
||||
"tizyx_pla",
|
||||
"tizyx_pva",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA_Glitter",
|
||||
"Vertex_Delta_PLA_Mat",
|
||||
"Vertex_Delta_PLA_Satin",
|
||||
"Vertex_Delta_PLA_Wood",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"volumic_abs_ultra",
|
||||
"volumic_arma_ultra",
|
||||
"volumic_asa_ultra",
|
||||
"volumic_br80_ultra",
|
||||
"volumic_bumper_ultra",
|
||||
"volumic_cu80_ultra",
|
||||
"volumic_flex93_ultra",
|
||||
"volumic_medical_ultra",
|
||||
"volumic_nylon_ultra",
|
||||
"volumic_pekk_carbone",
|
||||
"volumic_petg_ultra",
|
||||
"volumic_petgcarbone_ultra",
|
||||
"volumic_pla_ultra",
|
||||
"volumic_pp_ultra",
|
||||
"volumic_strong_ultra",
|
||||
"volumic_support_ultra",
|
||||
"xyzprinting_abs",
|
||||
"xyzprinting_antibact_pla",
|
||||
"xyzprinting_carbon_fiber",
|
||||
"xyzprinting_colorinkjet_pla",
|
||||
"xyzprinting_flexible",
|
||||
"xyzprinting_metallic_pla",
|
||||
"xyzprinting_nylon",
|
||||
"xyzprinting_petg",
|
||||
"xyzprinting_pla",
|
||||
"xyzprinting_tough_pla",
|
||||
"xyzprinting_tpu",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla"
|
||||
],
|
||||
"platform_offset": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"infill_pattern": { "value": "'lines' if infill_sparse_density > 45 else 'grid'" },
|
||||
"machine_depth": { "default_value": 120 },
|
||||
"machine_end_gcode": { "default_value": ";(**** end.gcode for tina2****)\nM203 Z15\nM104 S0\nM107\nG92 E0 (Reset after prime)\nG0 E-1 F300\nG28 Z F300\nG28 X0 Y0\nG1 Y90 F1000" },
|
||||
"machine_heated_bed": { "default_value": false },
|
||||
"machine_height": { "default_value": 100 },
|
||||
"machine_name": { "default_value": "ENTINA TINA2" },
|
||||
"machine_start_gcode": { "default_value": ";MachineType:{machine_name}\n;FilamentType:{material_type}\n;InfillDensity:{infill_sparse_density}\n;Extruder0Temperature:{material_print_temperature}\n\n;(**** start.gcode for tina2****)\nM203 Z15\nM104 S150\nG28 Z\nG28 X Y; Home extruder\nG1 X55 Y55 F1000\nG29\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM109 S{material_print_temperature_layer_0}\nG92 E0 ; Reset extruder position\nG1 X90 Y6 Z0.27 F2000\nG1 X20 Y6 Z0.27 E15 F1000\nG92 E0 ; Reset extruder position\nM203 Z5" },
|
||||
"machine_width": { "default_value": 100 },
|
||||
"raft_base_thickness": { "value": 0.35 },
|
||||
"speed_infill": { "value": 40.0 },
|
||||
"speed_print": { "value": 40.0 },
|
||||
"speed_print_layer_0": { "value": 22.0 },
|
||||
"speed_roofing": { "value": 25.0 },
|
||||
"speed_support_bottom": { "value": 30.0 },
|
||||
"speed_support_infill": { "value": 45.0 },
|
||||
"speed_support_roof": { "value": 30.0 },
|
||||
"speed_topbottom": { "value": 30.0 },
|
||||
"speed_travel": { "value": 65.0 },
|
||||
"speed_travel_layer_0": { "value": 60 },
|
||||
"speed_wall": { "value": 25.0 },
|
||||
"speed_wall_0": { "value": 20.0 },
|
||||
"speed_wall_x": { "value": 25.0 }
|
||||
}
|
||||
}
|
201
resources/definitions/entina_tina2s.def.json
Normal file
201
resources/definitions/entina_tina2s.def.json
Normal file
@ -0,0 +1,201 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "ENTINA TINA2S",
|
||||
"inherits": "weedo_base",
|
||||
"metadata":
|
||||
{
|
||||
"visible": true,
|
||||
"author": "ENTINA",
|
||||
"manufacturer": "ENTINA",
|
||||
"file_formats": "text/x-gcode",
|
||||
"exclude_materials": [
|
||||
"3D-Fuel_PLA_PRO_Black",
|
||||
"3D-Fuel_PLA_SnapSupport",
|
||||
"bestfilament_abs_skyblue",
|
||||
"bestfilament_petg_orange",
|
||||
"bestfilament_pla_green",
|
||||
"leapfrog_abs_natural",
|
||||
"leapfrog_epla_natural",
|
||||
"leapfrog_pva_natural",
|
||||
"generic_abs_175",
|
||||
"generic_asa_175",
|
||||
"generic_cpe_175",
|
||||
"generic_nylon_175",
|
||||
"generic_pc_175",
|
||||
"generic_petg_175",
|
||||
"generic_pva_175",
|
||||
"goofoo_abs",
|
||||
"goofoo_asa",
|
||||
"goofoo_bronze_pla",
|
||||
"goofoo_emarble_pla",
|
||||
"goofoo_esilk_pla",
|
||||
"goofoo_hips",
|
||||
"goofoo_pa_cf",
|
||||
"goofoo_pa",
|
||||
"goofoo_pc",
|
||||
"goofoo_peek",
|
||||
"goofoo_petg",
|
||||
"goofoo_pla",
|
||||
"goofoo_pva",
|
||||
"goofoo_tpe_83a",
|
||||
"goofoo_tpu_87a",
|
||||
"goofoo_tpu_95a",
|
||||
"goofoo_wood_pla",
|
||||
"emotiontech_abs",
|
||||
"emotiontech_absx",
|
||||
"emotiontech_acetate",
|
||||
"emotiontech_asax",
|
||||
"emotiontech_bvoh",
|
||||
"emotiontech_copa",
|
||||
"emotiontech_hips",
|
||||
"emotiontech_nylon_1030",
|
||||
"emotiontech_nylon_1030cf",
|
||||
"emotiontech_nylon_1070",
|
||||
"emotiontech_pc",
|
||||
"emotiontech_pekk",
|
||||
"emotiontech_petg",
|
||||
"emotiontech_pla",
|
||||
"emotiontech_pla_hr_870",
|
||||
"emotiontech_pva-m",
|
||||
"emotiontech_pva-s",
|
||||
"emotiontech_tpu98a",
|
||||
"eryone_petg",
|
||||
"eryone_pla_glow",
|
||||
"eryone_pla_matte",
|
||||
"eryone_pla_wood",
|
||||
"eryone_pla",
|
||||
"eryone_tpu",
|
||||
"eSUN_PETG_Black",
|
||||
"eSUN_PETG_Grey",
|
||||
"eSUN_PETG_Purple",
|
||||
"eSUN_PLA_PRO_Black",
|
||||
"eSUN_PLA_PRO_Grey",
|
||||
"eSUN_PLA_PRO_Purple",
|
||||
"eSUN_PLA_PRO_White",
|
||||
"Extrudr_GreenTECPro_Anthracite_175",
|
||||
"Extrudr_GreenTECPro_Black_175",
|
||||
"Extrudr_GreenTECPro_Blue_175",
|
||||
"Extrudr_GreenTECPro_Nature_175",
|
||||
"Extrudr_GreenTECPro_Red_175",
|
||||
"Extrudr_GreenTECPro_Silver_175",
|
||||
"Extrudr_GreenTECPro_White_175",
|
||||
"verbatim_bvoh_175",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"chromatik_pla",
|
||||
"dsm_arnitel2045_175",
|
||||
"dsm_novamid1070_175",
|
||||
"fabtotum_abs",
|
||||
"fabtotum_nylon",
|
||||
"fabtotum_pla",
|
||||
"fabtotum_tpu",
|
||||
"fdplast_abs_tomato",
|
||||
"fdplast_petg_gray",
|
||||
"fdplast_pla_olive",
|
||||
"fiberlogy_hd_pla",
|
||||
"filo3d_pla",
|
||||
"filo3d_pla_green",
|
||||
"filo3d_pla_red",
|
||||
"imade3d_petg_green",
|
||||
"imade3d_petg_pink",
|
||||
"imade3d_pla_green",
|
||||
"imade3d_pla_pink",
|
||||
"imade3d_petg_175",
|
||||
"imade3d_pla_175",
|
||||
"innofill_innoflex60_175",
|
||||
"layer_one_black_pla",
|
||||
"layer_one_dark_gray_pla",
|
||||
"layer_one_white_pla",
|
||||
"octofiber_pla",
|
||||
"polyflex_pla",
|
||||
"polymax_pla",
|
||||
"polyplus_pla",
|
||||
"polywood_pla",
|
||||
"redd_abs",
|
||||
"redd_asa",
|
||||
"redd_hips",
|
||||
"redd_nylon",
|
||||
"redd_petg",
|
||||
"redd_pla",
|
||||
"redd_tpe",
|
||||
"tizyx_abs",
|
||||
"tizyx_flex",
|
||||
"tizyx_petg",
|
||||
"tizyx_pla_bois",
|
||||
"tizyx_pla",
|
||||
"tizyx_pva",
|
||||
"Vertex_Delta_ABS",
|
||||
"Vertex_Delta_PET",
|
||||
"Vertex_Delta_PLA_Glitter",
|
||||
"Vertex_Delta_PLA_Mat",
|
||||
"Vertex_Delta_PLA_Satin",
|
||||
"Vertex_Delta_PLA_Wood",
|
||||
"Vertex_Delta_PLA",
|
||||
"Vertex_Delta_TPU",
|
||||
"volumic_abs_ultra",
|
||||
"volumic_arma_ultra",
|
||||
"volumic_asa_ultra",
|
||||
"volumic_br80_ultra",
|
||||
"volumic_bumper_ultra",
|
||||
"volumic_cu80_ultra",
|
||||
"volumic_flex93_ultra",
|
||||
"volumic_medical_ultra",
|
||||
"volumic_nylon_ultra",
|
||||
"volumic_pekk_carbone",
|
||||
"volumic_petg_ultra",
|
||||
"volumic_petgcarbone_ultra",
|
||||
"volumic_pla_ultra",
|
||||
"volumic_pp_ultra",
|
||||
"volumic_strong_ultra",
|
||||
"volumic_support_ultra",
|
||||
"xyzprinting_abs",
|
||||
"xyzprinting_antibact_pla",
|
||||
"xyzprinting_carbon_fiber",
|
||||
"xyzprinting_colorinkjet_pla",
|
||||
"xyzprinting_flexible",
|
||||
"xyzprinting_metallic_pla",
|
||||
"xyzprinting_nylon",
|
||||
"xyzprinting_petg",
|
||||
"xyzprinting_pla",
|
||||
"xyzprinting_tough_pla",
|
||||
"xyzprinting_tpu",
|
||||
"zyyx_pro_flex",
|
||||
"zyyx_pro_pla"
|
||||
],
|
||||
"platform_offset": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"machine_depth": { "default_value": 110 },
|
||||
"machine_end_gcode": { "default_value": ";(**** end.gcode for tina2****)\nM203 Z15\nM104 S0\nM107\nG92 E0 (Reset after prime)\nG0 E-1 F300\nG28 Z F300\nG28 X0 Y0\nG1 Y90 F1000" },
|
||||
"machine_height": { "default_value": 100 },
|
||||
"machine_name": { "default_value": "ENTINA TINA2S" },
|
||||
"machine_start_gcode": { "default_value": ";MachineType:{machine_name}\n;FilamentType:{material_type}\n;InfillDensity:{infill_sparse_density}\n;Extruder0Temperature:{material_print_temperature}\n;BedTemperature:{material_bed_temperature}\n\n;(**** start.gcode for tina2****)\nM203 Z15\nM104 S150\nG28 Z\nG28 X Y; Home extruder\nG1 X55 Y55 F1000\nG29\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM109 S{material_print_temperature_layer_0}\nG92 E0 ; Reset extruder position\nG1 X90 Y6 Z0.27 F2000\nG1 X20 Y6 Z0.27 E15 F1000\nG92 E0 ; Reset extruder position\nM203 Z5" },
|
||||
"machine_width": { "default_value": 100 },
|
||||
"material_bed_temperature":
|
||||
{
|
||||
"maximum_value": "65",
|
||||
"maximum_value_warning": "60"
|
||||
},
|
||||
"raft_base_thickness": { "value": 0.35 },
|
||||
"speed_infill": { "value": 40.0 },
|
||||
"speed_print": { "value": 40.0 },
|
||||
"speed_print_layer_0": { "value": 22.0 },
|
||||
"speed_roofing": { "value": 25.0 },
|
||||
"speed_support_bottom": { "value": 30.0 },
|
||||
"speed_support_infill": { "value": 45.0 },
|
||||
"speed_support_roof": { "value": 30.0 },
|
||||
"speed_topbottom": { "value": 30.0 },
|
||||
"speed_travel": { "value": 65.0 },
|
||||
"speed_travel_layer_0": { "value": 60 },
|
||||
"speed_wall": { "value": 25.0 },
|
||||
"speed_wall_0": { "value": 20.0 },
|
||||
"speed_wall_x": { "value": 25.0 }
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user