mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-21 12:15:21 +00:00
Compare commits
11 Commits
fix/remove
...
v2.3.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e63fce706 | ||
|
|
380f4b4a18 | ||
|
|
240cf9ab5d | ||
|
|
05cb8b4d89 | ||
|
|
897a3e915f | ||
|
|
586e96479a | ||
|
|
0879b2079b | ||
|
|
c4801250ea | ||
|
|
f0386d981f | ||
|
|
cd5c8f2ad0 | ||
|
|
2d0a0568e7 |
2
.github/workflows/build_all.yml
vendored
2
.github/workflows/build_all.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
- os: orca-macos-arm64
|
||||
- os: macos-14
|
||||
arch: arm64
|
||||
# Don't run scheduled builds on forks:
|
||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
|
||||
2
.github/workflows/build_check_cache.yml
vendored
2
.github/workflows/build_check_cache.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: set outputs
|
||||
id: set_outputs
|
||||
env:
|
||||
dep-folder-name: ${{ inputs.os != 'orca-macos-arm64' && '/OrcaSlicer_dep' || '' }}
|
||||
dep-folder-name: ${{ inputs.os != 'macos-14' && '/OrcaSlicer_dep' || '' }}
|
||||
output-cmd: ${{ inputs.os == 'windows-latest' && '$env:GITHUB_OUTPUT' || '"$GITHUB_OUTPUT"'}}
|
||||
run: |
|
||||
echo cache-key=${{ inputs.os }}-cache-orcaslicer_deps-build-${{ hashFiles('deps/**') }} >> ${{ env.output-cmd }}
|
||||
|
||||
14
.github/workflows/build_deps.yml
vendored
14
.github/workflows/build_deps.yml
vendored
@@ -74,18 +74,18 @@ jobs:
|
||||
cd ${{ github.workspace }}/deps/build
|
||||
|
||||
- name: Build on Mac ${{ inputs.arch }}
|
||||
if: inputs.os == 'orca-macos-arm64'
|
||||
if: inputs.os == 'macos-14'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
# brew install automake texinfo libtool
|
||||
# brew list
|
||||
# brew uninstall --ignore-dependencies zstd
|
||||
./build_release_macos.sh -dx -a universal -t 10.15
|
||||
brew install automake texinfo libtool
|
||||
brew list
|
||||
brew uninstall --ignore-dependencies zstd
|
||||
./build_release_macos.sh -dx -a universal -t 10.15 -1
|
||||
for arch in arm64 x86_64; do
|
||||
(cd "${{ github.workspace }}/deps/build/${arch}" && \
|
||||
find . -mindepth 1 -maxdepth 1 ! -name 'OrcaSlicer_dep' -exec rm -rf {} +)
|
||||
done
|
||||
# brew install zstd
|
||||
brew install zstd
|
||||
|
||||
|
||||
- name: Apt-Install Dependencies
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
|
||||
# Upload Artifacts
|
||||
# - name: Upload Mac ${{ inputs.arch }} artifacts
|
||||
# if: inputs.os == 'orca-macos-arm64'
|
||||
# if: inputs.os == 'macos-14'
|
||||
# uses: actions/upload-artifact@v6
|
||||
# with:
|
||||
# name: OrcaSlicer_dep_mac_${{ env.date }}
|
||||
|
||||
36
.github/workflows/build_orca.yml
vendored
36
.github/workflows/build_orca.yml
vendored
@@ -86,29 +86,29 @@ jobs:
|
||||
|
||||
# Mac
|
||||
- name: Install tools mac
|
||||
if: inputs.os == 'orca-macos-arm64'
|
||||
if: inputs.os == 'macos-14'
|
||||
run: |
|
||||
# brew install libtool
|
||||
# brew list
|
||||
brew install libtool
|
||||
brew list
|
||||
mkdir -p ${{ github.workspace }}/deps/build
|
||||
|
||||
# - name: Free disk space
|
||||
# if: inputs.os == 'orca-macos-arm64'
|
||||
# run: |
|
||||
# df -hI /dev/disk3s1s1
|
||||
# sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
|
||||
# sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
|
||||
# df -hI /dev/disk3s1s1
|
||||
- name: Free disk space
|
||||
if: inputs.os == 'macos-14'
|
||||
run: |
|
||||
df -hI /dev/disk3s1s1
|
||||
sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
|
||||
sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
|
||||
df -hI /dev/disk3s1s1
|
||||
|
||||
- name: Build slicer mac
|
||||
if: inputs.os == 'orca-macos-arm64'
|
||||
if: inputs.os == 'macos-14'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
./build_release_macos.sh -s -n -x -a universal -t 10.15
|
||||
./build_release_macos.sh -s -n -x -a universal -t 10.15 -1
|
||||
|
||||
# Thanks to RaySajuuk, it's working now
|
||||
- name: Sign app and notary
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && inputs.os == 'orca-macos-arm64'
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && inputs.os == 'macos-14'
|
||||
working-directory: ${{ github.workspace }}
|
||||
env:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
@@ -162,7 +162,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Create DMG without notary
|
||||
if: github.ref != 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
|
||||
if: github.ref != 'refs/heads/main' && inputs.os == 'macos-14'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
|
||||
@@ -181,14 +181,14 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload artifacts mac
|
||||
if: inputs.os == 'orca-macos-arm64'
|
||||
if: inputs.os == 'macos-14'
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: OrcaSlicer_Mac_universal_${{ env.ver }}
|
||||
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
|
||||
- name: Upload OrcaSlicer_profile_validator DMG mac
|
||||
if: inputs.os == 'orca-macos-arm64'
|
||||
if: inputs.os == 'macos-14'
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: OrcaSlicer_profile_validator_Mac_universal_DMG_${{ env.ver }}
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Deploy Mac release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'macos-14'
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
@@ -207,7 +207,7 @@ jobs:
|
||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||
|
||||
- name: Deploy Mac OrcaSlicer_profile_validator DMG release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'orca-macos-arm64'
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && inputs.os == 'macos-14'
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
|
||||
2
deps/GLEW/GLEW.cmake
vendored
2
deps/GLEW/GLEW.cmake
vendored
@@ -5,6 +5,8 @@ find_package(OpenGL QUIET REQUIRED)
|
||||
orcaslicer_add_cmake_project(
|
||||
GLEW
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/glew
|
||||
CMAKE_ARGS
|
||||
-DGLEW_USE_EGL=OFF
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
|
||||
12
deps/GLEW/glew/CMakeLists.txt
vendored
12
deps/GLEW/glew/CMakeLists.txt
vendored
@@ -3,9 +3,17 @@ project(GLEW)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
if(OpenGL_EGL_FOUND)
|
||||
message(STATUS "building GLEW for EGL (hope that wxWidgets agrees, otherwise you won't have any output!)")
|
||||
# Allow parent project to control EGL usage.
|
||||
# Default to OFF since OrcaSlicer forces GDK_BACKEND=x11 (using GLX contexts).
|
||||
# GLEW must use glXGetProcAddressARB (GLX) to match wxWidgets GL canvas.
|
||||
# Using EGL function loading with GLX contexts causes rendering failures.
|
||||
option(GLEW_USE_EGL "Use EGL instead of GLX for OpenGL function loading" OFF)
|
||||
|
||||
if(GLEW_USE_EGL)
|
||||
message(STATUS "Building GLEW with EGL support")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGLEW_EGL")
|
||||
else()
|
||||
message(STATUS "Building GLEW with GLX support")
|
||||
endif()
|
||||
|
||||
add_library(GLEW src/glew.c)
|
||||
|
||||
1
deps/wxWidgets/wxWidgets.cmake
vendored
1
deps/wxWidgets/wxWidgets.cmake
vendored
@@ -51,6 +51,7 @@ orcaslicer_add_cmake_project(
|
||||
-DwxUSE_UNICODE=ON
|
||||
-DwxUSE_PRIVATE_FONTS=ON
|
||||
-DwxUSE_OPENGL=ON
|
||||
-DwxUSE_GLCANVAS_EGL=OFF
|
||||
-DwxUSE_WEBREQUEST=ON
|
||||
-DwxUSE_WEBVIEW=ON
|
||||
${_wx_edge}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Afinia",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Afinia configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anker",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Anker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Anycubic",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Anycubic configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Artillery",
|
||||
"version": "02.03.02.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Artillery configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Bambulab",
|
||||
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
|
||||
"version": "02.00.00.56",
|
||||
"version": "02.01.00.00",
|
||||
"force_update": "0",
|
||||
"description": "the initial version of BBL configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -102,6 +102,21 @@
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15"
|
||||
],
|
||||
"filament_tower_interface_pre_extrusion_dist": [
|
||||
"10"
|
||||
],
|
||||
"filament_tower_interface_pre_extrusion_length": [
|
||||
"0"
|
||||
],
|
||||
"filament_tower_ironing_area": [
|
||||
"4"
|
||||
],
|
||||
"filament_tower_interface_purge_volume": [
|
||||
"20"
|
||||
],
|
||||
"filament_tower_interface_print_temp": [
|
||||
"-1"
|
||||
],
|
||||
"filament_printable": [
|
||||
"3"
|
||||
],
|
||||
@@ -277,4 +292,4 @@
|
||||
"volumetric_speed_coefficients":[
|
||||
"0 0 0 0 0 0"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
"prime_tower_lift_height": "-1",
|
||||
"prime_tower_max_speed": "90",
|
||||
"prime_tower_flat_ironing": "0",
|
||||
"enable_tower_interface_features": "0",
|
||||
"enable_tower_interface_cooldown_during_tower": "0",
|
||||
"raft_layers": "0",
|
||||
"reduce_crossing_wall": "0",
|
||||
"reduce_infill_retraction": "1",
|
||||
@@ -170,4 +172,4 @@
|
||||
"xy_contour_compensation": "0",
|
||||
"xy_hole_compensation": "0",
|
||||
"z_direction_outwall_speed_continuous": "0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "BIQU",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "BIQU configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Blocks",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Blocks configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "CONSTRUCT3D",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Construct3D configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Chuanying",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Chuanying configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Co Print",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "CoPrint configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "CoLiDo",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "CoLiDo configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Comgrow",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Comgrow configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Creality",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Creality configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Cubicon",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Cubicon configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Custom Printer",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "My configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "DeltaMaker",
|
||||
"url": "",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "DeltaMaker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Dremel",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Dremel configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Elegoo",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Elegoo configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Eryone",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Eryone configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "FLSun",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "FLSun configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Flashforge",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Flashforge configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "FlyingBear",
|
||||
"version": "02.03.01.00",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "FlyingBear configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Folgertech",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Folgertech configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Geeetech",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Geeetech configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Ginger Additive",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "Ginger configuration",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "InfiMech",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "InfiMech configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Kingroon",
|
||||
"url": "https://kingroon.com/",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "Kingroon configuration files",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "LONGER",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "LONGER configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Lulzbot",
|
||||
"url": "https://ohai.lulzbot.com/group/taz-6/",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Lulzbot configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "M3D",
|
||||
"version": "1.0.0",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Configuration for M3D printers",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "MagicMaker",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "MagicMaker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Mellow",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Mellow Printer Profiles",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "OpenEYE",
|
||||
"url": "http://www.openeye.tech",
|
||||
"version": "01.00.00.03",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "OpenEYE Printers Configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Orca Arena Printer",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Orca Arena configuration files",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "OrcaFilamentLibrary",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Orca Filament Library",
|
||||
"filament_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Peopoly",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Peopoly configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Phrozen",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Phrozen configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Positron 3D",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Positron 3D Printer Profile",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Prusa",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Prusa configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Qidi",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Qidi configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "RH3D",
|
||||
"version": "00.06.10.25",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "RH3D - printer profiles",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Raise3D",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Raise3D configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "RatRig",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "RatRig configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "RolohaunDesign",
|
||||
"version": "02.03.02.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "RolohaunDesign Printer Profiles",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "SecKit",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "SecKit configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Snapmaker",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Snapmaker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Sovol",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Sovol configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Tiertime",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Tiertime configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Tronxy",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Tronxy configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TwoTrees",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "TwoTrees configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "UltiMaker",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "UltiMaker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Vivedino",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Vivedino configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Volumic",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "VOLUMIC configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Voron",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Voron configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Voxelab",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Voxelab configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Vzbot",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Vzbot configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "WEMAKE3D",
|
||||
"version": "02.03.01.20",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "WEMAKE3D configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Wanhao France",
|
||||
"version": "02.03.01.11",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Wanhao France D12 configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Wanhao",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Wanhao configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "WonderMaker",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "WonderMaker configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Z-Bolt",
|
||||
"url": "",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "0",
|
||||
"description": "Z-Bolt configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "innovatiQ",
|
||||
"version": "02.03.01.10",
|
||||
"version": "02.03.02.40",
|
||||
"force_update": "1",
|
||||
"description": "innovatiQ configuration",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -880,7 +880,23 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(old_retract_length_toolchange));
|
||||
config.set_key_value("new_retract_length_toolchange", new ConfigOptionFloat(new_retract_length_toolchange));
|
||||
config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp));
|
||||
int interface_temp = full_config.filament_tower_interface_print_temp.get_at(new_filament_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = full_config.nozzle_temperature_range_high.get_at(new_filament_id);
|
||||
if (full_config.enable_tower_interface_features && tcr.is_contact)
|
||||
new_filament_temp = interface_temp;
|
||||
config.set_key_value("new_filament_temp", new ConfigOptionInt(new_filament_temp));
|
||||
if (full_config.enable_tower_interface_features && tcr.is_contact) {
|
||||
auto temps = full_config.nozzle_temperature.values;
|
||||
if (new_filament_id >= 0 && new_filament_id < (int)temps.size())
|
||||
temps[new_filament_id] = interface_temp;
|
||||
config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = full_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id >= 0 && new_filament_id < (int)first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = interface_temp;
|
||||
config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
config.set_key_value("x_after_toolchange", new ConfigOptionFloat(tool_change_start_pos(0)));
|
||||
config.set_key_value("y_after_toolchange", new ConfigOptionFloat(tool_change_start_pos(1)));
|
||||
config.set_key_value("z_after_toolchange", new ConfigOptionFloat(nozzle_pos(2)));
|
||||
@@ -910,6 +926,9 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
config.set_key_value("flush_length", new ConfigOptionFloat(purge_length));
|
||||
config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
|
||||
config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
|
||||
config.set_key_value("is_prime_tower_interface", new ConfigOptionBool(tcr.is_contact));
|
||||
config.set_key_value("filament_tower_interface_purge_volume", new ConfigOptionFloat(full_config.filament_tower_interface_purge_volume.get_at(new_filament_id)));
|
||||
config.set_key_value("filament_tower_interface_print_temp", new ConfigOptionInt(interface_temp));
|
||||
|
||||
int flush_count = std::min(g_max_flush_count, (int) std::round(purge_volume / g_purge_volume_one_time));
|
||||
float flush_unit = purge_length / flush_count;
|
||||
@@ -1144,10 +1163,18 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
std::string toolchange_gcode_str;
|
||||
std::string deretraction_str;
|
||||
int toolchange_temp_override = -1;
|
||||
int interface_temp = -1;
|
||||
if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) {
|
||||
if (is_ramming)
|
||||
gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().enable_tower_interface_features && tcr.is_contact) {
|
||||
interface_temp = gcodegen.config().filament_tower_interface_print_temp.get_at(new_extruder_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = gcodegen.config().nozzle_temperature_range_high.get_at(new_extruder_id);
|
||||
toolchange_temp_override = interface_temp;
|
||||
}
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().enable_prime_tower) {
|
||||
deretraction_str += gcodegen.writer().travel_to_z(z, "Force restore layer Z", true);
|
||||
Vec3d position{gcodegen.writer().get_position()};
|
||||
@@ -1157,6 +1184,144 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
}
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0) {
|
||||
int base_temp = gcodegen.on_first_layer() ? gcodegen.config().nozzle_temperature_initial_layer.get_at(new_extruder_id)
|
||||
: gcodegen.config().nozzle_temperature.get_at(new_extruder_id);
|
||||
if (std::abs(tcr.print_z) < EPSILON)
|
||||
base_temp = gcodegen.config().nozzle_temperature_initial_layer.get_at(new_extruder_id);
|
||||
const std::string t_token = " T" + std::to_string(new_extruder_id);
|
||||
std::string out;
|
||||
out.reserve(toolchange_gcode_str.size());
|
||||
size_t pos = 0;
|
||||
while (pos < toolchange_gcode_str.size()) {
|
||||
size_t line_end = toolchange_gcode_str.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = toolchange_gcode_str.size();
|
||||
std::string line = toolchange_gcode_str.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
bool skip_line = false;
|
||||
if (boost::starts_with(trimmed, "M109")) {
|
||||
bool matches_extruder = trimmed.find(t_token) != std::string::npos;
|
||||
if (!matches_extruder) {
|
||||
size_t t_pos = trimmed.find('T');
|
||||
if (t_pos != std::string::npos) {
|
||||
size_t t_end = trimmed.find_first_not_of("0123456789", t_pos + 1);
|
||||
const std::string t_val = trimmed.substr(t_pos + 1, t_end == std::string::npos ? std::string::npos : t_end - (t_pos + 1));
|
||||
if (!t_val.empty()) {
|
||||
try {
|
||||
matches_extruder = std::stoi(t_val) == new_extruder_id;
|
||||
} catch (...) {
|
||||
matches_extruder = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches_extruder) {
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
const std::string s_val = trimmed.substr(s_pos + 1, s_end == std::string::npos ? std::string::npos : s_end - (s_pos + 1));
|
||||
if (!s_val.empty()) {
|
||||
try {
|
||||
skip_line = std::stoi(s_val) == base_temp;
|
||||
} catch (...) {
|
||||
skip_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip_line) {
|
||||
out.append(line);
|
||||
if (line_end < toolchange_gcode_str.size())
|
||||
out.push_back('\n');
|
||||
}
|
||||
pos = line_end + 1;
|
||||
}
|
||||
toolchange_gcode_str.swap(out);
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0) {
|
||||
const std::string preheat_token = "preheat T" + std::to_string(new_extruder_id);
|
||||
const int preheat_temp = interface_temp > 0 ? interface_temp : toolchange_temp_override;
|
||||
std::string out;
|
||||
out.reserve(tcr_rotated_gcode.size());
|
||||
size_t pos = 0;
|
||||
while (pos < tcr_rotated_gcode.size()) {
|
||||
size_t line_end = tcr_rotated_gcode.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = tcr_rotated_gcode.size();
|
||||
std::string line = tcr_rotated_gcode.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
const bool is_preheat_line = (trimmed.find(preheat_token) != std::string::npos);
|
||||
if (is_preheat_line) {
|
||||
// Preserve early-preheat timing while forcing interface temp for contact toolchanges.
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
trimmed.replace(s_pos + 1,
|
||||
(s_end == std::string::npos ? trimmed.size() : s_end) - (s_pos + 1),
|
||||
std::to_string(preheat_temp));
|
||||
// Reapply left indentation from the original line.
|
||||
size_t line_prefix = line.find_first_not_of(" \t");
|
||||
if (line_prefix != std::string::npos)
|
||||
line = line.substr(0, line_prefix) + trimmed;
|
||||
else
|
||||
line = trimmed;
|
||||
}
|
||||
}
|
||||
out.append(line);
|
||||
if (line_end < tcr_rotated_gcode.size())
|
||||
out.push_back('\n');
|
||||
pos = line_end + 1;
|
||||
}
|
||||
tcr_rotated_gcode.swap(out);
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0 && interface_temp > 0) {
|
||||
const std::string t_token = " T" + std::to_string(new_extruder_id);
|
||||
std::string out;
|
||||
out.reserve(tcr_rotated_gcode.size());
|
||||
size_t pos = 0;
|
||||
while (pos < tcr_rotated_gcode.size()) {
|
||||
size_t line_end = tcr_rotated_gcode.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = tcr_rotated_gcode.size();
|
||||
std::string line = tcr_rotated_gcode.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
bool skip_line = false;
|
||||
if (boost::starts_with(trimmed, "M109")) {
|
||||
bool matches_extruder = true;
|
||||
if (trimmed.find('T') != std::string::npos)
|
||||
matches_extruder = trimmed.find(t_token) != std::string::npos;
|
||||
if (matches_extruder) {
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
const std::string s_val = trimmed.substr(s_pos + 1, s_end == std::string::npos ? std::string::npos : s_end - (s_pos + 1));
|
||||
if (!s_val.empty()) {
|
||||
try {
|
||||
skip_line = std::stoi(s_val) == interface_temp;
|
||||
} catch (...) {
|
||||
skip_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip_line) {
|
||||
out.append(line);
|
||||
if (line_end < tcr_rotated_gcode.size())
|
||||
out.push_back('\n');
|
||||
}
|
||||
pos = line_end + 1;
|
||||
}
|
||||
tcr_rotated_gcode.swap(out);
|
||||
}
|
||||
|
||||
// Insert the toolchange and deretraction gcode into the generated gcode.
|
||||
|
||||
DynamicConfig config;
|
||||
@@ -7192,7 +7357,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object)
|
||||
std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object, int toolchange_temp_override)
|
||||
{
|
||||
int new_extruder_id = get_extruder_id(new_filament_id);
|
||||
if (!m_writer.need_toolchange(new_filament_id))
|
||||
@@ -7280,6 +7445,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
// BBS: if print_z == 0 use first layer temperature
|
||||
if (abs(print_z) < EPSILON)
|
||||
new_filament_temp = m_config.nozzle_temperature_initial_layer.get_at(new_filament_id);
|
||||
if (toolchange_temp_override > 0)
|
||||
new_filament_temp = toolchange_temp_override;
|
||||
|
||||
Vec3d nozzle_pos = m_writer.get_position();
|
||||
float old_retract_length, old_retract_length_toolchange, wipe_volume;
|
||||
@@ -7372,6 +7539,27 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
dyn_config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
|
||||
dyn_config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(false));
|
||||
dyn_config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
|
||||
dyn_config.set_key_value("is_prime_tower_interface", new ConfigOptionBool(false));
|
||||
dyn_config.set_key_value("filament_tower_interface_purge_volume", new ConfigOptionFloat(m_config.filament_tower_interface_purge_volume.get_at(new_filament_id)));
|
||||
{
|
||||
int interface_temp = m_config.filament_tower_interface_print_temp.get_at(new_filament_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = m_config.nozzle_temperature_range_high.get_at(new_filament_id);
|
||||
dyn_config.set_key_value("filament_tower_interface_print_temp", new ConfigOptionInt(interface_temp));
|
||||
}
|
||||
if (toolchange_temp_override > 0) {
|
||||
auto temps = m_config.nozzle_temperature.values;
|
||||
if (new_filament_id < temps.size())
|
||||
temps[new_filament_id] = toolchange_temp_override;
|
||||
dyn_config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
dyn_config.set_key_value("nozzle_temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = m_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id < first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = toolchange_temp_override;
|
||||
dyn_config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
dyn_config.set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
|
||||
auto flush_v_speed = m_print->config().filament_flush_volumetric_speed.values;
|
||||
auto flush_temps =m_print->config().filament_flush_temp.values;
|
||||
@@ -7472,6 +7660,19 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(new_filament_id)));
|
||||
if (toolchange_temp_override > 0) {
|
||||
auto temps = m_config.nozzle_temperature.values;
|
||||
if (new_filament_id < temps.size())
|
||||
temps[new_filament_id] = toolchange_temp_override;
|
||||
config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
config.set_key_value("nozzle_temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = m_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id < first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = toolchange_temp_override;
|
||||
config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
config.set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
||||
if (add_change_filament_624) {
|
||||
gcode += "M625\n";
|
||||
|
||||
@@ -249,7 +249,7 @@ public:
|
||||
bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type);
|
||||
std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift, bool apply_instantly = false, ExtrusionRole role = erNone);
|
||||
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false);
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1);
|
||||
bool is_BBL_Printer();
|
||||
bool is_QIDI_Printer();
|
||||
|
||||
|
||||
@@ -760,11 +760,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& line_at(size_t idx) const
|
||||
{
|
||||
return m_lines[idx].line;
|
||||
}
|
||||
|
||||
size_t lines_size() const
|
||||
{
|
||||
return m_lines.size();
|
||||
}
|
||||
|
||||
// Insert the gcode lines required by the command cmd by backtracing into the cache
|
||||
void insert_lines(const Backtrace& backtrace,
|
||||
bool insert_lines(const Backtrace& backtrace,
|
||||
const std::string& cmd,
|
||||
std::function<std::string(unsigned int, const std::vector<float>&)> line_inserter,
|
||||
std::function<std::string(const std::string&)> line_replacer)
|
||||
std::function<std::string(const std::string&)> line_replacer,
|
||||
std::function<bool(size_t)> allow_insert = nullptr,
|
||||
bool force_insert_last = false)
|
||||
{
|
||||
// Orca: find start pos by seaching G28/G29/PRINT_START/START_PRINT commands
|
||||
auto is_start_pos = [](const std::string& curr_cmd) {
|
||||
@@ -775,6 +787,21 @@ public:
|
||||
const float time_step = backtrace.time_step();
|
||||
size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace
|
||||
float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time
|
||||
auto inside_toolchange_block = [this](size_t idx) -> bool {
|
||||
if (m_lines.empty() || idx >= m_lines.size())
|
||||
return false;
|
||||
// Find last START/END marker before or at idx; inside if last marker is START.
|
||||
for (size_t i = idx + 1; i-- > 0;) {
|
||||
const std::string &line = m_lines[i].line;
|
||||
if (line.find("CP TOOLCHANGE START") != std::string::npos)
|
||||
return true;
|
||||
if (line.find("CP TOOLCHANGE END") != std::string::npos)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool inserted = false;
|
||||
for (int i = 0; i < backtrace.steps; ++i) {
|
||||
const float backtrace_time_i = (i + 1) * time_step;
|
||||
const float time_threshold_i = m_times[Normal] - backtrace_time_i;
|
||||
@@ -796,6 +823,23 @@ public:
|
||||
|
||||
// insert the line for the current step
|
||||
if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->times[Normal] != last_time_insertion) {
|
||||
// Avoid inserting inside wipe-tower toolchange blocks.
|
||||
// If the selected point is inside a block, move to the nearest
|
||||
// earlier line outside the block instead of dropping preheat.
|
||||
size_t idx = m_lines.size() - 1 - size_t(std::distance(m_lines.rbegin(), rev_it));
|
||||
if (inside_toolchange_block(idx)) {
|
||||
size_t adjusted_idx = idx;
|
||||
while (adjusted_idx > 0 && inside_toolchange_block(adjusted_idx))
|
||||
--adjusted_idx;
|
||||
if (inside_toolchange_block(adjusted_idx))
|
||||
continue;
|
||||
const size_t adjusted_rev_dist = m_lines.size() - 1 - adjusted_idx;
|
||||
rev_it = m_lines.rbegin() + adjusted_rev_dist;
|
||||
idx = adjusted_idx;
|
||||
}
|
||||
if (allow_insert && !allow_insert(idx)) {
|
||||
continue;
|
||||
}
|
||||
last_time_insertion = rev_it->times[Normal];
|
||||
std::vector<float> time_diffs;
|
||||
time_diffs.push_back(m_times[Normal] - last_time_insertion);
|
||||
@@ -814,8 +858,39 @@ public:
|
||||
}
|
||||
|
||||
++m_added_lines_counter;
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inserted && force_insert_last) {
|
||||
for (size_t idx = 0; idx < m_lines.size(); ++idx) {
|
||||
if (inside_toolchange_block(idx))
|
||||
continue;
|
||||
if (allow_insert && !allow_insert(idx))
|
||||
continue;
|
||||
|
||||
const LineData &data = m_lines[idx];
|
||||
std::vector<float> time_diffs;
|
||||
time_diffs.push_back(m_times[Normal] - data.times[Normal]);
|
||||
if (!m_machines[Stealth].g1_times_cache.empty())
|
||||
time_diffs.push_back(m_times[Stealth] - data.times[Stealth]);
|
||||
const std::string out_line = line_inserter(1, time_diffs);
|
||||
const size_t rev_it_dist = m_lines.size() - idx;
|
||||
m_lines.insert(m_lines.begin() + idx, {out_line, data.times});
|
||||
#ifndef NDEBUG
|
||||
m_statistics.add_line(out_line.length());
|
||||
#endif // NDEBUG
|
||||
m_size += out_line.length();
|
||||
for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) {
|
||||
++map_it->second;
|
||||
}
|
||||
++m_added_lines_counter;
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
// write to file:
|
||||
@@ -1254,12 +1329,169 @@ void GCodeProcessor::run_post_process()
|
||||
if (m_print != nullptr)
|
||||
m_print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning);
|
||||
}
|
||||
int override_temp = -1;
|
||||
{
|
||||
const size_t line_count = export_line.lines_size();
|
||||
if (line_count > 0) {
|
||||
size_t start_idx = 0;
|
||||
bool in_block = false;
|
||||
for (size_t i = line_count; i-- > 0;) {
|
||||
const std::string &line = export_line.line_at(i);
|
||||
if (line.find("CP TOOLCHANGE END") != std::string::npos)
|
||||
break;
|
||||
if (line.find("CP TOOLCHANGE START") != std::string::npos) {
|
||||
start_idx = i;
|
||||
in_block = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (in_block) {
|
||||
int base_temp = int(m_layer_id != 1 ? m_filament_nozzle_temp[tool_number] :
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
for (size_t i = start_idx; i < line_count; ++i) {
|
||||
const std::string &line = export_line.line_at(i);
|
||||
if (GCodeReader::GCodeLine::cmd_is(line, "M109")) {
|
||||
GCodeReader::GCodeLine gline;
|
||||
GCodeReader reader;
|
||||
reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; });
|
||||
float s_val = 0.f;
|
||||
if (gline.has_value('S', s_val)) {
|
||||
float t_val = -1.f;
|
||||
if (gline.has_value('T', t_val)) {
|
||||
if (int(t_val) != tool_number)
|
||||
continue;
|
||||
}
|
||||
int temp = int(std::round(s_val));
|
||||
if (temp != base_temp)
|
||||
override_temp = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Disallow inserting preheat before the last switch away from this tool.
|
||||
size_t min_insert_idx = 0;
|
||||
{
|
||||
const size_t line_count = export_line.lines_size();
|
||||
if (line_count > 0) {
|
||||
for (size_t i = line_count; i-- > 0;) {
|
||||
const std::string &line = export_line.line_at(i);
|
||||
std::string cmd = GCodeReader::GCodeLine::extract_cmd(line);
|
||||
if (cmd.empty())
|
||||
continue;
|
||||
if (cmd[0] == 'T') {
|
||||
unsigned int id = 0;
|
||||
auto ret = std::from_chars(cmd.data() + 1, cmd.data() + cmd.size(), id);
|
||||
if (ret.ec == std::errc()) {
|
||||
if (static_cast<int>(id) != tool_number) {
|
||||
min_insert_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (cmd == "M1020") {
|
||||
size_t pos = line.find("S");
|
||||
if (pos != std::string::npos) {
|
||||
size_t start = pos + 1;
|
||||
size_t end = line.find_first_not_of("0123456789", start);
|
||||
const std::string val = line.substr(start, end == std::string::npos ? std::string::npos : end - start);
|
||||
if (!val.empty()) {
|
||||
try {
|
||||
if (std::stoi(val) != tool_number) {
|
||||
min_insert_idx = i;
|
||||
break;
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto allow_insert = [&export_line, tool_number, min_insert_idx](size_t idx) -> bool {
|
||||
if (idx <= min_insert_idx)
|
||||
return false;
|
||||
// Do not insert preheat for a tool that is already active at the insertion point.
|
||||
const size_t line_count = export_line.lines_size();
|
||||
if (idx >= line_count)
|
||||
return true;
|
||||
for (size_t i = idx + 1; i-- > 0;) {
|
||||
const std::string &line = export_line.line_at(i);
|
||||
std::string cmd = GCodeReader::GCodeLine::extract_cmd(line);
|
||||
if (cmd.empty())
|
||||
continue;
|
||||
if (cmd[0] == 'T') {
|
||||
unsigned int id = 0;
|
||||
auto ret = std::from_chars(cmd.data() + 1, cmd.data() + cmd.size(), id);
|
||||
if (ret.ec == std::errc()) {
|
||||
return static_cast<int>(id) != tool_number;
|
||||
}
|
||||
} else if (cmd == "M1020") {
|
||||
size_t pos = line.find("S");
|
||||
if (pos != std::string::npos) {
|
||||
size_t start = pos + 1;
|
||||
size_t end = line.find_first_not_of("0123456789", start);
|
||||
const std::string val = line.substr(start, end == std::string::npos ? std::string::npos : end - start);
|
||||
if (!val.empty()) {
|
||||
try {
|
||||
return std::stoi(val) != tool_number;
|
||||
} catch (...) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Skip preheat insertion if this T command doesn't change the active tool.
|
||||
{
|
||||
const size_t line_count = export_line.lines_size();
|
||||
if (line_count > 0) {
|
||||
int last_tool = -1;
|
||||
for (size_t i = line_count; i-- > 0;) {
|
||||
const std::string &line = export_line.line_at(i);
|
||||
std::string cmd = GCodeReader::GCodeLine::extract_cmd(line);
|
||||
if (cmd.empty())
|
||||
continue;
|
||||
if (cmd[0] == 'T') {
|
||||
unsigned int id = 0;
|
||||
auto ret = std::from_chars(cmd.data() + 1, cmd.data() + cmd.size(), id);
|
||||
if (ret.ec == std::errc()) {
|
||||
last_tool = static_cast<int>(id);
|
||||
break;
|
||||
}
|
||||
} else if (cmd == "M1020") {
|
||||
size_t pos = line.find("S");
|
||||
if (pos != std::string::npos) {
|
||||
size_t start = pos + 1;
|
||||
size_t end = line.find_first_not_of("0123456789", start);
|
||||
const std::string val = line.substr(start, end == std::string::npos ? std::string::npos : end - start);
|
||||
if (!val.empty()) {
|
||||
try {
|
||||
last_tool = std::stoi(val);
|
||||
break;
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (last_tool != -1 && last_tool == tool_number)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export_line.insert_lines(
|
||||
backtrace, cmd,
|
||||
// line inserter
|
||||
[tool_number, this](unsigned int id, const std::vector<float>& time_diffs) {
|
||||
const int temperature = int(m_layer_id != 1 ? m_filament_nozzle_temp[tool_number] :
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
[tool_number, override_temp, this](unsigned int id, const std::vector<float>& time_diffs) {
|
||||
const int base_temperature = int(m_layer_id != 1 ? m_filament_nozzle_temp[tool_number] :
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
const int temperature = override_temp > 0 ? override_temp : base_temperature;
|
||||
// Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from
|
||||
// Prusa-Firmware-Buddy here
|
||||
/**
|
||||
@@ -1302,7 +1534,11 @@ void GCodeProcessor::run_post_process()
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
},
|
||||
allow_insert,
|
||||
// If backtracing can't find a valid insertion point (e.g. dense recurring toolchanges),
|
||||
// still force one at the earliest allowed line after the last switch-away point.
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5897,4 +6133,3 @@ int GCodeProcessor::get_extruder_id(bool force_initialize)const
|
||||
}
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
static constexpr float flat_iron_area = 4.f;
|
||||
constexpr float flat_iron_speed = 10.f * 60.f;
|
||||
static const double wipe_tower_wall_infill_overlap = 0.0;
|
||||
static constexpr double WIPE_TOWER_RESOLUTION = 0.1;
|
||||
@@ -1243,7 +1242,8 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const
|
||||
float purge_volume,
|
||||
bool is_contact) const
|
||||
{
|
||||
ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1260,6 +1260,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
result.is_finish_first = is_finish;
|
||||
result.nozzle_change_result = m_nozzle_change_result;
|
||||
result.is_tool_change = is_tool_change;
|
||||
result.is_contact = is_contact;
|
||||
result.tool_change_start_pos = is_tool_change ? result.start_pos : Vec2f(0, 0);
|
||||
|
||||
// BBS
|
||||
@@ -1283,6 +1284,7 @@ WipeTower::ToolChangeResult WipeTower::construct_block_tcr(WipeTowerWriter &writ
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_tool_change = false;
|
||||
result.is_contact = false;
|
||||
result.tool_change_start_pos = Vec2f(0, 0);
|
||||
// BBS
|
||||
result.purge_volume = purge_volume;
|
||||
@@ -1486,7 +1488,9 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
m_used_fillet(config.wipe_tower_fillet_wall.value),
|
||||
m_extra_spacing((float)config.prime_tower_infill_gap.value/100.f),
|
||||
m_tower_framework(config.prime_tower_enable_framework.value),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value)
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
m_flat_ironing = (m_flat_ironing && m_use_gap_wall);
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
@@ -1546,6 +1550,16 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].category = config.filament_adhesiveness_category.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1608,7 +1622,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
return std::vector<ToolChangeResult>();
|
||||
}
|
||||
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length)
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool)
|
||||
{
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -1740,7 +1754,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
}
|
||||
}
|
||||
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, false, tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
if (extrude_perimeter) {
|
||||
@@ -1796,7 +1810,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, false);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id)
|
||||
@@ -2284,6 +2298,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
bool first_layer = is_first_layer();
|
||||
// BBS: speed up perimeter speed to 90mm/s for non-first layer
|
||||
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
|
||||
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
|
||||
@@ -2426,7 +2442,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
@@ -2646,6 +2662,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) {
|
||||
std::string travel_gcode = "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + " Y" +
|
||||
Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F5400" + "\n";
|
||||
@@ -2769,6 +2786,15 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
}
|
||||
}
|
||||
|
||||
bool interface_layer = solid_toolchange && m_enable_tower_interface_features;
|
||||
if (interface_layer && new_tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[new_tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
purge_volume += extra_purge_length * m_filpar[new_tool].filament_area;
|
||||
wipe_length += extra_purge_length;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTowerBlock* block = get_block_by_category(m_filpar[new_tool].category, false);
|
||||
if (!block) {
|
||||
assert(block != nullptr);
|
||||
@@ -2795,7 +2821,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
if (new_tool != (unsigned int) -1) { // This is not the last change.
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, interface_layer, new_tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
@@ -2804,6 +2830,23 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
toolchange_Change(writer, new_tool, m_filpar[new_tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[new_tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[new_tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
bool start_left = (m_cur_layer_id % 4 == 0 || m_cur_layer_id % 4 == 3);
|
||||
float target_x = writer.x() + (start_left ? pre_dist : -pre_dist);
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_is_multi_extruder && is_tpu_filament(new_tool)) {
|
||||
float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width;
|
||||
if (m_layer_info->extra_spacing < m_tpu_fixed_spacing) {
|
||||
@@ -2838,6 +2881,13 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
toolchange_wipe_new(writer, cleaning_box, wipe_length, solid_toolchange);
|
||||
|
||||
if (interface_layer) {
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++m_num_tool_changes;
|
||||
} else
|
||||
@@ -2859,7 +2909,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, interface_layer);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_infill)
|
||||
@@ -3157,7 +3207,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
m_nozzle_change_result.gcode.clear();
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill)
|
||||
@@ -3350,6 +3400,8 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
}
|
||||
float retract_length = m_filpar[m_current_tool].retract_length;
|
||||
float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
const bool do_ironing = m_flat_ironing && (!solid_tool_toolchange || !m_enable_tower_interface_features);
|
||||
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -3393,10 +3445,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
} else
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3408,10 +3460,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
}else
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3837,6 +3889,8 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
|
||||
for (auto layer : m_plan) {
|
||||
reset_block_status();
|
||||
m_cur_layer_id = index++;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
m_current_layer_has_interface = !solid_blocks_id.empty();
|
||||
set_layer(layer.z, layer.height, 0, false, layer.z == m_plan.back().z);
|
||||
|
||||
if (m_layer_info->depth < m_perimeter_width) continue;
|
||||
@@ -4188,7 +4242,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
|
||||
if (!m_no_sparse_layers || toolchanges_on_layer)
|
||||
if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
Polygon WipeTower::generate_rib_polygon(const box_coordinates &wt_box)
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
bool priming;
|
||||
|
||||
bool is_tool_change{false};
|
||||
bool is_contact{false};
|
||||
Vec2f tool_change_start_pos;
|
||||
|
||||
// Pass a polyline so that normal G-code generator can do a wipe for us.
|
||||
@@ -160,8 +161,9 @@ public:
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const;
|
||||
bool is_tool_change,
|
||||
float purge_volume,
|
||||
bool is_contact = false) const;
|
||||
|
||||
ToolChangeResult construct_block_tcr(WipeTowerWriter& writer,
|
||||
bool priming,
|
||||
@@ -319,6 +321,7 @@ public:
|
||||
bool is_support = false;
|
||||
int nozzle_temperature = 0;
|
||||
int nozzle_temperature_initial_layer = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -336,6 +339,10 @@ public:
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float wipe_dist;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
|
||||
@@ -492,6 +499,10 @@ private:
|
||||
std::map<float,Polylines> m_outer_wall;
|
||||
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
|
||||
bool m_flat_ironing=false;
|
||||
bool m_enable_tower_interface_features=false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower=false;
|
||||
bool m_prev_layer_had_interface=false;
|
||||
bool m_current_layer_has_interface=false;
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
||||
@@ -503,7 +514,7 @@ private:
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length);
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool);
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
@@ -972,6 +972,25 @@ public:
|
||||
return add_wipe_point(Vec2f(x, y));
|
||||
}
|
||||
|
||||
void spiral_flat_ironing(const Vec2f ¢er, float area, float step_length, float feedrate)
|
||||
{
|
||||
float edge_length = std::sqrt(area);
|
||||
Vec2f box_max = center + Vec2f{step_length, step_length};
|
||||
Vec2f box_min = center - Vec2f{step_length, step_length};
|
||||
int n = std::ceil(edge_length / step_length / 2.f);
|
||||
if (n <= 0)
|
||||
return;
|
||||
while (n--) {
|
||||
travel(box_max.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_max.y(), feedrate);
|
||||
travel(box_min.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_min.y(), feedrate);
|
||||
|
||||
box_max += Vec2f{step_length, step_length};
|
||||
box_min -= Vec2f{step_length, step_length};
|
||||
}
|
||||
}
|
||||
|
||||
// Extrude with an explicitely provided amount of extrusion.
|
||||
WipeTowerWriter2& extrude_arc_explicit(ArcSegment& arc,
|
||||
float f = 0.f,
|
||||
@@ -1200,7 +1219,8 @@ private:
|
||||
WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const
|
||||
bool is_finish,
|
||||
bool is_contact) const
|
||||
{
|
||||
WipeTower::ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1215,6 +1235,7 @@ WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
result.extrusions = std::move(writer.extrusions());
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_contact = is_contact;
|
||||
// ORCA: Always initialize the tool_change_start_pos with a valid position
|
||||
// to avoid undefined variable travel on X in Gcode.cpp function std::string WipeTowerIntegration::post_process_wipe_tower_moves
|
||||
result.tool_change_start_pos = result.start_pos; // always valid fallback
|
||||
@@ -1250,7 +1271,10 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_used_fillet(config.wipe_tower_fillet_wall),
|
||||
m_rib_width(config.wipe_tower_rib_width),
|
||||
m_extra_rib_length(config.wipe_tower_extra_rib_length),
|
||||
m_wall_type((int)config.wipe_tower_wall_type)
|
||||
m_wall_type((int)config.wipe_tower_wall_type),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
// it is taken over following default. Speeds from config are not
|
||||
@@ -1317,6 +1341,16 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1440,11 +1474,11 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
toolchange_Load(writer, cleaning_box); // Prime the tool.
|
||||
if (idx_tool + 1 == tools.size()) {
|
||||
// Last tool should not be unloaded, but it should be wiped enough to become of a pure color.
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool]);
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false);
|
||||
} else {
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
//writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f, false);
|
||||
WipeTower::box_coordinates box = cleaning_box;
|
||||
box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width);
|
||||
toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature);
|
||||
@@ -1472,7 +1506,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
"\n\n");
|
||||
}
|
||||
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true));
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true, false));
|
||||
}
|
||||
|
||||
m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear
|
||||
@@ -1487,6 +1521,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
|
||||
float wipe_area = 0.f;
|
||||
float wipe_volume = 0.f;
|
||||
bool interface_layer = m_enable_tower_interface_features && m_current_layer_has_interface;
|
||||
|
||||
// Finds this toolchange info
|
||||
if (tool != (unsigned int)(-1))
|
||||
@@ -1501,6 +1536,12 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
else {
|
||||
// Otherwise we are going to Unload only. And m_layer_info would be invalid.
|
||||
}
|
||||
if (interface_layer && tool != (unsigned int)(-1) && tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
wipe_volume += extra_purge_length * m_filpar[tool].filament_area;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTower::box_coordinates cleaning_box(
|
||||
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
@@ -1542,7 +1583,27 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
int base_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
float target_x = writer.x() + pre_dist;
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++ m_num_tool_changes;
|
||||
} else
|
||||
@@ -1564,7 +1625,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false);
|
||||
return construct_tcr(writer, false, old_tool, false, interface_layer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1854,7 +1915,8 @@ void WipeTower2::toolchange_Load(
|
||||
void WipeTower2::toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume)
|
||||
float wipe_volume,
|
||||
bool interface_layer)
|
||||
{
|
||||
// Increase flow on first layer, slow down print.
|
||||
writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
|
||||
@@ -1884,6 +1946,9 @@ void WipeTower2::toolchange_Wipe(
|
||||
m_left_to_right = !m_left_to_right;
|
||||
}
|
||||
|
||||
const bool do_ironing = m_flat_ironing && (!interface_layer || !m_enable_tower_interface_features);
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
|
||||
// now the wiping itself:
|
||||
for (int i = 0; true; ++i) {
|
||||
if (i!=0) {
|
||||
@@ -1899,6 +1964,11 @@ void WipeTower2::toolchange_Wipe(
|
||||
else
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
|
||||
|
||||
if (i == 0 && do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x(), writer.y(), 600.f);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, 10.f * 60.f);
|
||||
}
|
||||
|
||||
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width)
|
||||
break; // in case next line would not fit
|
||||
|
||||
@@ -1943,10 +2013,12 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
|
||||
|
||||
|
||||
// Slow down on the 1st layer.
|
||||
// Slow down on the 1st layer.
|
||||
// If spare layers are excluded -> if 1 or less toolchange has been done, it must be still the first layer, too. So slow down.
|
||||
bool first_layer = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers);
|
||||
float feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||
WipeTower::box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
@@ -2077,7 +2149,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
m_current_height += m_layer_info->height;
|
||||
}
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true);
|
||||
return construct_tcr(writer, false, old_tool, true, false);
|
||||
}
|
||||
|
||||
// Static method to get the radius and x-scaling of the stabilizing cone base.
|
||||
@@ -2245,6 +2317,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if (first.end_pos != second.start_pos)
|
||||
out.gcode += "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3)
|
||||
+ " Y" + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3)
|
||||
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
WipeTower::ToolChangeResult construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const;
|
||||
bool is_finish,
|
||||
bool is_contact = false) const;
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
@@ -88,11 +89,13 @@ public:
|
||||
m_layer_height = layer_height;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_layer_finished = false;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
m_current_layer_has_interface = (m_layer_info != m_plan.end()) && (m_layer_info->toolchanges_depth() > WT_EPSILON);
|
||||
|
||||
//m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
m_current_shape = SHAPE_NORMAL;
|
||||
@@ -145,6 +148,7 @@ public:
|
||||
bool is_soluble = false;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -168,6 +172,10 @@ public:
|
||||
float filament_minimal_purge_on_wipe_tower = 0.f;
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -208,6 +216,11 @@ private:
|
||||
float m_perimeter_speed = 0.f;
|
||||
float m_first_layer_speed = 0.f;
|
||||
size_t m_first_layer_idx = size_t(-1);
|
||||
bool m_flat_ironing = false;
|
||||
bool m_enable_tower_interface_features = false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower = false;
|
||||
bool m_prev_layer_had_interface = false;
|
||||
bool m_current_layer_has_interface = false;
|
||||
|
||||
int m_wall_type;
|
||||
bool m_used_fillet = true;
|
||||
@@ -335,7 +348,8 @@ private:
|
||||
void toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume);
|
||||
float wipe_volume,
|
||||
bool interface_layer);
|
||||
|
||||
|
||||
Polygon generate_support_rib_wall(WipeTowerWriter2& writer,
|
||||
|
||||
@@ -923,6 +923,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_volume",
|
||||
"prime_tower_infill_gap",
|
||||
"prime_tower_flat_ironing",
|
||||
"enable_tower_interface_features",
|
||||
"enable_tower_interface_cooldown_during_tower",
|
||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"flush_into_infill", "flush_into_objects", "flush_into_support",
|
||||
"tree_support_branch_angle", "tree_support_angle_slow", "tree_support_wall_count", "tree_support_top_rate", "tree_support_branch_distance", "tree_support_tip_diameter",
|
||||
@@ -959,6 +961,8 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
|
||||
"filament_soluble", "filament_is_support", "filament_printable",
|
||||
"filament_max_volumetric_speed", "filament_adaptive_volumetric_speed",
|
||||
"filament_flow_ratio", "filament_density", "filament_adhesiveness_category", "filament_cost", "filament_minimal_purge_on_wipe_tower",
|
||||
"filament_tower_interface_pre_extrusion_dist", "filament_tower_interface_pre_extrusion_length", "filament_tower_ironing_area", "filament_tower_interface_purge_volume",
|
||||
"filament_tower_interface_print_temp",
|
||||
"nozzle_temperature", "nozzle_temperature_initial_layer",
|
||||
// BBS
|
||||
"cool_plate_temp", "textured_cool_plate_temp", "eng_plate_temp", "hot_plate_temp", "textured_plate_temp", "cool_plate_temp_initial_layer", "textured_cool_plate_temp_initial_layer", "eng_plate_temp_initial_layer", "hot_plate_temp_initial_layer", "textured_plate_temp_initial_layer", "supertack_plate_temp_initial_layer", "supertack_plate_temp",
|
||||
|
||||
@@ -317,6 +317,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "prime_tower_brim_width"
|
||||
|| opt_key == "prime_tower_skip_points"
|
||||
|| opt_key == "prime_tower_flat_ironing"
|
||||
|| opt_key == "enable_tower_interface_features"
|
||||
|| opt_key == "first_layer_print_sequence"
|
||||
|| opt_key == "other_layers_print_sequence"
|
||||
|| opt_key == "other_layers_print_sequence_nums"
|
||||
@@ -324,6 +325,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "filament_map_mode"
|
||||
|| opt_key == "filament_map"
|
||||
|| opt_key == "filament_adhesiveness_category"
|
||||
|| opt_key == "filament_tower_interface_pre_extrusion_dist"
|
||||
|| opt_key == "filament_tower_interface_pre_extrusion_length"
|
||||
|| opt_key == "filament_tower_ironing_area"
|
||||
|| opt_key == "filament_tower_interface_purge_volume"
|
||||
|| opt_key == "filament_tower_interface_print_temp"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wipe_tower_extra_flow"
|
||||
|| opt_key == "wipe_tower_no_sparse_layers"
|
||||
|
||||
@@ -2587,6 +2587,46 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 15. });
|
||||
|
||||
def = this->add("filament_tower_interface_pre_extrusion_dist", coFloats);
|
||||
def->label = L("Interface layer pre-extrusion distance");
|
||||
def->tooltip = L("Pre-extrusion distance for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 10. });
|
||||
|
||||
def = this->add("filament_tower_interface_pre_extrusion_length", coFloats);
|
||||
def->label = L("Interface layer pre-extrusion length");
|
||||
def->tooltip = L("Pre-extrusion length for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 0. });
|
||||
|
||||
def = this->add("filament_tower_ironing_area", coFloats);
|
||||
def->label = L("Tower ironing area");
|
||||
def->tooltip = L("Ironing area for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm²");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 4. });
|
||||
|
||||
def = this->add("filament_tower_interface_purge_volume", coFloats);
|
||||
def->label = L("Interface layer purge length");
|
||||
def->tooltip = L("Purge length for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 20. });
|
||||
|
||||
def = this->add("filament_tower_interface_print_temp", coInts);
|
||||
def->label = L("Interface layer print temperature");
|
||||
def->tooltip = L("Print temperature for prime tower interface layer (where different materials meet). If set to -1, use max recommended nozzle temperature.");
|
||||
def->sidetext = L("°C");
|
||||
def->min = -1;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInts { -1 });
|
||||
|
||||
def = this->add("filament_cooling_final_speed", coFloats);
|
||||
def->label = L("Speed of the last cooling move");
|
||||
def->tooltip = L("Cooling moves are gradually accelerating towards this speed.");
|
||||
@@ -6408,6 +6448,18 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("enable_tower_interface_features", coBool);
|
||||
def->label = L("Enable tower interface features");
|
||||
def->tooltip = L("Enable optimized prime tower interface behavior when different materials meet.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("enable_tower_interface_cooldown_during_tower", coBool);
|
||||
def->label = L("Cool down from interface boost during prime tower");
|
||||
def->tooltip = L("When interface-layer temperature boost is active, set the nozzle back to print temperature at the start of the prime tower so it cools down during the tower.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("prime_tower_infill_gap", coPercent);
|
||||
def->label = L("Infill gap");
|
||||
def->tooltip = L("Infill gap.");
|
||||
@@ -9236,6 +9288,61 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Options in printer_options_with_variant_2 are stored as (normal,silent) pairs per printer variant.
|
||||
// Some legacy presets/projects carry a variant list but still store only one pair; normalize to avoid crashes.
|
||||
static void normalize_stride2_floats(ConfigOptionFloats &opt, size_t expected_size)
|
||||
{
|
||||
auto &v = opt.values;
|
||||
if (expected_size == 0) {
|
||||
v.clear();
|
||||
return;
|
||||
}
|
||||
if (v.empty()) {
|
||||
// Fallback: keep behavior predictable instead of crashing. This should be rare.
|
||||
v.resize(expected_size, 0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
const double first = v[0];
|
||||
const double second = (v.size() >= 2) ? v[1] : first;
|
||||
|
||||
// Ensure we have at least one (normal,silent) pair to replicate.
|
||||
if (v.size() < 2) {
|
||||
v.resize(2, first);
|
||||
v[1] = second;
|
||||
}
|
||||
// Keep pair alignment if some legacy preset produced odd length.
|
||||
if (v.size() % 2 != 0)
|
||||
v.push_back(second);
|
||||
|
||||
if (v.size() > expected_size) {
|
||||
v.resize(expected_size);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t have_variants = v.size() / 2;
|
||||
const size_t want_variants = expected_size / 2;
|
||||
v.resize(expected_size);
|
||||
for (size_t vi = have_variants; vi < want_variants; ++vi) {
|
||||
v[vi * 2] = first;
|
||||
if (vi * 2 + 1 < v.size())
|
||||
v[vi * 2 + 1] = second;
|
||||
}
|
||||
}
|
||||
|
||||
static void log_normalize_legacy_vector_size(const char *fn, const std::string &key, int stride, size_t src_size, size_t dest_size, size_t expected_size,
|
||||
size_t restore_n, int cur_variant_count, int target_variant_count, size_t cur_ids, size_t target_ids,
|
||||
const ConfigOption *opt_src, const ConfigOption *opt_target)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << fn << ": normalizing legacy vector size for key '" << key << "'"
|
||||
<< " stride=" << stride << " src_size=" << src_size << " dest_size=" << dest_size << " expected=" << expected_size
|
||||
<< " restore_index.size=" << restore_n << " cur_variants=" << cur_variant_count << " target_variants=" << target_variant_count
|
||||
<< " cur_ids=" << cur_ids << " target_ids=" << target_ids << " cur_value=" << opt_src->serialize()
|
||||
<< " target_value=" << opt_target->serialize();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfig& new_config, const t_config_option_keys& keys, const std::set<std::string>& different_keys,
|
||||
std::string extruder_id_name, std::string extruder_variant_name, std::set<std::string>& key_set1, std::set<std::string>& key_set2)
|
||||
{
|
||||
@@ -9258,7 +9365,10 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
|
||||
|
||||
variant_index.resize(target_variant_count, -1);
|
||||
if (cur_variant_count == 0) {
|
||||
variant_index[0] = 0;
|
||||
// Defensive: target_variant_count may be 0 if the preset doesn't carry extruder_variant_name.
|
||||
// In that case keep variant_index empty and let the downstream size checks produce a useful error.
|
||||
if (!variant_index.empty())
|
||||
variant_index[0] = 0;
|
||||
}
|
||||
else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){
|
||||
//should not happen
|
||||
@@ -9300,12 +9410,53 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
|
||||
//nothing to do, keep the original one
|
||||
}
|
||||
else {
|
||||
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
|
||||
const ConfigOptionVectorBase* opt_vec_dest = static_cast<const ConfigOptionVectorBase*>(opt_target);
|
||||
int stride = 1;
|
||||
if (key_set2.find(opt) != key_set2.end())
|
||||
stride = 2;
|
||||
opt_vec_src->set_with_restore(opt_vec_dest, variant_index, stride);
|
||||
|
||||
const size_t restore_n = variant_index.size();
|
||||
const size_t expected_size = restore_n * size_t(stride);
|
||||
|
||||
if (stride == 2) {
|
||||
// Options in key_set2 are machine limits stored as (normal,silent) pairs per printer variant.
|
||||
if (opt_src->type() != coFloats || opt_target->type() != coFloats)
|
||||
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be ConfigOptionFloats for stride=2.") % __FUNCTION__ % opt).str());
|
||||
|
||||
auto *src_f = static_cast<ConfigOptionFloats*>(opt_src);
|
||||
ConfigOptionFloats rhs_tmp(*static_cast<const ConfigOptionFloats*>(opt_target));
|
||||
|
||||
const size_t src_size = src_f->values.size();
|
||||
const size_t dest_size = rhs_tmp.values.size();
|
||||
if (src_size != expected_size || dest_size != expected_size)
|
||||
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
|
||||
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
|
||||
|
||||
// Normalize src in-place so backup_values indexing is safe, normalize rhs via a temporary copy.
|
||||
normalize_stride2_floats(*src_f, expected_size);
|
||||
normalize_stride2_floats(rhs_tmp, expected_size);
|
||||
src_f->set_with_restore(&rhs_tmp, variant_index, stride);
|
||||
} else {
|
||||
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
|
||||
|
||||
const size_t src_size = opt_vec_src->size();
|
||||
const size_t dest_size = static_cast<const ConfigOptionVectorBase*>(opt_target)->size();
|
||||
if (src_size != expected_size || dest_size != expected_size)
|
||||
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
|
||||
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
|
||||
|
||||
if (opt_vec_src->size() != expected_size)
|
||||
opt_vec_src->resize(expected_size, opt_target);
|
||||
|
||||
// Normalize rhs via a cloned temporary (rhs itself is const).
|
||||
ConfigOptionUniquePtr rhs_owner(opt_target->clone());
|
||||
ConfigOptionVectorBase *rhs_vec = dynamic_cast<ConfigOptionVectorBase*>(rhs_owner.get());
|
||||
if (rhs_vec == nullptr)
|
||||
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be a vector option.") % __FUNCTION__ % opt).str());
|
||||
if (rhs_vec->size() != expected_size)
|
||||
rhs_vec->resize(expected_size, opt_target);
|
||||
|
||||
opt_vec_src->set_with_restore(rhs_vec, variant_index, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1376,6 +1376,11 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInts, filament_cooling_moves))
|
||||
((ConfigOptionFloats, filament_cooling_initial_speed))
|
||||
((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower))
|
||||
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_dist))
|
||||
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_length))
|
||||
((ConfigOptionFloats, filament_tower_ironing_area))
|
||||
((ConfigOptionFloats, filament_tower_interface_purge_volume))
|
||||
((ConfigOptionInts, filament_tower_interface_print_temp))
|
||||
((ConfigOptionFloats, filament_cooling_final_speed))
|
||||
((ConfigOptionStrings, filament_ramming_parameters))
|
||||
((ConfigOptionBools, filament_multitool_ramming))
|
||||
@@ -1505,6 +1510,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionPercent, prime_tower_infill_gap))
|
||||
((ConfigOptionBool, prime_tower_skip_points))
|
||||
((ConfigOptionBool, prime_tower_flat_ironing))
|
||||
((ConfigOptionBool, enable_tower_interface_features))
|
||||
((ConfigOptionBool, enable_tower_interface_cooldown_during_tower))
|
||||
((ConfigOptionFloat, wipe_tower_bridging))
|
||||
((ConfigOptionPercent, wipe_tower_extra_flow))
|
||||
((ConfigOptionFloats, flush_volumes_matrix))
|
||||
|
||||
@@ -816,9 +816,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
toggle_line("preheat_steps", have_ooze_prevention && (preheat_steps > 0));
|
||||
|
||||
bool have_prime_tower = config->opt_bool("enable_prime_tower");
|
||||
for (auto el : {"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "wipe_tower_wall_type", "prime_tower_infill_gap","prime_tower_enable_framework"})
|
||||
for (auto el : {"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "wipe_tower_wall_type", "prime_tower_infill_gap","prime_tower_enable_framework", "enable_tower_interface_features"})
|
||||
toggle_line(el, have_prime_tower);
|
||||
|
||||
toggle_line("enable_tower_interface_cooldown_during_tower",
|
||||
have_prime_tower && config->opt_bool("enable_tower_interface_features"));
|
||||
|
||||
for (auto el : {"wall_filament", "sparse_infill_filament", "solid_infill_filament", "wipe_tower_filament"})
|
||||
toggle_line(el, !bSEMM);
|
||||
|
||||
|
||||
@@ -25,6 +25,18 @@
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#endif // __APPLE__
|
||||
|
||||
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
|
||||
// A mismatch causes rendering failures: GLEW's function loading must match
|
||||
// the context type created by wxWidgets.
|
||||
#if defined(__linux__)
|
||||
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
|
||||
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
|
||||
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
@@ -2576,6 +2576,8 @@ void TabPrint::build()
|
||||
optgroup = page->new_optgroup(L("Prime tower"), L"param_tower");
|
||||
optgroup->append_single_option_line("enable_prime_tower", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_skip_points", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("enable_tower_interface_features", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("enable_tower_interface_cooldown_during_tower", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_enable_framework", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_width", "multimaterial_settings_prime_tower#width");
|
||||
optgroup->append_single_option_line("prime_volume", "multimaterial_settings_prime_tower");
|
||||
@@ -4040,6 +4042,11 @@ void TabFilament::build()
|
||||
page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material"); // ORCA: icon only visible on placeholders
|
||||
optgroup = page->new_optgroup(L("Wipe tower parameters"), "param_tower");
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_dist", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_length", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_ironing_area", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_purge_volume", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_print_temp", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
|
||||
optgroup = page->new_optgroup(L("Multi Filament"));
|
||||
// optgroup->append_single_option_line("filament_flush_temp", "", 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "CalibUtils.hpp"
|
||||
#include "../GUI/I18N.hpp"
|
||||
#include "../GUI/GUI_App.hpp"
|
||||
#include "../GUI/DeviceCore/DevStorage.h"
|
||||
#include "../GUI/DeviceCore/DevStorage.h"
|
||||
#include "../GUI/DeviceManager.hpp"
|
||||
#include "../GUI/Jobs/ProgressIndicator.hpp"
|
||||
#include "../GUI/PartPlate.hpp"
|
||||
|
||||
@@ -461,42 +461,6 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Color normalization helper (handles #RRGGBB, 0xRRGGBB -> RRGGBBAA)
|
||||
auto normalize_color = [](const std::string& color) -> std::string {
|
||||
std::string value = color;
|
||||
boost::trim(value);
|
||||
|
||||
// Remove 0x or 0X prefix if present
|
||||
if (value.size() >= 2 && (value.rfind("0x", 0) == 0 || value.rfind("0X", 0) == 0)) {
|
||||
value = value.substr(2);
|
||||
}
|
||||
// Remove # prefix if present
|
||||
if (!value.empty() && value[0] == '#') {
|
||||
value = value.substr(1);
|
||||
}
|
||||
|
||||
// Extract only hex digits
|
||||
std::string normalized;
|
||||
for (char c : value) {
|
||||
if (std::isxdigit(static_cast<unsigned char>(c))) {
|
||||
normalized.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
|
||||
}
|
||||
}
|
||||
|
||||
// If 6 hex digits, add FF alpha
|
||||
if (normalized.size() == 6) {
|
||||
normalized += "FF";
|
||||
}
|
||||
|
||||
// Validate length - return default if invalid
|
||||
if (normalized.size() != 8) {
|
||||
return "00000000";
|
||||
}
|
||||
|
||||
return normalized;
|
||||
};
|
||||
|
||||
// Build BBL-format JSON for DevFilaSystemParser::ParseV1_0
|
||||
nlohmann::json ams_json = nlohmann::json::object();
|
||||
nlohmann::json ams_array = nlohmann::json::array();
|
||||
@@ -535,7 +499,7 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
|
||||
|
||||
tray_json["tray_info_idx"] = tray->tray_info_idx;
|
||||
tray_json["tray_type"] = tray->tray_type;
|
||||
tray_json["tray_color"] = normalize_color(tray->tray_color);
|
||||
tray_json["tray_color"] = normalize_color_value(tray->tray_color);
|
||||
|
||||
// Add temperature data if provided
|
||||
if (tray->bed_temp > 0) {
|
||||
@@ -604,119 +568,30 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
|
||||
|
||||
bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id)
|
||||
{
|
||||
// Fetch AFC lane data from Moonraker database (inline)
|
||||
std::string url = join_url(device_info.base_url, "/server/database/item?namespace=lane_data");
|
||||
|
||||
std::string response_body;
|
||||
bool success = false;
|
||||
std::string http_error;
|
||||
|
||||
auto http = Http::get(url);
|
||||
if (!device_info.api_key.empty()) {
|
||||
http.header("X-Api-Key", device_info.api_key);
|
||||
}
|
||||
http.timeout_connect(5)
|
||||
.timeout_max(10)
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
if (status == 200) {
|
||||
response_body = body;
|
||||
success = true;
|
||||
} else {
|
||||
http_error = "HTTP error: " + std::to_string(status);
|
||||
}
|
||||
})
|
||||
.on_error([&](std::string body, std::string err, unsigned status) {
|
||||
http_error = err;
|
||||
if (status > 0) {
|
||||
http_error += " (HTTP " + std::to_string(status) + ")";
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
if (!success) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Failed to fetch lane data: " << http_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
|
||||
if (json.is_discarded()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Invalid JSON response";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Expected structure: { "result": { "namespace": "lane_data", "value": { "lane1": {...}, ... } } }
|
||||
if (!json.contains("result") || !json["result"].contains("value") || !json["result"]["value"].is_object()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_filament_info: Unexpected JSON structure or no lane_data found";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse response into AmsTrayData
|
||||
const auto& value = json["result"]["value"];
|
||||
std::vector<AmsTrayData> trays;
|
||||
int max_lane_index = 0;
|
||||
|
||||
// Null-safe JSON accessors: nlohmann::json::value() throws type_error
|
||||
// when the key exists but the value is null (type mismatch).
|
||||
auto safe_string = [](const nlohmann::json& obj, const char* key) -> std::string {
|
||||
auto it = obj.find(key);
|
||||
if (it != obj.end() && it->is_string())
|
||||
return it->get<std::string>();
|
||||
return "";
|
||||
};
|
||||
auto safe_int = [](const nlohmann::json& obj, const char* key) -> int {
|
||||
auto it = obj.find(key);
|
||||
if (it != obj.end() && it->is_number())
|
||||
return it->get<int>();
|
||||
return 0;
|
||||
};
|
||||
|
||||
for (const auto& [lane_key, lane_obj] : value.items()) {
|
||||
if (!lane_obj.is_object()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract lane index from the "lane" field (tool number, 0-based)
|
||||
std::string lane_str = safe_string(lane_obj, "lane");
|
||||
int lane_index = -1;
|
||||
if (!lane_str.empty()) {
|
||||
try {
|
||||
lane_index = std::stoi(lane_str);
|
||||
} catch (...) {
|
||||
lane_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lane_index < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AmsTrayData tray;
|
||||
tray.slot_index = lane_index;
|
||||
tray.tray_color = safe_string(lane_obj, "color");
|
||||
tray.tray_type = safe_string(lane_obj, "material");
|
||||
tray.bed_temp = safe_int(lane_obj, "bed_temp");
|
||||
tray.nozzle_temp = safe_int(lane_obj, "nozzle_temp");
|
||||
tray.has_filament = !tray.tray_type.empty();
|
||||
auto* bundle = GUI::wxGetApp().preset_bundle;
|
||||
tray.tray_info_idx = bundle
|
||||
? bundle->filaments.filament_id_by_type(tray.tray_type)
|
||||
: map_filament_type_to_generic_id(tray.tray_type);
|
||||
|
||||
max_lane_index = std::max(max_lane_index, lane_index);
|
||||
trays.push_back(tray);
|
||||
// Try Happy Hare first (more widely adopted, supports more filament changers)
|
||||
if (fetch_hh_filament_info(trays, max_lane_index)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Happy Hare MMU with "
|
||||
<< (max_lane_index + 1) << " gates";
|
||||
int ams_count = (max_lane_index + 4) / 4;
|
||||
build_ams_payload(ams_count, max_lane_index, trays);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (trays.empty()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No AFC lanes found";
|
||||
return false;
|
||||
// Fallback to AFC
|
||||
if (fetch_afc_filament_info(trays, max_lane_index)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected AFC with "
|
||||
<< (max_lane_index + 1) << " lanes";
|
||||
int ams_count = (max_lane_index + 4) / 4;
|
||||
build_ams_payload(ams_count, max_lane_index, trays);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate AMS count from max lane index (4 trays per AMS unit)
|
||||
int ams_count = (max_lane_index + 4) / 4;
|
||||
|
||||
// Build and parse the AMS payload
|
||||
build_ams_payload(ams_count, max_lane_index, trays);
|
||||
return true;
|
||||
// No MMU detected - this is normal for printers without MMU, not an error
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No MMU system detected (neither HH nor AFC)";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string MoonrakerPrinterAgent::trim_and_upper(const std::string& input)
|
||||
@@ -780,6 +655,298 @@ std::string MoonrakerPrinterAgent::map_filament_type_to_generic_id(const std::st
|
||||
return UNKNOWN_FILAMENT_ID;
|
||||
}
|
||||
|
||||
// JSON helper methods - null-safe accessors
|
||||
std::string MoonrakerPrinterAgent::safe_json_string(const nlohmann::json& obj, const char* key)
|
||||
{
|
||||
auto it = obj.find(key);
|
||||
if (it != obj.end() && it->is_string())
|
||||
return it->get<std::string>();
|
||||
return "";
|
||||
}
|
||||
|
||||
int MoonrakerPrinterAgent::safe_json_int(const nlohmann::json& obj, const char* key)
|
||||
{
|
||||
auto it = obj.find(key);
|
||||
if (it != obj.end() && it->is_number())
|
||||
return it->get<int>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string MoonrakerPrinterAgent::safe_array_string(const nlohmann::json& arr, int idx)
|
||||
{
|
||||
if (arr.is_array() && idx >= 0 && idx < static_cast<int>(arr.size()) && arr[idx].is_string())
|
||||
return arr[idx].get<std::string>();
|
||||
return "";
|
||||
}
|
||||
|
||||
int MoonrakerPrinterAgent::safe_array_int(const nlohmann::json& arr, int idx)
|
||||
{
|
||||
if (arr.is_array() && idx >= 0 && idx < static_cast<int>(arr.size()) && arr[idx].is_number())
|
||||
return arr[idx].get<int>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string MoonrakerPrinterAgent::normalize_color_value(const std::string& color)
|
||||
{
|
||||
std::string value = color;
|
||||
boost::trim(value);
|
||||
|
||||
// Remove 0x or 0X prefix if present
|
||||
if (value.size() >= 2 && (value.rfind("0x", 0) == 0 || value.rfind("0X", 0) == 0)) {
|
||||
value = value.substr(2);
|
||||
}
|
||||
// Remove # prefix if present
|
||||
if (!value.empty() && value[0] == '#') {
|
||||
value = value.substr(1);
|
||||
}
|
||||
|
||||
// Extract only hex digits
|
||||
std::string normalized;
|
||||
for (char c : value) {
|
||||
if (std::isxdigit(static_cast<unsigned char>(c))) {
|
||||
normalized.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
|
||||
}
|
||||
}
|
||||
|
||||
// If 6 hex digits, add FF alpha
|
||||
if (normalized.size() == 6) {
|
||||
normalized += "FF";
|
||||
}
|
||||
|
||||
// Validate length - return default if invalid
|
||||
if (normalized.size() != 8) {
|
||||
return "00000000";
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// Fetch filament info from Armored Turtle AFC
|
||||
bool MoonrakerPrinterAgent::fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index)
|
||||
{
|
||||
// Fetch AFC lane data from Moonraker database
|
||||
std::string url = join_url(device_info.base_url, "/server/database/item?namespace=lane_data");
|
||||
|
||||
std::string response_body;
|
||||
bool success = false;
|
||||
std::string http_error;
|
||||
|
||||
auto http = Http::get(url);
|
||||
if (!device_info.api_key.empty()) {
|
||||
http.header("X-Api-Key", device_info.api_key);
|
||||
}
|
||||
http.timeout_connect(5)
|
||||
.timeout_max(10)
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
if (status == 200) {
|
||||
response_body = body;
|
||||
success = true;
|
||||
} else {
|
||||
http_error = "HTTP error: " + std::to_string(status);
|
||||
}
|
||||
})
|
||||
.on_error([&](std::string body, std::string err, unsigned status) {
|
||||
http_error = err;
|
||||
if (status > 0) {
|
||||
http_error += " (HTTP " + std::to_string(status) + ")";
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
if (!success) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Failed to fetch lane data: " << http_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
|
||||
if (json.is_discarded()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Invalid JSON response";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Expected structure: { "result": { "namespace": "lane_data", "value": { "lane1": {...}, ... } } }
|
||||
if (!json.contains("result") || !json["result"].contains("value") || !json["result"]["value"].is_object()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Unexpected JSON structure or no lane_data found";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse response into AmsTrayData
|
||||
const auto& value = json["result"]["value"];
|
||||
trays.clear();
|
||||
max_lane_index = 0;
|
||||
|
||||
for (const auto& [lane_key, lane_obj] : value.items()) {
|
||||
if (!lane_obj.is_object()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract lane index from the "lane" field (tool number, 0-based)
|
||||
std::string lane_str = safe_json_string(lane_obj, "lane");
|
||||
int lane_index = -1;
|
||||
if (!lane_str.empty()) {
|
||||
try {
|
||||
lane_index = std::stoi(lane_str);
|
||||
} catch (...) {
|
||||
lane_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lane_index < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AmsTrayData tray;
|
||||
tray.slot_index = lane_index;
|
||||
tray.tray_color = safe_json_string(lane_obj, "color");
|
||||
tray.tray_type = safe_json_string(lane_obj, "material");
|
||||
tray.bed_temp = safe_json_int(lane_obj, "bed_temp");
|
||||
tray.nozzle_temp = safe_json_int(lane_obj, "nozzle_temp");
|
||||
tray.has_filament = !tray.tray_type.empty();
|
||||
auto* bundle = GUI::wxGetApp().preset_bundle;
|
||||
tray.tray_info_idx = bundle
|
||||
? bundle->filaments.filament_id_by_type(tray.tray_type)
|
||||
: map_filament_type_to_generic_id(tray.tray_type);
|
||||
|
||||
max_lane_index = std::max(max_lane_index, lane_index);
|
||||
trays.push_back(tray);
|
||||
}
|
||||
|
||||
if (trays.empty()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_afc_filament_info: No AFC lanes found";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch filament info from Happy Hare MMU
|
||||
bool MoonrakerPrinterAgent::fetch_hh_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index)
|
||||
{
|
||||
// Query Happy Hare MMU status
|
||||
std::string url = join_url(device_info.base_url, "/printer/objects/query?mmu");
|
||||
|
||||
std::string response_body;
|
||||
bool success = false;
|
||||
std::string http_error;
|
||||
|
||||
auto http = Http::get(url);
|
||||
if (!device_info.api_key.empty()) {
|
||||
http.header("X-Api-Key", device_info.api_key);
|
||||
}
|
||||
http.timeout_connect(5)
|
||||
.timeout_max(10)
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
if (status == 200) {
|
||||
response_body = body;
|
||||
success = true;
|
||||
} else {
|
||||
http_error = "HTTP error: " + std::to_string(status);
|
||||
}
|
||||
})
|
||||
.on_error([&](std::string body, std::string err, unsigned status) {
|
||||
http_error = err;
|
||||
if (status > 0) {
|
||||
http_error += " (HTTP " + std::to_string(status) + ")";
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
if (!success) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Failed to fetch HH data: " << http_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
|
||||
if (json.is_discarded()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Invalid JSON response";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Expected structure: { "result": { "status": { "mmu": { ... } } } }
|
||||
if (!json.contains("result") || !json["result"].contains("status") ||
|
||||
!json["result"]["status"].contains("mmu") || !json["result"]["status"]["mmu"].is_object()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No mmu object in response";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& mmu = json["result"]["status"]["mmu"];
|
||||
|
||||
// Check if HH is installed (empty mmu object means HH not installed)
|
||||
if (mmu.empty()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Empty mmu object (HH not installed)";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get num_gates
|
||||
if (!mmu.contains("num_gates") || !mmu["num_gates"].is_number()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No num_gates field";
|
||||
return false;
|
||||
}
|
||||
|
||||
int num_gates = mmu["num_gates"].get<int>();
|
||||
if (num_gates <= 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_hh_filament_info: Invalid num_gates: " << num_gates;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get arrays
|
||||
const auto& gate_status = mmu.contains("gate_status") ? mmu["gate_status"] : nlohmann::json::array();
|
||||
const auto& gate_material = mmu.contains("gate_material") ? mmu["gate_material"] : nlohmann::json::array();
|
||||
const auto& gate_color = mmu.contains("gate_color") ? mmu["gate_color"] : nlohmann::json::array();
|
||||
const auto& gate_temperature = mmu.contains("gate_temperature") ? mmu["gate_temperature"] : nlohmann::json::array();
|
||||
|
||||
if (!gate_status.is_array() || !gate_material.is_array() ||
|
||||
!gate_color.is_array() || !gate_temperature.is_array()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_hh_filament_info: HH arrays not found or invalid type";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse gate data
|
||||
trays.clear();
|
||||
max_lane_index = 0;
|
||||
|
||||
for (int gate_idx = 0; gate_idx < num_gates; ++gate_idx) {
|
||||
// Check gate_status: -1 = unknown, 0 = empty, 1 or 2 = available
|
||||
int status = safe_array_int(gate_status, gate_idx);
|
||||
if (status <= 0) {
|
||||
continue; // Skip unknown or empty gates
|
||||
}
|
||||
|
||||
// Extract gate data
|
||||
std::string material = safe_array_string(gate_material, gate_idx);
|
||||
std::string color = safe_array_string(gate_color, gate_idx);
|
||||
int nozzle_temp = safe_array_int(gate_temperature, gate_idx);
|
||||
|
||||
// Skip if no material type (empty gate)
|
||||
if (material.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AmsTrayData tray;
|
||||
tray.slot_index = gate_idx;
|
||||
tray.tray_type = material;
|
||||
tray.tray_color = color;
|
||||
tray.nozzle_temp = nozzle_temp;
|
||||
tray.bed_temp = 0; // HH doesn't provide bed temp in gate arrays
|
||||
tray.has_filament = true;
|
||||
|
||||
auto* bundle = GUI::wxGetApp().preset_bundle;
|
||||
tray.tray_info_idx = bundle
|
||||
? bundle->filaments.filament_id_by_type(tray.tray_type)
|
||||
: map_filament_type_to_generic_id(tray.tray_type);
|
||||
|
||||
max_lane_index = std::max(max_lane_index, gate_idx);
|
||||
trays.push_back(tray);
|
||||
}
|
||||
|
||||
if (trays.empty()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_hh_filament_info: No valid HH gates found";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::string& json_str)
|
||||
{
|
||||
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
||||
|
||||
@@ -160,6 +160,17 @@ private:
|
||||
const std::string& api_key,
|
||||
uint64_t generation);
|
||||
|
||||
// System-specific filament fetch methods
|
||||
bool fetch_hh_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
|
||||
bool fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
|
||||
|
||||
// JSON helper methods
|
||||
static std::string safe_json_string(const nlohmann::json& obj, const char* key);
|
||||
static int safe_json_int(const nlohmann::json& obj, const char* key);
|
||||
static std::string safe_array_string(const nlohmann::json& arr, int idx);
|
||||
static int safe_array_int(const nlohmann::json& arr, int idx);
|
||||
static std::string normalize_color_value(const std::string& color);
|
||||
|
||||
std::string ssdp_announced_host;
|
||||
std::string ssdp_announced_id;
|
||||
std::shared_ptr<ICloudServiceAgent> m_cloud_agent;
|
||||
|
||||
@@ -7,7 +7,7 @@ set(SLIC3R_APP_KEY "OrcaSlicer")
|
||||
if(NOT DEFINED BBL_INTERNAL_TESTING)
|
||||
set(BBL_INTERNAL_TESTING "0")
|
||||
endif()
|
||||
set(SoftFever_VERSION "2.3.2-dev")
|
||||
set(SoftFever_VERSION "2.3.2-beta2")
|
||||
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)"
|
||||
SoftFever_VERSION_MATCH ${SoftFever_VERSION})
|
||||
set(ORCA_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
|
||||
Reference in New Issue
Block a user