mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 01:01:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ecfee6a21 | ||
|
|
fbf4652e12 | ||
|
|
be9ff50130 | ||
|
|
dee1f1715f | ||
|
|
fcb1f62bd9 |
@@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- release/*
|
- release/*
|
||||||
|
- belt-printer
|
||||||
paths:
|
paths:
|
||||||
- 'deps/**'
|
- 'deps/**'
|
||||||
- 'src/**'
|
- 'src/**'
|
||||||
@@ -261,6 +262,9 @@ jobs:
|
|||||||
date:
|
date:
|
||||||
ver:
|
ver:
|
||||||
ver_pure:
|
ver_pure:
|
||||||
|
# Belt-printer nightlies share the main nightly release but carry a `_belt`
|
||||||
|
# suffix so they never overwrite the main assets.
|
||||||
|
nightly_suffix: ${{ github.ref == 'refs/heads/belt-printer' && '_belt' || '' }}
|
||||||
steps:
|
steps:
|
||||||
- name: "Remove unneeded stuff to free disk space"
|
- name: "Remove unneeded stuff to free disk space"
|
||||||
run:
|
run:
|
||||||
@@ -435,13 +439,13 @@ jobs:
|
|||||||
name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||||
path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
|
path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
|
||||||
- name: Deploy Flatpak to nightly release
|
- name: Deploy Flatpak to nightly release
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main'
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer')
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
release_id: 137995723
|
release_id: 137995723
|
||||||
asset_path: /__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
asset_path: /__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||||
asset_name: OrcaSlicer-Linux-flatpak_nightly_${{ matrix.variant.arch }}.flatpak
|
asset_name: OrcaSlicer-Linux-flatpak_nightly${{ env.nightly_suffix }}_${{ matrix.variant.arch }}.flatpak
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||||
# The asset is /app (the exes link it at runtime) plus the build tree
|
# The asset is /app (the exes link it at runtime) plus the build tree
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ jobs:
|
|||||||
ubuntu-ver: '2404'
|
ubuntu-ver: '2404'
|
||||||
ubuntu-ver-str: '_Ubuntu2404'
|
ubuntu-ver-str: '_Ubuntu2404'
|
||||||
ORCA_UPDATER_SIG_KEY: ${{ secrets.ORCA_UPDATER_SIG_KEY }}
|
ORCA_UPDATER_SIG_KEY: ${{ secrets.ORCA_UPDATER_SIG_KEY }}
|
||||||
|
# Branches whose builds are published to the nightly release. The
|
||||||
|
# belt-printer branch ships alongside main but its assets carry a `_belt`
|
||||||
|
# suffix (nightly_suffix) so they never overwrite the main nightly assets.
|
||||||
|
deploy_nightly: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' }}
|
||||||
|
nightly_suffix: ${{ github.ref == 'refs/heads/belt-printer' && '_belt' || '' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -255,7 +260,7 @@ jobs:
|
|||||||
|
|
||||||
# Thanks to RaySajuuk, it's working now
|
# Thanks to RaySajuuk, it's working now
|
||||||
- name: Sign app and notary
|
- name: Sign app and notary
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'macOS' && inputs.macos-combine-only
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'macOS' && inputs.macos-combine-only
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
env:
|
||||||
@@ -343,7 +348,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create DMG without notary
|
- name: Create DMG without notary
|
||||||
if: github.ref != 'refs/heads/main' && runner.os == 'macOS' && inputs.macos-combine-only
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/belt-printer' && runner.os == 'macOS' && inputs.macos-combine-only
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
# Load the `retry` helper (retries flaky commands such as `hdiutil create`).
|
# Load the `retry` helper (retries flaky commands such as `hdiutil create`).
|
||||||
@@ -389,13 +394,13 @@ jobs:
|
|||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
|
|
||||||
- name: Deploy Mac release
|
- name: Deploy Mac release
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'macOS' && inputs.macos-combine-only && !vars.SELF_HOSTED
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'macOS' && inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
release_id: 137995723
|
release_id: 137995723
|
||||||
asset_path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
asset_path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||||
asset_name: OrcaSlicer_Mac_universal_nightly.dmg
|
asset_name: OrcaSlicer_Mac_universal_nightly${{ env.nightly_suffix }}.dmg
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||||
|
|
||||||
@@ -538,24 +543,24 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/build/src/Release/OrcaSlicer_profile_validator.exe
|
path: ${{ github.workspace }}/build/src/Release/OrcaSlicer_profile_validator.exe
|
||||||
|
|
||||||
- name: Deploy Windows release portable
|
- name: Deploy Windows release portable
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
release_id: 137995723
|
release_id: 137995723
|
||||||
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip
|
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip
|
||||||
asset_name: OrcaSlicer_Windows${{ env.ARCH_SUFFIX }}_nightly_portable.zip
|
asset_name: OrcaSlicer_Windows${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}_portable.zip
|
||||||
asset_content_type: application/x-zip-compressed
|
asset_content_type: application/x-zip-compressed
|
||||||
max_releases: 1
|
max_releases: 1
|
||||||
|
|
||||||
- name: Deploy Windows release installer
|
- name: Deploy Windows release installer
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
release_id: 137995723
|
release_id: 137995723
|
||||||
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_Installer_${{ env.ver }}${{ env.ARCH_SUFFIX }}.exe
|
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_Installer_${{ env.ver }}${{ env.ARCH_SUFFIX }}.exe
|
||||||
asset_name: OrcaSlicer_Windows_Installer${{ env.ARCH_SUFFIX }}_nightly.exe
|
asset_name: OrcaSlicer_Windows_Installer${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}.exe
|
||||||
asset_content_type: application/x-msdownload
|
asset_content_type: application/x-msdownload
|
||||||
max_releases: 1
|
max_releases: 1
|
||||||
|
|
||||||
@@ -696,13 +701,13 @@ jobs:
|
|||||||
path: './build/src/dev-utils/Release/generate_system_cache'
|
path: './build/src/dev-utils/Release/generate_system_cache'
|
||||||
|
|
||||||
- name: Deploy Ubuntu release
|
- name: Deploy Ubuntu release
|
||||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && github.ref == 'refs/heads/main' && runner.os == 'Linux' && !vars.SELF_HOSTED }}
|
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && env.deploy_nightly == 'true' && runner.os == 'Linux' && !vars.SELF_HOSTED }}
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
with:
|
with:
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
release_id: 137995723
|
release_id: 137995723
|
||||||
asset_path: ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage
|
asset_path: ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage
|
||||||
asset_name: OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_nightly.AppImage
|
asset_name: OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_nightly${{ env.nightly_suffix }}.AppImage
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
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 Ubuntu release
|
- name: Deploy Ubuntu release
|
||||||
|
|||||||
@@ -74,26 +74,12 @@ jobs:
|
|||||||
set +e
|
set +e
|
||||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 2>&1 | tee ${{ runner.temp }}/validate_system.log
|
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 2>&1 | tee ${{ runner.temp }}/validate_system.log
|
||||||
exit ${PIPESTATUS[0]}
|
exit ${PIPESTATUS[0]}
|
||||||
# The validator above is the nightly build of main, so it cannot slice profiles that use
|
|
||||||
# settings a PR adds to the engine: it reports their placeholders as undefined. A PR that
|
|
||||||
# changes src/ also runs Build all, whose Slice check runs this same sweep with the
|
|
||||||
# validator built from the PR, so the sweep below only runs for the other PRs.
|
|
||||||
- name: Detect engine changes
|
|
||||||
id: engine_changes
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
run: |
|
|
||||||
base=${{ github.event.pull_request.base.sha }}
|
|
||||||
if git fetch --no-tags --depth=1 origin "$base" && ! git diff --quiet "$base" HEAD -- src/; then
|
|
||||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "::notice::This PR changes src/, so Build all's Slice check slices the profiles with the PR-built validator."
|
|
||||||
fi
|
|
||||||
# Slice a two-colour cube through every printer, and through every system process/filament whose
|
# Slice a two-colour cube through every printer, and through every system process/filament whose
|
||||||
# templates no printer's own slice reaches, so every custom g-code and filename_format shipped is
|
# templates no printer's own slice reaches, so every custom g-code and filename_format shipped is
|
||||||
# expanded (names in {if} branches not taken included) - catches undefined-placeholder /
|
# expanded (names in {if} branches not taken included) - catches undefined-placeholder /
|
||||||
# invalid-flow bugs the static checks above cannot see.
|
# invalid-flow bugs the static checks above cannot see.
|
||||||
- name: validate slice (expand custom g-code)
|
- name: validate slice (expand custom g-code)
|
||||||
id: validate_slice
|
id: validate_slice
|
||||||
if: ${{ steps.engine_changes.outputs.changed != 'true' }}
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
set +e
|
set +e
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ If you come across any of these in search results, please <b>report them</b> as
|
|||||||
Regular updates fueled by continuous community contributions.
|
Regular updates fueled by continuous community contributions.
|
||||||
- **Wide Printer Compatibility**
|
- **Wide Printer Compatibility**
|
||||||
Supports a broad range of printers: Bambu Lab, Prusa, Creality, Voron, and more.
|
Supports a broad range of printers: Bambu Lab, Prusa, Creality, Voron, and more.
|
||||||
- **[Belt Printer Support](https://www.orcaslicer.com/wiki/belt_printing)**
|
|
||||||
Slice for belt / conveyor (infinite-Z) printers, with belt-aware supports and a tilted-bed preview. Contributed by [Joseph Robertson (@HarrierPigeon)](https://github.com/HarrierPigeon).
|
|
||||||
- Additional features can be found in the [change notes](https://github.com/OrcaSlicer/OrcaSlicer/releases/).
|
- Additional features can be found in the [change notes](https://github.com/OrcaSlicer/OrcaSlicer/releases/).
|
||||||
|
|
||||||
# Wiki
|
# Wiki
|
||||||
@@ -91,6 +89,17 @@ Visit our GitHub Releases page for the latest stable version of OrcaSlicer, reco
|
|||||||
🌙 **[Download the Latest Nightly Build](https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds)**
|
🌙 **[Download the Latest Nightly Build](https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds)**
|
||||||
Explore the latest developments in OrcaSlicer with our nightly builds. Feedback on these versions is highly appreciated.
|
Explore the latest developments in OrcaSlicer with our nightly builds. Feedback on these versions is highly appreciated.
|
||||||
|
|
||||||
|
### Belt Printer Builds
|
||||||
|
|
||||||
|
The [nightly release](https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds) ships **two parallel builds**: the standard build and a belt-printer build. Both are attached to the same release — tell them apart by the filename suffix:
|
||||||
|
|
||||||
|
- **Standard** — no suffix (e.g. `OrcaSlicer_Windows_Installer_x64_nightly.exe`)
|
||||||
|
- **Belt** — `_belt` suffix (e.g. `OrcaSlicer_Windows_Installer_x64_nightly_belt.exe`)
|
||||||
|
|
||||||
|
The `_belt` builds add **experimental support for belt / conveyor (infinite-Z) printers**, where the model is sliced against a tilted belt surface instead of a flat horizontal bed. They include ready-to-use belt printer profiles, the full belt slicing pipeline (mesh rotation and G-code transforms), belt-aware support generation, and a tilted-bed preview.
|
||||||
|
|
||||||
|
> ⚠️ Belt printer support is under active development and is **not yet merged into `main`** — it currently ships only in these parallel `_belt` builds, produced from the [`belt-printer`](https://github.com/OrcaSlicer/OrcaSlicer/tree/belt-printer) branch. See tracking PR [#14394](https://github.com/OrcaSlicer/OrcaSlicer/pull/14394) and the original documentation in [#12998](https://github.com/OrcaSlicer/OrcaSlicer/pull/12998).
|
||||||
|
|
||||||
# How to install
|
# How to install
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|||||||
Vendored
-29
@@ -44,18 +44,6 @@ else()
|
|||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(_conf_cmd export MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} && ./Configure -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET})
|
set(_conf_cmd export MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} && ./Configure -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET})
|
||||||
else()
|
else()
|
||||||
# A static library that is embedded into a shared object must not export
|
|
||||||
# its symbols. On Linux the running process also loads the system OpenSSL
|
|
||||||
# 3.x (WebKitGTK/gnutls pull in libcrypto.so.3), and CPython's _ssl and
|
|
||||||
# _hashlib are dlopened (RTLD_LOCAL) DSOs that each embed this OpenSSL.
|
|
||||||
# With default visibility their unversioned OpenSSL references are
|
|
||||||
# preempted by that global 3.x copy, mixing the 1.1.1 and 3.x ABIs and
|
|
||||||
# corrupting the heap (ssl.create_default_context() aborts). Hidden
|
|
||||||
# visibility makes each embedded copy self-contained. Linux-only: macOS
|
|
||||||
# binds dylibs with a two-level namespace (no interposition) and ships no
|
|
||||||
# OpenSSL, and Windows has no equivalent flag and no system OpenSSL to
|
|
||||||
# collide with.
|
|
||||||
set(_openssl_extra_cflags -fvisibility=hidden)
|
|
||||||
set(_conf_cmd env "CC=${CMAKE_C_COMPILER}" "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS}" "./config")
|
set(_conf_cmd env "CC=${CMAKE_C_COMPILER}" "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS}" "./config")
|
||||||
endif()
|
endif()
|
||||||
set(_cross_comp_prefix_line "")
|
set(_cross_comp_prefix_line "")
|
||||||
@@ -114,20 +102,3 @@ ExternalProject_Add_Step(dep_OpenSSL install_cmake_files
|
|||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory openssl "${DESTDIR}${CMAKE_INSTALL_LIBDIR}/cmake/openssl"
|
COMMAND ${CMAKE_COMMAND} -E copy_directory openssl "${DESTDIR}${CMAKE_INSTALL_LIBDIR}/cmake/openssl"
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
|
||||||
# OpenSSL's object rules do not depend on CFLAGS, so reconfiguring it (for
|
|
||||||
# example to add -fvisibility=hidden) relinks the archives from stale
|
|
||||||
# objects instead of recompiling them, and the change silently has no
|
|
||||||
# effect. Drop the objects whenever this recipe changes so the next build
|
|
||||||
# actually recompiles them.
|
|
||||||
ExternalProject_Get_Property(dep_OpenSSL SOURCE_DIR)
|
|
||||||
ExternalProject_Add_Step(dep_OpenSSL clean_objects
|
|
||||||
DEPENDEES configure
|
|
||||||
DEPENDERS build
|
|
||||||
COMMAND make clean
|
|
||||||
WORKING_DIRECTORY "${SOURCE_DIR}"
|
|
||||||
DEPENDS "${CMAKE_CURRENT_LIST_FILE}"
|
|
||||||
COMMENT "OpenSSL: cleaning objects after a recipe change"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
|
|||||||
Vendored
-24
@@ -299,27 +299,3 @@ endif()
|
|||||||
if(TARGET dep_ZLIB)
|
if(TARGET dep_ZLIB)
|
||||||
add_dependencies(dep_python3 dep_ZLIB)
|
add_dependencies(dep_python3 dep_ZLIB)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
|
||||||
# CPython's Makefile rules for _ssl and _hashlib depend only on their own
|
|
||||||
# sources, not on the OpenSSL archives, so a rebuilt OpenSSL does not make
|
|
||||||
# them relink and they keep the previous symbols. On an incremental tree,
|
|
||||||
# drop the built modules and relink them against the current OpenSSL; a
|
|
||||||
# fresh build is left alone (its PGO target builds them). "make" alone is a
|
|
||||||
# no-op once PGO has run, so sharedmods is invoked explicitly.
|
|
||||||
ExternalProject_Get_Property(dep_python3 SOURCE_DIR)
|
|
||||||
file(GLOB _python_ssl_modules
|
|
||||||
"${SOURCE_DIR}/Modules/_ssl*.so"
|
|
||||||
"${SOURCE_DIR}/Modules/_hashlib*.so")
|
|
||||||
if (_python_ssl_modules)
|
|
||||||
ExternalProject_Add_Step(dep_python3 relink_ssl_extensions
|
|
||||||
DEPENDEES configure
|
|
||||||
DEPENDERS build
|
|
||||||
COMMAND sh -c "rm -f '${SOURCE_DIR}'/Modules/_ssl*.so '${SOURCE_DIR}'/Modules/_hashlib*.so && make -j${NPROC} sharedmods"
|
|
||||||
WORKING_DIRECTORY "${SOURCE_DIR}"
|
|
||||||
COMMENT "CPython: relinking _ssl/_hashlib against the current OpenSSL"
|
|
||||||
DEPENDS "${CMAKE_CURRENT_LIST_FILE}"
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/../OpenSSL/OpenSSL.cmake"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|||||||
@@ -88,18 +88,6 @@ struct NfpPConfig {
|
|||||||
*/
|
*/
|
||||||
bool explore_holes = false;
|
bool explore_holes = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Keep the final pile on the bin.
|
|
||||||
*
|
|
||||||
* The final alignment centres the pile on the alignment target. A target
|
|
||||||
* near an edge (a belt printer starts its parts at the leading end of the
|
|
||||||
* belt) would push part of a pile that is larger than the room around that
|
|
||||||
* point off the bed; with this set the pile stops at the edge instead, and a
|
|
||||||
* pile that does not fit along an axis is centred on it. Off by default, so
|
|
||||||
* the alignment of every other printer is unchanged.
|
|
||||||
*/
|
|
||||||
bool clamp_to_bin = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief If true, use all CPUs available. Run on a single core otherwise.
|
* @brief If true, use all CPUs available. Run on a single core otherwise.
|
||||||
*/
|
*/
|
||||||
@@ -1123,24 +1111,7 @@ private:
|
|||||||
default: ; // DONT_ALIGN
|
default: ; // DONT_ALIGN
|
||||||
}
|
}
|
||||||
|
|
||||||
auto d = cb - ci;
|
auto d = cb - ci;
|
||||||
|
|
||||||
// Keep the pile on the bin (see Config::clamp_to_bin). The items' boxes carry
|
|
||||||
// their inflation, which is the margin left at the edge.
|
|
||||||
if (config_.clamp_to_bin) {
|
|
||||||
auto on_bin = [](Coord lo, Coord hi, Coord bin_lo, Coord bin_hi, Coord shift) {
|
|
||||||
if (hi - lo >= bin_hi - bin_lo)
|
|
||||||
return (bin_lo + bin_hi) / 2 - (lo + hi) / 2;
|
|
||||||
if (lo + shift < bin_lo)
|
|
||||||
shift = bin_lo - lo;
|
|
||||||
if (hi + shift > bin_hi)
|
|
||||||
shift = bin_hi - hi;
|
|
||||||
return shift;
|
|
||||||
};
|
|
||||||
setX(d, on_bin(getX(bb.minCorner()), getX(bb.maxCorner()), getX(bbin.minCorner()), getX(bbin.maxCorner()), getX(d)));
|
|
||||||
setY(d, on_bin(getY(bb.minCorner()), getY(bb.maxCorner()), getY(bbin.minCorner()), getY(bbin.maxCorner()), getY(d)));
|
|
||||||
cb = ci + d;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BBS make sure the item won't clash with excluded regions
|
// BBS make sure the item won't clash with excluded regions
|
||||||
// do we have wipe tower after arranging?
|
// do we have wipe tower after arranging?
|
||||||
|
|||||||
@@ -1,221 +0,0 @@
|
|||||||
# Adaptive TPMS infill — High Level Design
|
|
||||||
|
|
||||||
## Purpose and scope
|
|
||||||
|
|
||||||
`tpms_adaptive` grades the sparse infill of the Gyroid, TPMS-D and TPMS-FK
|
|
||||||
patterns inside the object: the cells grow continuously from the surface
|
|
||||||
towards the center of the object. `distance_warp`, `smooth_blend` and
|
|
||||||
`stepped_shells` follow the distance to the nearest surface, including the top
|
|
||||||
and bottom, like concentric shells; `lobes` follows the whole 3D shape towards
|
|
||||||
the center of each lobe of the object; `normal_z`, `normal_y` and `normal_x`
|
|
||||||
follow each section of the object normal to that axis, so the grading does not
|
|
||||||
change along the axis, as suits a profile extruded along it.
|
|
||||||
`sparse_infill_density` is the density at the surface, `tpms_interior_density`
|
|
||||||
the density at the center, and `tpms_adaptive_gradient` picks how the density
|
|
||||||
goes from one to the other. Only internal sparse infill is graded; the Gyroid
|
|
||||||
Z-buckling optimization does not apply to it.
|
|
||||||
|
|
||||||
The design has two parts: a field built once per object, and a pattern made
|
|
||||||
from it, warped around the center of each lobe of a body so that its cell size
|
|
||||||
follows the field, or, in the modes following the distance to the surface,
|
|
||||||
split into shells or blended between densities.
|
|
||||||
|
|
||||||
## Radial field
|
|
||||||
|
|
||||||
`TpmsRadialField` gives every point of an object the center of its lobe and a
|
|
||||||
radial coordinate: 0 at the center, 1 at the surface along the ray from the
|
|
||||||
center. `PrintObject::prepare_tpms_radial_fields()` builds it in
|
|
||||||
`bridge_over_infill()`, next to the adaptive cubic octree, because the anchoring
|
|
||||||
infill generated there has to match the printed infill. A field is built for
|
|
||||||
every mode a region uses, and is shared by the regions using that mode: the
|
|
||||||
field depends on the geometry only, the densities are applied per region in the
|
|
||||||
fill. An object thinner than the grid cells has no body in the field; no field
|
|
||||||
is kept then, and the infill falls back to the regular pattern. In the modes
|
|
||||||
following the distance to the surface, the field also gives the depth of every
|
|
||||||
point (see below).
|
|
||||||
|
|
||||||
A regular 3D grid of cubic cells is rasterized from the `lslices` of the layers,
|
|
||||||
so the field follows what is printed: negative volumes, the union of
|
|
||||||
overlapping parts and holes are taken into account, and the mesh does not need
|
|
||||||
to be closed. A padding node around the grid is always outside. The grid is
|
|
||||||
capped at about a million nodes, with cells no smaller than 0.5 mm.
|
|
||||||
|
|
||||||
- Bodies are the connected inside nodes. Each is graded on its own, so separate
|
|
||||||
parts of one object each get their own sparse center.
|
|
||||||
- A body is split into lobes around the local maxima of the depth, by an exact
|
|
||||||
Euclidean distance transform (Felzenszwalb and Huttenlocher, one pass per
|
|
||||||
axis). Two maxima are in separate lobes when the depth along the segment
|
|
||||||
between them drops below 0.8 of the shallower one, like at the neck between
|
|
||||||
two united spheres; maxima shallower than 0.3 of the deepest one are ignored.
|
|
||||||
A maximum joins the first lobe whose first maximum it sees without a neck.
|
|
||||||
The lobes are made one at a time, the remaining maxima tested against the
|
|
||||||
first one in parallel, as a plate has a whole plane of them.
|
|
||||||
Where the depth ties along a line or a plane, as in a tall box, the lobe's
|
|
||||||
center is the node nearest to the middle of the tied nodes, so the center is
|
|
||||||
in the middle of the height and not a column.
|
|
||||||
- A point belongs to the lobe it is nearest to relative to their depths, so the
|
|
||||||
side between two lobes is nearer to the smaller one. Near that side, within a
|
|
||||||
tenth of that relative distance, the patterns of the lobes morph into each
|
|
||||||
other, so the lines stay continuous. Every lobe in that range takes part, up
|
|
||||||
to four, so the morph is also continuous where three or four lobes meet.
|
|
||||||
- The reach of a lobe is the distance from its center to the first exit along
|
|
||||||
24 x 48 latitude-longitude directions, smoothed twice over neighbouring
|
|
||||||
directions in log space. Towards a neighbouring lobe it stops at twice the
|
|
||||||
distance to the side between them, so that side is graded half way, as deep
|
|
||||||
as a neck is, rather than as sparse as the center or as dense as the surface.
|
|
||||||
Only the lobes whose centers are near enough to be nearer at the current
|
|
||||||
distance are compared along a ray, so many lobes, as in a perforated plate,
|
|
||||||
stay cheap.
|
|
||||||
The radial coordinate of a point is its distance to the center over the reach
|
|
||||||
in its direction. Behind a gap, as across the hole
|
|
||||||
of a ring, the radial coordinate is above 1 and the infill keeps the surface
|
|
||||||
density.
|
|
||||||
- Every outside node belongs to its nearest body, so points near a surface find
|
|
||||||
their body without a search. With a single body, all nodes belong to it.
|
|
||||||
|
|
||||||
In the 2D modes, every plane of nodes normal to the axis is a field of its own:
|
|
||||||
the distance transform skips the axis, bodies, lobes and the nearest body are
|
|
||||||
found within the plane, and the reach is sampled on a circle of 48 directions.
|
|
||||||
A point is looked up in the two planes around it, the weights of their lobes
|
|
||||||
interpolated along the axis, so the grading does not step between planes; a
|
|
||||||
plane without a body uses the nearest one that has one. The planes are a cell
|
|
||||||
apart, not a layer: where the sections change abruptly, as at a step, the
|
|
||||||
patterns of the two planes morph into each other over that cell.
|
|
||||||
|
|
||||||
A distance to the nearest surface would be the obvious field, but no smooth map
|
|
||||||
follows it. By the divergence theorem, the mean scale of a map over a body is
|
|
||||||
fixed by its values on the surface: a map that keeps the full density along the
|
|
||||||
whole surface, as the distance would ask under the top and bottom, has the mean
|
|
||||||
density of the uniform infill, the sparser core being paid for by lines crowding
|
|
||||||
along the walls. The layers of a plate at different depths would also need
|
|
||||||
different line spacings in the same directions, which no continuous map allows
|
|
||||||
without shearing across the plate. Following the distance needs changes of the
|
|
||||||
topology of the lattice (see below). The radial coordinate instead grades what a
|
|
||||||
single map can: towards one point.
|
|
||||||
|
|
||||||
## Warped pattern
|
|
||||||
|
|
||||||
The pattern is evaluated on warped coordinates:
|
|
||||||
|
|
||||||
TPMS(f_surface * m(t) * (p - center))
|
|
||||||
|
|
||||||
where `m` scales the pattern around the center of the lobe: its frequency is
|
|
||||||
`m + t * m'` along the ray and `m` across it. `m(t)` is the mean of the target
|
|
||||||
scale over the ball of radius `t`, `3 / t^3 * integral of s^2 * target(s) ds`, so
|
|
||||||
the mean of the three, and with it the density, follows the gradient. The cells
|
|
||||||
are round at the center; near the surface they are flattened, with the lines
|
|
||||||
running parallel to it. Beyond the surface the target is the surface scale, so
|
|
||||||
the warp extends continuously outside.
|
|
||||||
|
|
||||||
In the 2D modes only the coordinates within the plane are warped, and `m(t)` is
|
|
||||||
the mean over the disc, `2 / t^2 * integral of s * target(s) ds`. Along the axis
|
|
||||||
the pattern keeps the interior frequency: scaling it with `m` would shear the
|
|
||||||
pattern by the distance along the axis times the gradient of `m`, without bound
|
|
||||||
on a long object. The cells are round at the center and stretched along the
|
|
||||||
axis near the surface. With Normal Z the layers are graded exactly, since
|
|
||||||
the lines of a layer follow its in-plane frequencies; normal to X or Y, the
|
|
||||||
layers near the sides are as dense as the larger of the two frequencies in the
|
|
||||||
layer, which is the surface one.
|
|
||||||
|
|
||||||
Evaluating a TPMS at a frequency that varies with the position without such a
|
|
||||||
map distorts it wherever the frequency changes, because the phase also changes
|
|
||||||
with the gradient of the frequency times the distance from the origin. Fitting a
|
|
||||||
smooth map to a varying isotropic scale in the least-squares sense (a Poisson
|
|
||||||
problem per axis) cannot grade strongly: its divergence is the target scale plus
|
|
||||||
a harmonic function pinned by the surface, which keeps the scale in the core
|
|
||||||
near two thirds of the surface one. Following a distance exactly needs the
|
|
||||||
lattice to change its topology, by blending lattices of different densities or
|
|
||||||
filling shells of equal distance with them, as the modes following the distance
|
|
||||||
to the surface do.
|
|
||||||
|
|
||||||
The target scale at depth `d = 1 - t`, with `S` the surface and `I` the interior
|
|
||||||
frequency, both from each pattern's own density calibration:
|
|
||||||
|
|
||||||
| Gradient | Scale |
|
|
||||||
|-------------|------------------------|
|
|
||||||
| Linear | `1 + (I / S - 1) * d` |
|
|
||||||
| Quadratic | `1 + (I / S - 1) * d^2`|
|
|
||||||
| Exponential | `(I / S)^d` |
|
|
||||||
|
|
||||||
With a denser surface, quadratic keeps the surface density deepest and
|
|
||||||
exponential drops fastest. A denser interior works the same way.
|
|
||||||
|
|
||||||
The zero level is extracted with marching squares like the regular TPMS-FK, on
|
|
||||||
a sampling grid fixed in the fill frame like the optimized Gyroid, so that every
|
|
||||||
region of a layer connects its lines the same way at the saddles of the pattern.
|
|
||||||
Loops narrower than two lines (shorter than `2 * PI * spacing`) are dropped, as
|
|
||||||
they would print as blobs. The fill works in a frame rotated by the infill
|
|
||||||
angle, so the radial field is looked up at the point rotated back into the
|
|
||||||
object frame, and the center rotated into the fill frame. Both use the middle of
|
|
||||||
the layer.
|
|
||||||
|
|
||||||
## Modes following the distance to the surface
|
|
||||||
|
|
||||||
`distance_warp`, `smooth_blend` and `stepped_shells` grade by the distance to
|
|
||||||
the nearest surface, including the top and bottom, as concentric shells do. The
|
|
||||||
depth of a point is that distance over the distance of the deepest point of its
|
|
||||||
body, from 0 at the surface to 1; the field keeps it for every node and
|
|
||||||
interpolates it between them. A tall box so keeps its whole axis as sparse as
|
|
||||||
its center, and a plate is graded through its thickness.
|
|
||||||
|
|
||||||
No single smooth pattern follows that depth without distortion (see above), so
|
|
||||||
the three modes trade differently:
|
|
||||||
|
|
||||||
- Distance warp keeps the lobes and the warp of Lobes, but its radial profile
|
|
||||||
comes from the depth. For every direction of a lobe, the mean depth over the
|
|
||||||
ball along the ray is sampled at 33 radii up to the reach, then smoothed over
|
|
||||||
the neighbouring directions like the reach. The radial coordinate is the one
|
|
||||||
of the linear profile with the same mean depth, `t = 4/3 * (1 - mean depth)`,
|
|
||||||
so with a linear gradient the mean cell size follows the depth exactly, and
|
|
||||||
with the others approximately. In a sphere or a cube, where the depth falls
|
|
||||||
linearly along every ray, it is Lobes. Elsewhere the profile changes with the
|
|
||||||
direction, and the warp shears where neighbouring directions differ, as in
|
|
||||||
plates and long bodies; right under the top of a long body the cells are
|
|
||||||
sparser within the layer, the warp moving their density into the height.
|
|
||||||
The profiles are smoothed over the directions like the reach, as sharper
|
|
||||||
ones shear the pattern across the layer, which adds lines. A long body is so
|
|
||||||
graded partly along its length, between Lobes and the distance.
|
|
||||||
- Smooth blend evaluates the regular patterns of the two levels around the
|
|
||||||
target of every point and blends them by a smoothstep over the whole gap
|
|
||||||
between the levels, here at most 2.5 times apart. The density follows the
|
|
||||||
depth without steps, but where two lattices blend, part of their lines run
|
|
||||||
along the blend, so fewer levels print fewer extra lines. From 25% to 5%,
|
|
||||||
three levels print about 0.45 of the uniform infill in a deep core whose
|
|
||||||
levels alone would print 0.3; levels 1.5 times apart print 0.6 to 0.7, and a
|
|
||||||
single blend from the surface to the interior 0.6.
|
|
||||||
- Stepped shells split each region of a layer into shells and fill every shell
|
|
||||||
with the regular pattern at its density. The densities are levels from the
|
|
||||||
surface to the interior density at most 1.5 times apart, five from 25% to 5%,
|
|
||||||
and a point takes the level nearest to its target on that geometric scale.
|
|
||||||
The shells are traced by marching squares of the continuous level over the
|
|
||||||
layer on a 0.5 mm grid fixed in the object, so every region of a layer gets
|
|
||||||
the same shells, and clipped to the region. Each shell is shrunk by half a
|
|
||||||
line, like a filled region, and its regular filler connects its lines along
|
|
||||||
that boundary, so the connections of two neighbouring shells lie side by side
|
|
||||||
instead of on top of each other. The pattern is never
|
|
||||||
distorted, but its lines end at every shell, and thin parts get thin shells.
|
|
||||||
The connections add lines: in the core of a 60 mm cube, about a third more
|
|
||||||
than the target.
|
|
||||||
|
|
||||||
Stepped shells and Smooth blend need neither lobes nor reaches, which are not
|
|
||||||
built for them.
|
|
||||||
|
|
||||||
## Constraints
|
|
||||||
|
|
||||||
- With `tpms_adaptive` disabled, or for other patterns, the fill parameters are reset
|
|
||||||
to their defaults, so they neither change the infill nor split fill batches.
|
|
||||||
- `Layer::get_sparse_infill_max_void_area()` uses the sparser of the two
|
|
||||||
densities, as the voids at the center are that large.
|
|
||||||
- At a sparse infill density of 100% the sparse infill is turned into solid
|
|
||||||
infill, so there is nothing to grade: the options are hidden and no field is
|
|
||||||
built.
|
|
||||||
- The adaptive options invalidate `posPrepareInfill`, which rebuilds the field
|
|
||||||
and the anchoring infill.
|
|
||||||
- An elongated body without a neck has one center, so its far ends are graded
|
|
||||||
as the outer part of the body, and the warp shears where the reach changes
|
|
||||||
quickly with the direction. A concave body, like an L, may be split into lobes
|
|
||||||
where its maxima cannot see each other in a straight line.
|
|
||||||
- Across a ray, the scale is the mean of the gradient from the center, so the
|
|
||||||
layers right under the top and above the bottom are sparser than the surface
|
|
||||||
density in their middle, and a plate is graded from its middle outwards rather
|
|
||||||
than through its thickness.
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,79 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Belt temperature-tower asset generator (discrete-provini design).
|
|
||||||
|
|
||||||
A vertical temperature tower cannot be sliced on a belt printer, so lay a row of
|
|
||||||
DISCRETE provini (one per temperature) along the belt (designed Y) with a fixed
|
|
||||||
surface gap. Each provino is the chevron+arc unit (belt_temp_provino_unit.stl,
|
|
||||||
keel-first); its temperature is ENGRAVED upright into the 50 mm face — a raised
|
|
||||||
number would be an unsupported overhang on the belt. The C++ calib_temp belt branch
|
|
||||||
(Plater.cpp) injects one M104 per zone 70 layers INTO provino i:
|
|
||||||
print_z[i] = i * PITCH * cos(theta) + 70 * layer_height (theta = 45)
|
|
||||||
inside the body, not in the empty inter-provino gap (which has no sliced layers for
|
|
||||||
the event to attach to). PITCH below is the shared geometry contract with that code —
|
|
||||||
keep them in sync.
|
|
||||||
|
|
||||||
Generates one STL per filament temp range used by Temp_Calibration_Dlg.
|
|
||||||
"""
|
|
||||||
import numpy as np, trimesh, os
|
|
||||||
from matplotlib.textpath import TextPath
|
|
||||||
from matplotlib.font_manager import FontProperties
|
|
||||||
from shapely.geometry import Polygon as ShPoly
|
|
||||||
from shapely.ops import unary_union
|
|
||||||
|
|
||||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
UNIT = os.path.join(HERE, 'belt_temp_provino_unit.stl') # single provino, keel-first
|
|
||||||
SURF_GAP = 25.0 # surface-to-surface gap between provini (mm) — user spec
|
|
||||||
TEXT_H = 9.0
|
|
||||||
TEXT_DEPTH = 0.8 # engraving depth (numbers are CUT into the face, not raised:
|
|
||||||
# a raised number is an unsupported Y-overhang on the belt)
|
|
||||||
TEXT_OVERSHOOT = 0.6 # extra height poking out of the face for a clean boolean cut
|
|
||||||
|
|
||||||
# Temperature ranges (start, end) per filament family, 5 C step. File name encodes them.
|
|
||||||
RANGES = [(230,190),(270,230),(250,230),(280,240),(240,210),(320,280)]
|
|
||||||
|
|
||||||
unit = trimesh.load(UNIT)
|
|
||||||
dY = unit.bounds[1,1] - unit.bounds[0,1]
|
|
||||||
PITCH = dY + SURF_GAP # designed-Y pitch == C++ contract constant
|
|
||||||
print(f"unit dY={dY:.2f} PITCH={PITCH:.3f} (C++ contract: print_z[i]=i*{PITCH:.3f}*cos45)")
|
|
||||||
|
|
||||||
# 50 mm face normal (0,-1,1)/sqrt2 ; UPRIGHT basis u=+X det(+1) (verified non-mirrored)
|
|
||||||
n = np.array([0,-1,1.])/np.sqrt(2)
|
|
||||||
u = np.array([1,0,0.]); v = np.array([0,1,1.])/np.sqrt(2)
|
|
||||||
R = np.column_stack([u,v,n])
|
|
||||||
fn = unit.face_normals; fc = unit.triangles_center; fa = unit.area_faces
|
|
||||||
sel = (fn@n) > 0.9
|
|
||||||
face_c = (fc[sel]*fa[sel,None]).sum(0)/fa[sel].sum()
|
|
||||||
|
|
||||||
def text_mesh(s):
|
|
||||||
tp = TextPath((0,0), s, size=TEXT_H, prop=FontProperties(family='DejaVu Sans'))
|
|
||||||
rings = [ShPoly(p) for p in tp.to_polygons() if len(p)>=3]
|
|
||||||
rings.sort(key=lambda r:r.area, reverse=True)
|
|
||||||
used=[False]*len(rings); parts=[]
|
|
||||||
for i,o in enumerate(rings):
|
|
||||||
if used[i]: continue
|
|
||||||
holes=[]
|
|
||||||
for j in range(i+1,len(rings)):
|
|
||||||
if not used[j] and o.contains(rings[j]): holes.append(rings[j].exterior.coords); used[j]=True
|
|
||||||
parts.append(ShPoly(o.exterior.coords,holes)); used[i]=True
|
|
||||||
poly = unary_union(parts)
|
|
||||||
geoms = list(poly.geoms) if poly.geom_type=='MultiPolygon' else [poly]
|
|
||||||
m = trimesh.util.concatenate([trimesh.creation.extrude_polygon(g,height=TEXT_DEPTH+TEXT_OVERSHOOT) for g in geoms])
|
|
||||||
c = m.bounds.mean(axis=0); m.apply_translation([-c[0],-c[1],0]); return m
|
|
||||||
|
|
||||||
for t_start, t_end in RANGES:
|
|
||||||
temps = list(range(t_start, t_end-1, -5))
|
|
||||||
parts=[]
|
|
||||||
for i,T in enumerate(temps):
|
|
||||||
c = unit.copy(); c.apply_translation([0, i*PITCH, 0])
|
|
||||||
t = text_mesh(str(T)); M=np.eye(4); M[:3,:3]=R; t.apply_transform(M)
|
|
||||||
# place the text spanning from TEXT_DEPTH inside the face to TEXT_OVERSHOOT outside,
|
|
||||||
# then CUT it out of the provino (engrave) — no raised material, no Y-overhang.
|
|
||||||
t.apply_translation(face_c - n*TEXT_DEPTH + np.array([0,i*PITCH,0]))
|
|
||||||
c = trimesh.boolean.difference([c, t], engine='manifold')
|
|
||||||
parts.append(c)
|
|
||||||
asset = trimesh.util.concatenate(parts)
|
|
||||||
out = os.path.join(HERE, f"belt_temp_tower_{t_start}_{t_end}.stl")
|
|
||||||
asset.export(out)
|
|
||||||
dims = np.round(asset.bounds[1]-asset.bounds[0],1)
|
|
||||||
wt = all(p.is_watertight for p in parts)
|
|
||||||
print(f" {t_start}->{t_end}: {len(temps)} zones bbox={dims} watertight={wt} -> {os.path.basename(out)}")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M5.5,14.5c-1.105,0-2-3.686-2-7s.895-7,2-7" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><line x1="8.67" y1="4.67" x2="14.33" y2="10.33" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round"/><line x1="14.33" y1="4.67" x2="8.67" y2="10.33" style="fill:none;stroke:#949494;stroke-linecap:square;stroke-linejoin:round"/><path d="M3.5,13.7c-.294.511-.636.8-1,.8-1.1,0-2-3.686-2-7s.9-7,2-7c.365,0,.707.293,1,.805" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><path d="M6.727,4.5c.334-2.208,1-4,1.773-4,.354,0,.686.378.974,1" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/><path d="M9.474,13.5c-.288.622-.62,1-.974,1-.77,0-1.439-1.792-1.773-4" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 931 B |
@@ -10,7 +10,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000"
|
"4000"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000",
|
"4000",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000"
|
"4000"
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000"
|
"4000"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000",
|
"4000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000",
|
"4000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"4000",
|
"4000",
|
||||||
"4000",
|
"4000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000"
|
"10000"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"50",
|
"50",
|
||||||
"50"
|
"50"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000",
|
"10000",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000"
|
"10000"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"30",
|
"30",
|
||||||
"30"
|
"30"
|
||||||
],
|
],
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"default_acceleration": [
|
"default_acceleration": [
|
||||||
"10000",
|
"10000",
|
||||||
"10000"
|
"10000"
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "Custom Printer",
|
"name": "Custom Printer",
|
||||||
"version": "02.04.00.08",
|
"version": "02.04.00.07",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "My configurations",
|
"description": "My configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
{
|
|
||||||
"name": "Generic Belt Printer",
|
|
||||||
"sub_path": "machine/MyBeltPrinter.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Generic Klipper Printer",
|
"name": "Generic Klipper Printer",
|
||||||
"sub_path": "machine/MyKlipper.json"
|
"sub_path": "machine/MyKlipper.json"
|
||||||
@@ -54,10 +50,6 @@
|
|||||||
"name": "0.08mm Extra Fine @MyKlipper",
|
"name": "0.08mm Extra Fine @MyKlipper",
|
||||||
"sub_path": "process/0.08mm Extra Fine @MyKlipper.json"
|
"sub_path": "process/0.08mm Extra Fine @MyKlipper.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "0.12mm Fine @MyBeltPrinter",
|
|
||||||
"sub_path": "process/0.12mm Fine @MyBeltPrinter.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "0.12mm Fine @MyKlipper",
|
"name": "0.12mm Fine @MyKlipper",
|
||||||
"sub_path": "process/0.12mm Fine @MyKlipper.json"
|
"sub_path": "process/0.12mm Fine @MyKlipper.json"
|
||||||
@@ -70,10 +62,6 @@
|
|||||||
"name": "0.16mm Optimal @MyKlipper",
|
"name": "0.16mm Optimal @MyKlipper",
|
||||||
"sub_path": "process/0.16mm Optimal @MyKlipper.json"
|
"sub_path": "process/0.16mm Optimal @MyKlipper.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "0.20mm Standard @MyBeltPrinter",
|
|
||||||
"sub_path": "process/0.20mm Standard @MyBeltPrinter.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "0.20mm Standard @MyKlipper",
|
"name": "0.20mm Standard @MyKlipper",
|
||||||
"sub_path": "process/0.20mm Standard @MyKlipper.json"
|
"sub_path": "process/0.20mm Standard @MyKlipper.json"
|
||||||
@@ -274,10 +262,6 @@
|
|||||||
"name": "MyKlipper 0.8 nozzle",
|
"name": "MyKlipper 0.8 nozzle",
|
||||||
"sub_path": "machine/MyKlipper 0.8 nozzle.json"
|
"sub_path": "machine/MyKlipper 0.8 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"sub_path": "machine/fdm_belt_common.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "fdm_toolchanger_common",
|
"name": "fdm_toolchanger_common",
|
||||||
"sub_path": "machine/fdm_toolchanger_common.json"
|
"sub_path": "machine/fdm_toolchanger_common.json"
|
||||||
@@ -290,22 +274,6 @@
|
|||||||
"name": "MyRRF 0.4 nozzle",
|
"name": "MyRRF 0.4 nozzle",
|
||||||
"sub_path": "machine/MyRRF 0.4 nozzle.json"
|
"sub_path": "machine/MyRRF 0.4 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "MyBeltPrinter 0.2 nozzle",
|
|
||||||
"sub_path": "machine/MyBeltPrinter 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MyBeltPrinter 0.4 nozzle",
|
|
||||||
"sub_path": "machine/MyBeltPrinter 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MyBeltPrinter 0.6 nozzle",
|
|
||||||
"sub_path": "machine/MyBeltPrinter 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "MyBeltPrinter 0.8 nozzle",
|
|
||||||
"sub_path": "machine/MyBeltPrinter 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MyToolChanger 0.2 nozzle",
|
"name": "MyToolChanger 0.2 nozzle",
|
||||||
"sub_path": "machine/MyToolChanger 0.2 nozzle.json"
|
"sub_path": "machine/MyToolChanger 0.2 nozzle.json"
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "MyBeltPrinter 0.2 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "3w1uyJdmm14QhDnH",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "Generic Belt Printer",
|
|
||||||
"default_print_profile": "0.12mm Fine @MyBeltPrinter",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.2"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.16"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.04"
|
|
||||||
],
|
|
||||||
"printer_variant": "0.2",
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"350x0",
|
|
||||||
"350x350",
|
|
||||||
"0x350"
|
|
||||||
],
|
|
||||||
"printable_height": "300"
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "MyBeltPrinter 0.4 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "6nRHUtvJOUffocbu",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "Generic Belt Printer",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"350x0",
|
|
||||||
"350x350",
|
|
||||||
"0x350"
|
|
||||||
],
|
|
||||||
"printable_height": "300"
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "MyBeltPrinter 0.6 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "K0m9HbUNwKT4UCJV",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "Generic Belt Printer",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.6"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.12"
|
|
||||||
],
|
|
||||||
"printer_variant": "0.6",
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"350x0",
|
|
||||||
"350x350",
|
|
||||||
"0x350"
|
|
||||||
],
|
|
||||||
"printable_height": "300"
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "MyBeltPrinter 0.8 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "rHAweDz4eNwttPNA",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "Generic Belt Printer",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.6"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.2"
|
|
||||||
],
|
|
||||||
"printer_variant": "0.8",
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"350x0",
|
|
||||||
"350x350",
|
|
||||||
"0x350"
|
|
||||||
],
|
|
||||||
"printable_height": "300"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine_model",
|
|
||||||
"name": "Generic Belt Printer",
|
|
||||||
"model_id": "my_belt_01",
|
|
||||||
"nozzle_diameter": "0.4;0.2;0.6;0.8",
|
|
||||||
"machine_tech": "FFF",
|
|
||||||
"family": "MyPrinter",
|
|
||||||
"bed_model": "Custom_350_bed.stl",
|
|
||||||
"bed_texture": "orcaslicer_bed_texture.svg",
|
|
||||||
"hotend_model": "",
|
|
||||||
"default_materials": "Generic PLA @System;Generic PLA-CF @System;Generic PETG @System;Generic TPU @System;Generic PC @System;Generic PVA @System;Generic PA @System;Generic PA-CF @System"
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"inherits": "fdm_klipper_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"gcode_flavor": "klipper",
|
|
||||||
"single_extruder_multi_material": "0",
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @System"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @MyBeltPrinter",
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"extruder_colour": [
|
|
||||||
"#FCE94F"
|
|
||||||
],
|
|
||||||
"extruder_offset": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"long_retractions_when_cut": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retract_lift_above": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_below": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_enforce": [
|
|
||||||
"All Surfaces"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_cut": [
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"travel_slope": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"wipe_distance": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"z_hop_types": [
|
|
||||||
"Normal Lift"
|
|
||||||
],
|
|
||||||
"gcode_remap_x": "rev_x",
|
|
||||||
"gcode_remap_y": "pos_z",
|
|
||||||
"gcode_remap_z": "pos_y",
|
|
||||||
"belt_printer": "1",
|
|
||||||
"belt_slice_rotation": "x",
|
|
||||||
"belt_slice_rotation_angle": "45",
|
|
||||||
"build_plate_tilt_x": "45",
|
|
||||||
"purge_in_prime_tower": "0",
|
|
||||||
"scan_first_layer": "0",
|
|
||||||
"auxiliary_fan": "0"
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "0.12mm Fine @MyBeltPrinter",
|
|
||||||
"inherits": "fdm_process_klipper_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "EugqqdLJ423bgEwN",
|
|
||||||
"instantiation": "true",
|
|
||||||
"layer_height": "0.12",
|
|
||||||
"initial_layer_print_height": "0.12",
|
|
||||||
"bottom_shell_layers": "5",
|
|
||||||
"top_shell_layers": "6",
|
|
||||||
"support_top_z_distance": "0.08",
|
|
||||||
"support_bottom_z_distance": "0.08",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"skirt_distance": "0",
|
|
||||||
"compatible_printers": [
|
|
||||||
"MyBeltPrinter 0.2 nozzle",
|
|
||||||
"MyBeltPrinter 0.4 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "0.20mm Standard @MyBeltPrinter",
|
|
||||||
"inherits": "fdm_process_klipper_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "YzCDAgH3uLOM53pF",
|
|
||||||
"instantiation": "true",
|
|
||||||
"layer_height": "0.2",
|
|
||||||
"initial_layer_print_height": "0.2",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"skirt_distance": "0",
|
|
||||||
"compatible_printers": [
|
|
||||||
"MyBeltPrinter 0.4 nozzle",
|
|
||||||
"MyBeltPrinter 0.6 nozzle",
|
|
||||||
"MyBeltPrinter 0.8 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "IdeaFormer",
|
|
||||||
"version": "02.00.00.06",
|
|
||||||
"force_update": "0",
|
|
||||||
"description": "IdeaFormer belt printer configurations",
|
|
||||||
"machine_model_list": [
|
|
||||||
{
|
|
||||||
"name": "IdeaFormer IR3 V2",
|
|
||||||
"sub_path": "machine/IdeaFormer IR3 V2.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"process_list": [
|
|
||||||
{
|
|
||||||
"name": "fdm_process_common",
|
|
||||||
"sub_path": "process/fdm_process_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "0.20mm Standard @IdeaFormer IR3 V2",
|
|
||||||
"sub_path": "process/0.20mm Standard @IdeaFormer IR3 V2.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filament_list": [
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @IdeaFormer IR3 V2",
|
|
||||||
"sub_path": "filament/Generic PLA @IdeaFormer IR3 V2.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "eSUN PLA @IdeaFormer IR3 V2",
|
|
||||||
"sub_path": "filament/eSUN PLA @IdeaFormer IR3 V2.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG @IdeaFormer IR3 V2",
|
|
||||||
"sub_path": "filament/Generic PETG @IdeaFormer IR3 V2.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"machine_list": [
|
|
||||||
{
|
|
||||||
"name": "fdm_machine_common",
|
|
||||||
"sub_path": "machine/fdm_machine_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "fdm_klipper_common",
|
|
||||||
"sub_path": "machine/fdm_klipper_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"sub_path": "machine/fdm_belt_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "IdeaFormer IR3 V2 0.4 nozzle",
|
|
||||||
"sub_path": "machine/IdeaFormer IR3 V2 0.4 nozzle.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 183 KiB |
@@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @IdeaFormer IR3 V2",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "n4zaXcUUzTqAxq5f",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"IdeaFormer IR3 V2 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PETG"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"Generic"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"Generic PETG @IdeaFormer IR3 V2"
|
|
||||||
],
|
|
||||||
"filament_flow_ratio": [
|
|
||||||
"0.95"
|
|
||||||
],
|
|
||||||
"filament_cost": [
|
|
||||||
"25"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"240"
|
|
||||||
],
|
|
||||||
"nozzle_temperature_initial_layer": [
|
|
||||||
"245"
|
|
||||||
],
|
|
||||||
"cool_plate_temp": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"cool_plate_temp_initial_layer": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"overhang_fan_threshold": [
|
|
||||||
"25%"
|
|
||||||
],
|
|
||||||
"overhang_fan_speed": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"full_fan_speed_layer": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"slow_down_min_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"slow_down_layer_time": [
|
|
||||||
"4"
|
|
||||||
],
|
|
||||||
"fan_cooling_layer_time": [
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"filament_retraction_length": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"filament_retraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"filament_deretraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"filament_start_gcode": [
|
|
||||||
"; Generic PETG @IdeaFormer IR3 V2 — belt PETG, bed 80C"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @IdeaFormer IR3 V2",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "1xjycsEAFh6KQIhp",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"IdeaFormer IR3 V2 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PLA"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"Generic"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"Generic PLA @IdeaFormer IR3 V2"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"215"
|
|
||||||
],
|
|
||||||
"hot_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"hot_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"cool_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"cool_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"textured_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"textured_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"close_fan_the_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"full_fan_speed_layer": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"slow_down_min_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"filament_retraction_length": [
|
|
||||||
"1.5"
|
|
||||||
],
|
|
||||||
"filament_retraction_speed": [
|
|
||||||
"35"
|
|
||||||
],
|
|
||||||
"filament_deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"filament_start_gcode": [
|
|
||||||
"; Generic PLA @IdeaFormer IR3 V2 — belt PLA, bed 75C"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "eSUN PLA @IdeaFormer IR3 V2",
|
|
||||||
"inherits": "Generic PLA @IdeaFormer IR3 V2",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "XqkviBmFHEglXueX",
|
|
||||||
"filament_id": "OFkrxQC4",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"IdeaFormer IR3 V2 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PLA"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"eSUN"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"eSUN PLA @IdeaFormer IR3 V2"
|
|
||||||
],
|
|
||||||
"nozzle_temperature_initial_layer": [
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"enable_pressure_advance": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"pressure_advance": [
|
|
||||||
"0.12"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "IdeaFormer IR3 V2 0.4 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "MDQZgwRgg72lmjtu",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "IdeaFormer IR3 V2",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"250x0",
|
|
||||||
"250x2000",
|
|
||||||
"0x2000"
|
|
||||||
],
|
|
||||||
"printable_height": "250",
|
|
||||||
"belt_printer_infinite_y": "1",
|
|
||||||
"thumbnails": [
|
|
||||||
"48x48/PNG",
|
|
||||||
"300x300/PNG"
|
|
||||||
],
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @IdeaFormer IR3 V2"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @IdeaFormer IR3 V2",
|
|
||||||
"use_relative_e_distances": "1",
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"1000",
|
|
||||||
"1000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_travel": [
|
|
||||||
"9000",
|
|
||||||
"9000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_z": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_x": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_y": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_z": [
|
|
||||||
"0.4",
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"machine_max_speed_e": [
|
|
||||||
"60",
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"500",
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"500",
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"20",
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"retract_lift_below": [
|
|
||||||
"300"
|
|
||||||
],
|
|
||||||
"machine_start_gcode": "; === IdeaFormer IR3 V2 Belt Printer Start ===\n; Axes: X=lateral, Y=gantry height (probe), Z=belt\nG90 ; absolute positioning\nM82 ; absolute extruder\nG21 ; millimeters\nG28 ; home all axes\nG1 Y20 F500 ; lift nozzle 20mm from belt\n; Bed + hotend temps come from the active filament profile. Belt PLA requires 75 C bed — use Generic/eSun PLA @IdeaFormer IR3 V2 filament presets to get it automatically.\nM140 S[hot_plate_temp_initial_layer] ; set bed temp\nM104 S[nozzle_temperature_initial_layer] ; hotend temp\nM109 S[nozzle_temperature_initial_layer] ; wait hotend\nM190 S[hot_plate_temp_initial_layer] ; wait bed\n; --- Purge blob ---\nG92 E0 ; zero extruder\nG1 Y.1 ; nozzle 0.1mm above belt\nG1 E15 F1000 ; purge 15mm blob\nG1 Z20 E25 F800 ; belt advance 20mm + extrude\nG1 E23 ; retract 2mm\nG28 Y ; re-probe belt surface\nG1 E25 ; de-retract\n; --- Prime lines (full 250mm bed width) ---\nFMS_on ; filament motion sensor\nG1 X250 E50 F2000 ; prime line 1\nG92 Z0 ; reset belt origin\nG1 Z.4 ; belt advance 0.4mm\nG1 X0 E75 ; prime line 2\nG1 F1000 ; default feedrate\nG92 E0 Z0 ; zero extruder + belt = print origin\n",
|
|
||||||
"machine_end_gcode": "; === IdeaFormer IR3 V2 Belt Printer End ===\nM400 ; wait for moves to finish\nM104 S0 ; heater off\nM140 S0 ; bed off\nG92 E0 ; zero extruder\nG1 E-5 F300 ; retract 5mm\nG4 P5000 ; wait for ooze\nG91 ; relative mode - keep every end move relative on a belt\nG1 Y20 F1000 ; raise gantry 20mm for clearance over the part\nG1 Z676 F3000 ; advance belt one full machine-depth to eject the part and clean the belt\nG90 ; back to absolute\nG28 X ; home X only - NEVER 'G28' all: that homes Z/belt and reverses the whole print back into the gantry\nFMS_off ; filament motion sensor off\nBED_MESH_CLEAR\nM84 ; disable motors\n",
|
|
||||||
"machine_pause_gcode": "PAUSE",
|
|
||||||
"layer_change_gcode": "G92 E0 ; belt: reset extruder at layer change (relative E)"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine_model",
|
|
||||||
"name": "IdeaFormer IR3 V2",
|
|
||||||
"model_id": "IdeaFormer_IR3_V2",
|
|
||||||
"nozzle_diameter": "0.4",
|
|
||||||
"machine_tech": "FFF",
|
|
||||||
"family": "IdeaFormer",
|
|
||||||
"bed_model": "",
|
|
||||||
"bed_texture": "",
|
|
||||||
"hotend_model": "",
|
|
||||||
"default_materials": "Generic PLA @IdeaFormer IR3 V2;Generic PETG @IdeaFormer IR3 V2"
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"inherits": "fdm_klipper_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"gcode_flavor": "klipper",
|
|
||||||
"single_extruder_multi_material": "0",
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @System"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @IdeaFormer IR3 V2",
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"extruder_colour": [
|
|
||||||
"#FCE94F"
|
|
||||||
],
|
|
||||||
"extruder_offset": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"long_retractions_when_cut": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retract_lift_above": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_below": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_enforce": [
|
|
||||||
"All Surfaces"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_cut": [
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"travel_slope": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"wipe_distance": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"z_hop_types": [
|
|
||||||
"Normal Lift"
|
|
||||||
],
|
|
||||||
"gcode_remap_x": "rev_x",
|
|
||||||
"gcode_remap_y": "pos_z",
|
|
||||||
"gcode_remap_z": "pos_y",
|
|
||||||
"printer_extruder_id": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"belt_printer": "1",
|
|
||||||
"belt_slice_rotation": "x",
|
|
||||||
"belt_slice_rotation_angle": "45",
|
|
||||||
"build_plate_tilt_x": "45",
|
|
||||||
"purge_in_prime_tower": "0",
|
|
||||||
"scan_first_layer": "0",
|
|
||||||
"auxiliary_fan": "0"
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_klipper_common",
|
|
||||||
"inherits": "fdm_machine_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"gcode_flavor": "klipper",
|
|
||||||
"machine_max_acceleration_e": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_travel": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_z": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_e": [
|
|
||||||
"25",
|
|
||||||
"25"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_e": [
|
|
||||||
"2.5",
|
|
||||||
"2.5"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_x": [
|
|
||||||
"9",
|
|
||||||
"9"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_y": [
|
|
||||||
"9",
|
|
||||||
"9"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_z": [
|
|
||||||
"0.2",
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"machine_min_extruding_rate": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"machine_min_travel_rate": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"printable_height": "250",
|
|
||||||
"extruder_clearance_radius": "65",
|
|
||||||
"extruder_clearance_height_to_rod": "36",
|
|
||||||
"extruder_clearance_height_to_lid": "140",
|
|
||||||
"printer_settings_id": "",
|
|
||||||
"printer_technology": "FFF",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"z_hop_types": "Normal Lift",
|
|
||||||
"single_extruder_multi_material": "1",
|
|
||||||
"change_filament_gcode": "",
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @System"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @MyKlipper",
|
|
||||||
"bed_exclude_area": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"machine_start_gcode": "M190 S[bed_temperature_initial_layer_single]\nM109 S[nozzle_temperature_initial_layer]\nPRINT_START EXTRUDER=[nozzle_temperature_initial_layer] BED=[bed_temperature_initial_layer_single]\n",
|
|
||||||
"machine_end_gcode": "PRINT_END",
|
|
||||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
|
||||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
|
|
||||||
"machine_pause_gcode": "PAUSE",
|
|
||||||
"scan_first_layer": "0",
|
|
||||||
"nozzle_type": "undefine",
|
|
||||||
"auxiliary_fan": "0"
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_machine_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"printer_technology": "FFF",
|
|
||||||
"deretraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"extruder_colour": [
|
|
||||||
"#FCE94F"
|
|
||||||
],
|
|
||||||
"extruder_offset": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"gcode_flavor": "marlin",
|
|
||||||
"machine_max_acceleration_e": [
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"1000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_z": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_e": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_e": [
|
|
||||||
"5"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_x": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_y": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_z": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"machine_min_extruding_rate": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"machine_min_travel_rate": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"printable_height": "250",
|
|
||||||
"extruder_clearance_radius": "65",
|
|
||||||
"extruder_clearance_height_to_rod": "36",
|
|
||||||
"extruder_clearance_height_to_lid": "140",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"printer_settings_id": "",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"single_extruder_multi_material": "1",
|
|
||||||
"change_filament_gcode": "",
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"default_print_profile": "",
|
|
||||||
"machine_start_gcode": "G0 Z20 F9000\nG92 E0; G1 E-10 F1200\nG28\nM970 Q1 A10 B10 C130 K0\nM970 Q1 A10 B131 C250 K1\nM974 Q1 S1 P0\nM970 Q0 A10 B10 C130 H20 K0\nM970 Q0 A10 B131 C250 K1\nM974 Q0 S1 P0\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nG29 ;Home\nG90;\nG92 E0 ;Reset Extruder \nG1 Z2.0 F3000 ;Move Z Axis up \nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S205;\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder \nG1 X110 Y110 Z2.0 F3000 ;Move Z Axis up",
|
|
||||||
"machine_end_gcode": "M400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-4.0 F3600; retract \nG91\nG1 Z3;\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nG90 \nG0 X110 Y200 F3600 \nprint_end",
|
|
||||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
|
||||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
|
|
||||||
"machine_pause_gcode": "M601"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "0.20mm Standard @IdeaFormer IR3 V2",
|
|
||||||
"inherits": "fdm_process_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "91atcIwv5728phqX",
|
|
||||||
"instantiation": "true",
|
|
||||||
"layer_height": "0.2",
|
|
||||||
"initial_layer_print_height": "0.2",
|
|
||||||
"initial_layer_line_width": "0.42",
|
|
||||||
"wall_loops": "2",
|
|
||||||
"reduce_infill_retraction": "1",
|
|
||||||
"detect_overhang_wall": "1",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"skirt_distance": "0",
|
|
||||||
"sparse_infill_pattern": "grid",
|
|
||||||
"sparse_infill_speed": "200",
|
|
||||||
"support_base_pattern": "rectilinear",
|
|
||||||
"support_interface_pattern": "rectilinear",
|
|
||||||
"compatible_printers": [
|
|
||||||
"IdeaFormer IR3 V2 0.4 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "fdm_process_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"reduce_crossing_wall": "0",
|
|
||||||
"max_travel_detour_distance": "0",
|
|
||||||
"bottom_surface_pattern": "monotonic",
|
|
||||||
"bottom_shell_thickness": "0",
|
|
||||||
"bridge_speed": "50",
|
|
||||||
"brim_width": "5",
|
|
||||||
"brim_object_gap": "0.1",
|
|
||||||
"compatible_printers": [],
|
|
||||||
"compatible_printers_condition": "",
|
|
||||||
"print_sequence": "by layer",
|
|
||||||
"default_acceleration": "1000",
|
|
||||||
"initial_layer_acceleration": "500",
|
|
||||||
"top_surface_acceleration": "1000",
|
|
||||||
"travel_acceleration": "1000",
|
|
||||||
"inner_wall_acceleration": "1000",
|
|
||||||
"outer_wall_acceleration": "700",
|
|
||||||
"bridge_no_support": "0",
|
|
||||||
"draft_shield": "disabled",
|
|
||||||
"elefant_foot_compensation": "0",
|
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"wall_infill_order": "inner wall/outer wall/infill",
|
|
||||||
"infill_direction": "45",
|
|
||||||
"sparse_infill_density": "15%",
|
|
||||||
"sparse_infill_pattern": "crosshatch",
|
|
||||||
"initial_layer_print_height": "0.2",
|
|
||||||
"infill_combination": "0",
|
|
||||||
"infill_wall_overlap": "25%",
|
|
||||||
"interface_shells": "0",
|
|
||||||
"ironing_flow": "10%",
|
|
||||||
"ironing_spacing": "0.15",
|
|
||||||
"ironing_speed": "30",
|
|
||||||
"ironing_type": "no ironing",
|
|
||||||
"reduce_infill_retraction": "1",
|
|
||||||
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[initial_tool]}_{printer_model}_{print_time}.gcode",
|
|
||||||
"detect_overhang_wall": "1",
|
|
||||||
"slowdown_for_curled_perimeters": "1",
|
|
||||||
"overhang_1_4_speed": "0",
|
|
||||||
"overhang_2_4_speed": "50",
|
|
||||||
"overhang_3_4_speed": "30",
|
|
||||||
"overhang_4_4_speed": "10",
|
|
||||||
"line_width": "110%",
|
|
||||||
"inner_wall_line_width": "110%",
|
|
||||||
"outer_wall_line_width": "100%",
|
|
||||||
"top_surface_line_width": "93.75%",
|
|
||||||
"sparse_infill_line_width": "110%",
|
|
||||||
"initial_layer_line_width": "120%",
|
|
||||||
"internal_solid_infill_line_width": "120%",
|
|
||||||
"support_line_width": "96%",
|
|
||||||
"wall_loops": "3",
|
|
||||||
"print_settings_id": "",
|
|
||||||
"raft_layers": "0",
|
|
||||||
"seam_position": "aligned",
|
|
||||||
"skirt_distance": "2",
|
|
||||||
"skirt_height": "3",
|
|
||||||
"min_skirt_length": "4",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"minimum_sparse_infill_area": "15",
|
|
||||||
"spiral_mode": "0",
|
|
||||||
"standby_temperature_delta": "-5",
|
|
||||||
"enable_support": "0",
|
|
||||||
"resolution": "0.012",
|
|
||||||
"support_type": "normal(auto)",
|
|
||||||
"support_on_build_plate_only": "0",
|
|
||||||
"support_top_z_distance": "0.2",
|
|
||||||
"support_bottom_z_distance": "0.2",
|
|
||||||
"support_filament": "0",
|
|
||||||
"support_interface_loop_pattern": "0",
|
|
||||||
"support_interface_filament": "0",
|
|
||||||
"support_interface_top_layers": "2",
|
|
||||||
"support_interface_bottom_layers": "2",
|
|
||||||
"support_interface_spacing": "0.5",
|
|
||||||
"support_interface_speed": "80",
|
|
||||||
"support_base_pattern": "default",
|
|
||||||
"support_base_pattern_spacing": "2.5",
|
|
||||||
"support_speed": "150",
|
|
||||||
"support_threshold_angle": "30",
|
|
||||||
"support_object_xy_distance": "0.35",
|
|
||||||
"tree_support_branch_angle": "30",
|
|
||||||
"tree_support_wall_count": "0",
|
|
||||||
"detect_thin_wall": "0",
|
|
||||||
"top_surface_pattern": "monotonicline",
|
|
||||||
"top_shell_thickness": "0.8",
|
|
||||||
"enable_prime_tower": "1",
|
|
||||||
"wipe_tower_no_sparse_layers": "0",
|
|
||||||
"prime_tower_width": "60",
|
|
||||||
"xy_hole_compensation": "0",
|
|
||||||
"xy_contour_compensation": "0",
|
|
||||||
"layer_height": "0.2",
|
|
||||||
"bottom_shell_layers": "3",
|
|
||||||
"top_shell_layers": "4",
|
|
||||||
"bridge_flow": "1",
|
|
||||||
"initial_layer_speed": "45",
|
|
||||||
"initial_layer_infill_speed": "45",
|
|
||||||
"outer_wall_speed": "45",
|
|
||||||
"inner_wall_speed": "80",
|
|
||||||
"sparse_infill_speed": "150",
|
|
||||||
"internal_solid_infill_speed": "150",
|
|
||||||
"top_surface_speed": "50",
|
|
||||||
"gap_infill_speed": "30",
|
|
||||||
"travel_speed": "200"
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Printcepts",
|
|
||||||
"version": "01.00.00.04",
|
|
||||||
"force_update": "0",
|
|
||||||
"description": "Printcepts belt printer configurations",
|
|
||||||
"machine_model_list": [
|
|
||||||
{
|
|
||||||
"name": "BabyBelt Pro",
|
|
||||||
"sub_path": "machine/BabyBelt Pro.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"process_list": [
|
|
||||||
{
|
|
||||||
"name": "fdm_process_common",
|
|
||||||
"sub_path": "process/fdm_process_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "0.20mm Standard @BabyBelt Pro",
|
|
||||||
"sub_path": "process/0.20mm Standard @BabyBelt Pro.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filament_list": [
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @BabyBelt Pro",
|
|
||||||
"sub_path": "filament/Generic PLA @BabyBelt Pro.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "eSUN PLA @BabyBelt Pro",
|
|
||||||
"sub_path": "filament/eSUN PLA @BabyBelt Pro.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG @BabyBelt Pro",
|
|
||||||
"sub_path": "filament/Generic PETG @BabyBelt Pro.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"machine_list": [
|
|
||||||
{
|
|
||||||
"name": "fdm_machine_common",
|
|
||||||
"sub_path": "machine/fdm_machine_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "fdm_klipper_common",
|
|
||||||
"sub_path": "machine/fdm_klipper_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"sub_path": "machine/fdm_belt_common.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BabyBelt Pro 0.4 nozzle",
|
|
||||||
"sub_path": "machine/BabyBelt Pro 0.4 nozzle.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="95.0mm" height="500.0mm" viewBox="0 0 95.0 500.0" preserveAspectRatio="xMidYMid meet">
|
|
||||||
<!-- Printcepts BabyBelt Pro bed texture: 95 x 500 mm belt plate. -->
|
|
||||||
<!-- Transparent plate; green (#195F30) BabyBelt Pro logo centered along X, near the bottom edge. -->
|
|
||||||
<rect x="0" y="0" width="95.0" height="500.0" fill="none"/>
|
|
||||||
<g transform="translate(14.2500,436.3488) scale(0.067538)">
|
|
||||||
<g transform="translate(-11.000000,692.938562) scale(0.100000,-0.100000)"
|
|
||||||
fill="#195F30" stroke="none">
|
|
||||||
<path d="M1963 5604 l-1423 -1324 0 -2050 0 -2050 443 0 c244 0 741 3 1105 7
|
|
||||||
l662 6 0 746 c-1 575 -4 768 -14 841 -47 324 -179 486 -473 581 -40 12 -73 26
|
|
||||||
-73 30 0 4 32 17 72 29 212 64 333 166 378 320 35 121 38 191 32 868 l-5 662
|
|
||||||
-629 0 c-395 0 -628 4 -628 10 0 5 635 601 1410 1325 776 724 1410 1318 1410
|
|
||||||
1321 0 2 -190 4 -422 3 l-423 0 -1422 -1325z m-334 -2029 c143 -16 174 -96
|
|
||||||
173 -446 -2 -411 -24 -458 -224 -462 l-93 -2 -3 450 c-1 248 0 456 3 463 3 9
|
|
||||||
18 12 47 8 24 -3 67 -8 97 -11z m-4 -1556 c160 -29 173 -62 182 -469 9 -455
|
|
||||||
-14 -593 -108 -641 -39 -19 -193 -44 -210 -33 -10 6 -13 1147 -3 1157 6 6 45
|
|
||||||
2 139 -14z"/>
|
|
||||||
<path d="M3464 5979 c-142 -132 -263 -245 -268 -250 -6 -5 69 -9 190 -9 l199
|
|
||||||
1 268 249 267 250 -198 0 -198 0 -260 -241z"/>
|
|
||||||
<path d="M3650 5649 c-135 -126 -254 -238 -265 -249 -19 -20 -18 -20 177 -20
|
|
||||||
l197 0 228 211 c125 116 246 229 268 250 l40 39 -200 -1 -200 0 -245 -230z"/>
|
|
||||||
<path d="M2537 5089 c-101 -24 -204 -105 -251 -197 -96 -190 -19 -420 172
|
|
||||||
-514 l67 -33 2670 0 2670 0 57 27 c74 34 146 107 184 183 43 88 43 230 0 322
|
|
||||||
-35 76 -113 153 -193 191 l-58 27 -2640 2 c-1513 0 -2656 -3 -2678 -8z m5063
|
|
||||||
-77 c-57 -37 -118 -111 -140 -168 -31 -82 -25 -206 12 -279 26 -49 93 -121
|
|
||||||
133 -143 15 -8 -640 -11 -2410 -11 l-2430 0 30 21 c200 146 201 425 1 569
|
|
||||||
l-39 29 2434 -1 c2263 0 2432 -1 2409 -17z m-4890 -43 c270 -122 185 -526
|
|
||||||
-109 -522 -257 2 -370 324 -170 485 74 60 194 76 279 37z m5201 -12 c94 -55
|
|
||||||
140 -135 140 -242 0 -285 -393 -374 -517 -117 -26 54 -30 162 -9 219 28 74 97
|
|
||||||
139 173 164 53 17 166 4 213 -24z"/>
|
|
||||||
<path d="M2917 3973 c-4 -174 -7 -550 -7 -835 l0 -518 326 0 326 0 -7 150 -7
|
|
||||||
150 110 0 110 0 11 -32 c5 -18 26 -86 46 -150 l36 -118 325 0 c179 0 323 4
|
|
||||||
320 9 -3 4 -155 374 -337 822 -182 448 -333 820 -336 827 -4 9 -105 12 -457
|
|
||||||
12 l-453 0 -6 -317z m773 -745 c0 -5 -47 -8 -104 -8 l-103 0 -7 92 c-3 50 -6
|
|
||||||
202 -5 337 l1 246 109 -330 c60 -181 109 -333 109 -337z"/>
|
|
||||||
<path d="M4680 3455 l0 -835 448 0 c693 1 885 16 985 80 99 63 126 132 134
|
|
||||||
340 12 327 -44 405 -342 476 -28 7 -27 8 25 19 199 42 255 95 267 248 11 146
|
|
||||||
-32 285 -110 353 -145 126 -329 153 -1049 154 l-358 0 0 -835z m846 520 c36
|
|
||||||
-23 44 -54 44 -162 0 -152 -29 -183 -170 -183 l-40 0 0 186 0 187 71 -6 c39
|
|
||||||
-3 82 -13 95 -22z m4 -625 c33 -18 40 -52 40 -208 0 -200 -9 -214 -143 -228
|
|
||||||
l-67 -7 0 233 0 233 74 -6 c41 -3 84 -10 96 -17z"/>
|
|
||||||
<path d="M6150 4286 c0 -3 131 -242 290 -531 l290 -526 0 -304 0 -305 385 0
|
|
||||||
385 0 0 299 0 299 305 533 305 534 -377 3 c-207 1 -381 -2 -385 -6 -16 -16
|
|
||||||
-110 -258 -172 -444 l-62 -187 -18 77 c-18 75 -139 450 -171 525 l-15 37 -380
|
|
||||||
0 c-209 0 -380 -2 -380 -4z"/>
|
|
||||||
<path d="M2910 1355 l0 -1185 830 0 830 0 0 240 0 240 -350 0 -350 0 0 255 0
|
|
||||||
255 300 0 300 0 0 230 0 230 -300 0 -300 0 0 220 0 220 320 0 320 0 0 240 0
|
|
||||||
240 -800 0 -800 0 0 -1185z"/>
|
|
||||||
<path d="M4680 1355 l0 -1185 775 0 775 0 0 240 0 240 -295 0 -295 0 0 945 0
|
|
||||||
945 -480 0 -480 0 0 -1185z"/>
|
|
||||||
<path d="M5800 2300 l0 -240 280 0 280 0 0 -945 0 -945 480 0 480 0 0 945 0
|
|
||||||
945 285 0 285 0 0 240 0 240 -1045 0 -1045 0 0 -240z"/>
|
|
||||||
<path d="M8032 1358 l-2 -1188 1008 1 c621 1 971 5 912 10 -309 27 -631 139
|
|
||||||
-885 306 -593 391 -984 1122 -1025 1918 -4 77 -8 -394 -8 -1047z"/>
|
|
||||||
<path d="M7441 1934 c-43 -36 -59 -70 -70 -148 -18 -124 16 -252 76 -291 32
|
|
||||||
-21 226 -33 328 -20 114 14 161 97 153 269 -5 96 -24 151 -68 191 -20 18 -39
|
|
||||||
20 -205 23 l-182 3 -32 -27z m389 -199 c7 -8 10 -22 6 -30 -4 -13 -34 -15
|
|
||||||
-186 -15 -189 0 -202 3 -186 45 8 22 348 22 366 0z"/>
|
|
||||||
<path d="M7450 1267 c-14 -6 -35 -32 -47 -57 -21 -41 -23 -58 -23 -222 l0
|
|
||||||
-178 270 0 270 0 0 105 0 105 -121 0 -120 0 3 28 3 27 118 3 117 3 0 99 0 100
|
|
||||||
-113 0 c-121 0 -138 -7 -162 -65 -8 -19 -9 -19 -12 2 -10 55 -116 84 -183 50z
|
|
||||||
m134 -203 c15 -38 8 -44 -54 -44 -62 0 -69 6 -54 44 9 23 99 23 108 0z"/>
|
|
||||||
<path d="M466 1193 l-29 -43 -163 0 -164 0 0 -235 0 -235 165 0 165 0 27 -42
|
|
||||||
28 -42 3 163 c1 89 1 233 0 319 l-3 157 -29 -42z"/>
|
|
||||||
<path d="M7443 620 c-48 -20 -58 -60 -61 -262 l-4 -188 271 0 271 0 0 110 0
|
|
||||||
110 -110 0 -110 0 0 70 c0 76 -21 145 -51 160 -22 12 -176 12 -206 0z m161
|
|
||||||
-186 c15 -39 8 -44 -64 -44 -72 0 -79 5 -64 44 9 23 119 23 128 0z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB |
@@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @BabyBelt Pro",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "gCzHpDNgVwQR6tgk",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"BabyBelt Pro 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PETG"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"Generic"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"Generic PETG @BabyBelt Pro"
|
|
||||||
],
|
|
||||||
"filament_flow_ratio": [
|
|
||||||
"0.95"
|
|
||||||
],
|
|
||||||
"filament_cost": [
|
|
||||||
"25"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"240"
|
|
||||||
],
|
|
||||||
"nozzle_temperature_initial_layer": [
|
|
||||||
"245"
|
|
||||||
],
|
|
||||||
"cool_plate_temp": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"cool_plate_temp_initial_layer": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"overhang_fan_threshold": [
|
|
||||||
"25%"
|
|
||||||
],
|
|
||||||
"overhang_fan_speed": [
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"full_fan_speed_layer": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"slow_down_min_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"slow_down_layer_time": [
|
|
||||||
"4"
|
|
||||||
],
|
|
||||||
"fan_cooling_layer_time": [
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"filament_retraction_length": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"filament_retraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"filament_deretraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"filament_start_gcode": [
|
|
||||||
"; Generic PETG @BabyBelt Pro — belt PETG, bed 80C"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @BabyBelt Pro",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "24PpcnhVx9v5f4fD",
|
|
||||||
"instantiation": "true",
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard"
|
|
||||||
],
|
|
||||||
"compatible_printers": [
|
|
||||||
"BabyBelt Pro 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PLA"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"Generic"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"Generic PLA @BabyBelt Pro"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"215"
|
|
||||||
],
|
|
||||||
"hot_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"hot_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"cool_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"cool_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"textured_plate_temp": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"textured_plate_temp_initial_layer": [
|
|
||||||
"75"
|
|
||||||
],
|
|
||||||
"close_fan_the_first_x_layers": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"full_fan_speed_layer": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"slow_down_min_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"filament_retraction_length": [
|
|
||||||
"1.5"
|
|
||||||
],
|
|
||||||
"filament_retraction_speed": [
|
|
||||||
"35"
|
|
||||||
],
|
|
||||||
"filament_deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"filament_start_gcode": [
|
|
||||||
"; Generic PLA @BabyBelt Pro — belt PLA, bed 75C"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "eSUN PLA @BabyBelt Pro",
|
|
||||||
"inherits": "Generic PLA @BabyBelt Pro",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "EH3X7oE0DU5tSpjW",
|
|
||||||
"filament_id": "OFkrxQC4",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"BabyBelt Pro 0.4 nozzle"
|
|
||||||
],
|
|
||||||
"filament_type": [
|
|
||||||
"PLA"
|
|
||||||
],
|
|
||||||
"filament_vendor": [
|
|
||||||
"eSUN"
|
|
||||||
],
|
|
||||||
"filament_settings_id": [
|
|
||||||
"eSUN PLA @BabyBelt Pro"
|
|
||||||
],
|
|
||||||
"nozzle_temperature_initial_layer": [
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"nozzle_temperature": [
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"enable_pressure_advance": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"pressure_advance": [
|
|
||||||
"0.12"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "BabyBelt Pro 0.4 nozzle",
|
|
||||||
"inherits": "fdm_belt_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "34OWINlJpJgA9DwQ",
|
|
||||||
"instantiation": "true",
|
|
||||||
"printer_model": "BabyBelt Pro",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @BabyBelt Pro"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @BabyBelt Pro",
|
|
||||||
"printable_area": [
|
|
||||||
"0x0",
|
|
||||||
"95x0",
|
|
||||||
"95x500",
|
|
||||||
"0x500"
|
|
||||||
],
|
|
||||||
"printable_height": "100",
|
|
||||||
"best_object_pos": "0.5,0.05",
|
|
||||||
"nozzle_type": [
|
|
||||||
"hardened_steel"
|
|
||||||
],
|
|
||||||
"printer_extruder_id": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"printer_extruder_variant": [
|
|
||||||
"Direct Drive Standard"
|
|
||||||
],
|
|
||||||
"thumbnails": [
|
|
||||||
"48x48/PNG",
|
|
||||||
"300x300/PNG"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_e": [
|
|
||||||
"500",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"500",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"500",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"500",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"500",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_junction_deviation": [
|
|
||||||
"0.01",
|
|
||||||
"0.01"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"50",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"50",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"5",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"1.5"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"25"
|
|
||||||
],
|
|
||||||
"retract_lift_enforce": [
|
|
||||||
"Top and Bottom"
|
|
||||||
],
|
|
||||||
"support_chamber_temp_control": "0",
|
|
||||||
"machine_start_gcode": ";Start GCode\nPRINT_START ANGLE=[belt_slice_rotation_angle] EXTRUDER=[nozzle_temperature_initial_layer] BED=[hot_plate_temp_initial_layer] MATERIAL=[filament_type]\n"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine_model",
|
|
||||||
"name": "BabyBelt Pro",
|
|
||||||
"model_id": "Printcepts_BabyBelt_Pro",
|
|
||||||
"nozzle_diameter": "0.4",
|
|
||||||
"machine_tech": "FFF",
|
|
||||||
"family": "Printcepts",
|
|
||||||
"bed_model": "",
|
|
||||||
"bed_texture": "BabyBelt Pro_bed_texture.svg",
|
|
||||||
"hotend_model": "",
|
|
||||||
"default_materials": "Generic PLA @BabyBelt Pro;Generic PETG @BabyBelt Pro"
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_belt_common",
|
|
||||||
"inherits": "fdm_klipper_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"gcode_flavor": "klipper",
|
|
||||||
"single_extruder_multi_material": "0",
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @System"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @BabyBelt Pro",
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"extruder_colour": [
|
|
||||||
"#FCE94F"
|
|
||||||
],
|
|
||||||
"extruder_offset": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"long_retractions_when_cut": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retract_lift_above": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_below": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_lift_enforce": [
|
|
||||||
"All Surfaces"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_distances_when_cut": [
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"travel_slope": [
|
|
||||||
"3"
|
|
||||||
],
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"wipe_distance": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"z_hop_types": [
|
|
||||||
"Normal Lift"
|
|
||||||
],
|
|
||||||
"gcode_remap_x": "rev_x",
|
|
||||||
"gcode_remap_y": "pos_z",
|
|
||||||
"gcode_remap_z": "pos_y",
|
|
||||||
"printer_extruder_id": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"belt_printer": "1",
|
|
||||||
"belt_slice_rotation": "x",
|
|
||||||
"belt_slice_rotation_angle": "45",
|
|
||||||
"build_plate_tilt_x": "45",
|
|
||||||
"purge_in_prime_tower": "0",
|
|
||||||
"scan_first_layer": "0",
|
|
||||||
"auxiliary_fan": "0"
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_klipper_common",
|
|
||||||
"inherits": "fdm_machine_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"gcode_flavor": "klipper",
|
|
||||||
"machine_max_acceleration_e": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"5000",
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_travel": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"20000",
|
|
||||||
"20000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_z": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_e": [
|
|
||||||
"25",
|
|
||||||
"25"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"500",
|
|
||||||
"200"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_e": [
|
|
||||||
"2.5",
|
|
||||||
"2.5"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_x": [
|
|
||||||
"9",
|
|
||||||
"9"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_y": [
|
|
||||||
"9",
|
|
||||||
"9"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_z": [
|
|
||||||
"0.2",
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"machine_min_extruding_rate": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"machine_min_travel_rate": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"printable_height": "250",
|
|
||||||
"extruder_clearance_radius": "65",
|
|
||||||
"extruder_clearance_height_to_rod": "36",
|
|
||||||
"extruder_clearance_height_to_lid": "140",
|
|
||||||
"printer_settings_id": "",
|
|
||||||
"printer_technology": "FFF",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"0.8"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"deretraction_speed": [
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"z_hop_types": "Normal Lift",
|
|
||||||
"single_extruder_multi_material": "1",
|
|
||||||
"change_filament_gcode": "",
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"default_filament_profile": [
|
|
||||||
"Generic PLA @System"
|
|
||||||
],
|
|
||||||
"default_print_profile": "0.20mm Standard @MyKlipper",
|
|
||||||
"bed_exclude_area": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"machine_start_gcode": "M190 S[bed_temperature_initial_layer_single]\nM109 S[nozzle_temperature_initial_layer]\nPRINT_START EXTRUDER=[nozzle_temperature_initial_layer] BED=[bed_temperature_initial_layer_single]\n",
|
|
||||||
"machine_end_gcode": "PRINT_END",
|
|
||||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
|
||||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
|
|
||||||
"machine_pause_gcode": "PAUSE",
|
|
||||||
"scan_first_layer": "0",
|
|
||||||
"nozzle_type": "undefine",
|
|
||||||
"auxiliary_fan": "0"
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "machine",
|
|
||||||
"name": "fdm_machine_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"printer_technology": "FFF",
|
|
||||||
"deretraction_speed": [
|
|
||||||
"40"
|
|
||||||
],
|
|
||||||
"extruder_colour": [
|
|
||||||
"#FCE94F"
|
|
||||||
],
|
|
||||||
"extruder_offset": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"gcode_flavor": "marlin",
|
|
||||||
"machine_max_acceleration_e": [
|
|
||||||
"5000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_extruding": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_retracting": [
|
|
||||||
"1000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_x": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_y": [
|
|
||||||
"10000"
|
|
||||||
],
|
|
||||||
"machine_max_acceleration_z": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_e": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"machine_max_speed_x": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_y": [
|
|
||||||
"500"
|
|
||||||
],
|
|
||||||
"machine_max_speed_z": [
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_e": [
|
|
||||||
"5"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_x": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_y": [
|
|
||||||
"8"
|
|
||||||
],
|
|
||||||
"machine_max_jerk_z": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"machine_min_extruding_rate": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"machine_min_travel_rate": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"max_layer_height": [
|
|
||||||
"0.32"
|
|
||||||
],
|
|
||||||
"min_layer_height": [
|
|
||||||
"0.08"
|
|
||||||
],
|
|
||||||
"printable_height": "250",
|
|
||||||
"extruder_clearance_radius": "65",
|
|
||||||
"extruder_clearance_height_to_rod": "36",
|
|
||||||
"extruder_clearance_height_to_lid": "140",
|
|
||||||
"nozzle_diameter": [
|
|
||||||
"0.4"
|
|
||||||
],
|
|
||||||
"printer_settings_id": "",
|
|
||||||
"printer_variant": "0.4",
|
|
||||||
"retraction_minimum_travel": [
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"retract_before_wipe": [
|
|
||||||
"70%"
|
|
||||||
],
|
|
||||||
"retract_when_changing_layer": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retraction_length": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"retract_length_toolchange": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"z_hop": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retract_restart_extra_toolchange": [
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"retraction_speed": [
|
|
||||||
"60"
|
|
||||||
],
|
|
||||||
"single_extruder_multi_material": "1",
|
|
||||||
"change_filament_gcode": "",
|
|
||||||
"wipe": [
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"default_print_profile": "",
|
|
||||||
"machine_start_gcode": "G0 Z20 F9000\nG92 E0; G1 E-10 F1200\nG28\nM970 Q1 A10 B10 C130 K0\nM970 Q1 A10 B131 C250 K1\nM974 Q1 S1 P0\nM970 Q0 A10 B10 C130 H20 K0\nM970 Q0 A10 B131 C250 K1\nM974 Q0 S1 P0\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nG29 ;Home\nG90;\nG92 E0 ;Reset Extruder \nG1 Z2.0 F3000 ;Move Z Axis up \nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S205;\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder \nG1 X110 Y110 Z2.0 F3000 ;Move Z Axis up",
|
|
||||||
"machine_end_gcode": "M400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-4.0 F3600; retract \nG91\nG1 Z3;\nM104 S0 ; turn off hotend\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nG90 \nG0 X110 Y200 F3600 \nprint_end",
|
|
||||||
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]",
|
|
||||||
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n",
|
|
||||||
"machine_pause_gcode": "M601"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "0.20mm Standard @BabyBelt Pro",
|
|
||||||
"inherits": "fdm_process_common",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "JGfGtqX6CWjCt437",
|
|
||||||
"instantiation": "true",
|
|
||||||
"layer_height": "0.2",
|
|
||||||
"initial_layer_print_height": "0.2",
|
|
||||||
"initial_layer_line_width": "0.42",
|
|
||||||
"wall_loops": "2",
|
|
||||||
"reduce_infill_retraction": "1",
|
|
||||||
"detect_overhang_wall": "1",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"skirt_distance": "0",
|
|
||||||
"sparse_infill_pattern": "grid",
|
|
||||||
"sparse_infill_speed": "200",
|
|
||||||
"support_base_pattern": "rectilinear",
|
|
||||||
"support_interface_pattern": "rectilinear",
|
|
||||||
"compatible_printers": [
|
|
||||||
"BabyBelt Pro 0.4 nozzle"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "process",
|
|
||||||
"name": "fdm_process_common",
|
|
||||||
"from": "system",
|
|
||||||
"instantiation": "false",
|
|
||||||
"reduce_crossing_wall": "0",
|
|
||||||
"max_travel_detour_distance": "0",
|
|
||||||
"bottom_surface_pattern": "monotonic",
|
|
||||||
"bottom_shell_thickness": "0",
|
|
||||||
"bridge_speed": "50",
|
|
||||||
"brim_width": "5",
|
|
||||||
"brim_object_gap": "0.1",
|
|
||||||
"compatible_printers": [],
|
|
||||||
"compatible_printers_condition": "",
|
|
||||||
"print_sequence": "by layer",
|
|
||||||
"default_acceleration": "1000",
|
|
||||||
"initial_layer_acceleration": "500",
|
|
||||||
"top_surface_acceleration": "1000",
|
|
||||||
"travel_acceleration": "1000",
|
|
||||||
"inner_wall_acceleration": "1000",
|
|
||||||
"outer_wall_acceleration": "700",
|
|
||||||
"bridge_no_support": "0",
|
|
||||||
"draft_shield": "disabled",
|
|
||||||
"elefant_foot_compensation": "0",
|
|
||||||
"enable_arc_fitting": "0",
|
|
||||||
"wall_infill_order": "inner wall/outer wall/infill",
|
|
||||||
"infill_direction": "45",
|
|
||||||
"sparse_infill_density": "15%",
|
|
||||||
"sparse_infill_pattern": "crosshatch",
|
|
||||||
"initial_layer_print_height": "0.2",
|
|
||||||
"infill_combination": "0",
|
|
||||||
"infill_wall_overlap": "25%",
|
|
||||||
"interface_shells": "0",
|
|
||||||
"ironing_flow": "10%",
|
|
||||||
"ironing_spacing": "0.15",
|
|
||||||
"ironing_speed": "30",
|
|
||||||
"ironing_type": "no ironing",
|
|
||||||
"reduce_infill_retraction": "1",
|
|
||||||
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[initial_tool]}_{printer_model}_{print_time}.gcode",
|
|
||||||
"detect_overhang_wall": "1",
|
|
||||||
"slowdown_for_curled_perimeters": "1",
|
|
||||||
"overhang_1_4_speed": "0",
|
|
||||||
"overhang_2_4_speed": "50",
|
|
||||||
"overhang_3_4_speed": "30",
|
|
||||||
"overhang_4_4_speed": "10",
|
|
||||||
"line_width": "110%",
|
|
||||||
"inner_wall_line_width": "110%",
|
|
||||||
"outer_wall_line_width": "100%",
|
|
||||||
"top_surface_line_width": "93.75%",
|
|
||||||
"sparse_infill_line_width": "110%",
|
|
||||||
"initial_layer_line_width": "120%",
|
|
||||||
"internal_solid_infill_line_width": "120%",
|
|
||||||
"support_line_width": "96%",
|
|
||||||
"wall_loops": "3",
|
|
||||||
"print_settings_id": "",
|
|
||||||
"raft_layers": "0",
|
|
||||||
"seam_position": "aligned",
|
|
||||||
"skirt_distance": "2",
|
|
||||||
"skirt_height": "3",
|
|
||||||
"min_skirt_length": "4",
|
|
||||||
"skirt_loops": "0",
|
|
||||||
"minimum_sparse_infill_area": "15",
|
|
||||||
"spiral_mode": "0",
|
|
||||||
"standby_temperature_delta": "-5",
|
|
||||||
"enable_support": "0",
|
|
||||||
"resolution": "0.012",
|
|
||||||
"support_type": "normal(auto)",
|
|
||||||
"support_on_build_plate_only": "0",
|
|
||||||
"support_top_z_distance": "0.2",
|
|
||||||
"support_bottom_z_distance": "0.2",
|
|
||||||
"support_filament": "0",
|
|
||||||
"support_interface_loop_pattern": "0",
|
|
||||||
"support_interface_filament": "0",
|
|
||||||
"support_interface_top_layers": "2",
|
|
||||||
"support_interface_bottom_layers": "2",
|
|
||||||
"support_interface_spacing": "0.5",
|
|
||||||
"support_interface_speed": "80",
|
|
||||||
"support_base_pattern": "default",
|
|
||||||
"support_base_pattern_spacing": "2.5",
|
|
||||||
"support_speed": "150",
|
|
||||||
"support_threshold_angle": "30",
|
|
||||||
"support_object_xy_distance": "0.35",
|
|
||||||
"tree_support_branch_angle": "30",
|
|
||||||
"tree_support_wall_count": "0",
|
|
||||||
"detect_thin_wall": "0",
|
|
||||||
"top_surface_pattern": "monotonicline",
|
|
||||||
"top_shell_thickness": "0.8",
|
|
||||||
"enable_prime_tower": "1",
|
|
||||||
"wipe_tower_no_sparse_layers": "0",
|
|
||||||
"prime_tower_width": "60",
|
|
||||||
"xy_hole_compensation": "0",
|
|
||||||
"xy_contour_compensation": "0",
|
|
||||||
"layer_height": "0.2",
|
|
||||||
"bottom_shell_layers": "3",
|
|
||||||
"top_shell_layers": "4",
|
|
||||||
"bridge_flow": "1",
|
|
||||||
"initial_layer_speed": "45",
|
|
||||||
"initial_layer_infill_speed": "45",
|
|
||||||
"outer_wall_speed": "45",
|
|
||||||
"inner_wall_speed": "80",
|
|
||||||
"sparse_infill_speed": "150",
|
|
||||||
"internal_solid_infill_speed": "150",
|
|
||||||
"top_surface_speed": "50",
|
|
||||||
"gap_infill_speed": "30",
|
|
||||||
"travel_speed": "200"
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -78,8 +77,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// dot product of world normal with up direction, used for slope shading
|
// z component of normal vector in world coordinate used for slope shading
|
||||||
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ void main()
|
|||||||
color = LightBlue;
|
color = LightBlue;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
}
|
}
|
||||||
else if( dot(transformed_normal, slope.up_direction) < slope.normal_z - EPSILON)
|
else if( transformed_normal.z < slope.normal_z - EPSILON)
|
||||||
{
|
{
|
||||||
color = color * 0.5 + LightRed * 0.5;
|
color = color * 0.5 + LightRed * 0.5;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -47,8 +46,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// dot product of world normal with up direction, used for slope shading
|
// z component of normal vector in world coordinate used for slope shading
|
||||||
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
|
|||||||
@@ -29,13 +29,19 @@ uniform vec3 palette_lab[64];
|
|||||||
uniform vec3 palette_rgb[64];
|
uniform vec3 palette_rgb[64];
|
||||||
uniform int palette_count;
|
uniform int palette_count;
|
||||||
uniform bool pure_only; // match against single filaments only (flat-colour image)
|
uniform bool pure_only; // match against single filaments only (flat-colour image)
|
||||||
// How each entry prints. Every entry names a single filament: a mix is given its own mixed filament
|
// How each entry prints. A pure entry is one filament (a == b); a mix interleaves filaments a and b,
|
||||||
// slot, whose components the slicer alternates per print layer, so the fragment just looks that slot's
|
// num parts of a in every den, and the print shows that interleave rather than the entry's average
|
||||||
// colour up.
|
// colour. The fragment resolves it exactly as GLGizmoTextureDisplacement::make_mix_resolver() does
|
||||||
|
// per triangle on the CPU, so the preview shows the pattern the bake will print.
|
||||||
uniform int palette_a[64];
|
uniform int palette_a[64];
|
||||||
uniform int palette_b[64];
|
uniform int palette_b[64];
|
||||||
|
uniform int palette_num[64];
|
||||||
|
uniform int palette_den[64];
|
||||||
uniform vec3 filament_rgb[16];
|
uniform vec3 filament_rgb[16];
|
||||||
uniform int filament_count;
|
uniform int filament_count;
|
||||||
|
uniform int mix_mode; // ColorMixMode: 0 Z bands, 1 XY dither, 2 auto
|
||||||
|
uniform float layer_height; // mm; one Z band per print layer
|
||||||
|
uniform float dither_cell; // mm; one XY dither cell
|
||||||
uniform sampler2D color_tex; // the layer's colour image, sampled at the same uv as the height
|
uniform sampler2D color_tex; // the layer's colour image, sampled at the same uv as the height
|
||||||
uniform bool has_color_tex;
|
uniform bool has_color_tex;
|
||||||
uniform bool volume_mirrored;
|
uniform bool volume_mirrored;
|
||||||
@@ -223,16 +229,63 @@ int nearest_palette_entry(vec3 rgb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// One 2x2 Bayer cell, {0, 2; 3, 1}, for x and y in {0, 1}.
|
// One 2x2 Bayer cell, {0, 2; 3, 1}, for x and y in {0, 1}.
|
||||||
|
float bayer2(float x, float y) { return 2.0 * x + 3.0 * y - 4.0 * x * y; }
|
||||||
|
|
||||||
// The colour the printer lays down at world point `pos` for palette entry `index`. Every entry names a
|
// The colour the printer lays down at world point `pos` for palette entry `index`: its filament, or
|
||||||
// single filament: a mix is given its own mixed filament slot, whose components the slicer alternates
|
// for a mix whichever of its two filaments this point falls on. Mirrors make_mix_resolver() on the
|
||||||
// per print layer, so there is nothing left to interleave here.
|
// CPU, floors on the band/cell size included. All the modular arithmetic is done in floats with
|
||||||
vec3 printed_color(int index)
|
// mod(), which wraps negative coordinates the way the CPU's ((v % n) + n) % n does and needs no
|
||||||
|
// integer % (not available on every GLSL 1.10 target).
|
||||||
|
vec3 printed_color(int index, vec3 pos, vec3 normal, vec3 footprint)
|
||||||
{
|
{
|
||||||
int a = palette_a[index];
|
int a = palette_a[index];
|
||||||
if (a < 0 || a >= filament_count)
|
int b = palette_b[index];
|
||||||
|
if (a < 0 || a >= filament_count || b < 0 || b >= filament_count)
|
||||||
return palette_rgb[index]; // no filament to resolve to: the entry's own colour
|
return palette_rgb[index]; // no filament to resolve to: the entry's own colour
|
||||||
return filament_rgb[a];
|
if (a == b)
|
||||||
|
return filament_rgb[a];
|
||||||
|
float num = float(palette_num[index]);
|
||||||
|
float den = float(palette_den[index]);
|
||||||
|
// Auto: bands where the surface is steeper than ~45 degrees, the dominant filament elsewhere.
|
||||||
|
if (mix_mode == 2 && abs(normal.z) >= 0.7)
|
||||||
|
return filament_rgb[(num * 2.0 >= den) ? a : b];
|
||||||
|
|
||||||
|
// Pre-filter. The interleave is an ordered dither the eye is meant to blend away, and no dither
|
||||||
|
// blends when it is drawn at less than a few pixels per period - it aliases, which is what turned
|
||||||
|
// every upright wall into horizontal streaks: the Z band cycle is den * layer_height (around a
|
||||||
|
// millimetre), and every pixel of a row on a vertical wall shares one z, so each row came out as a
|
||||||
|
// 1-bit threshold of the image at that row's phase. `footprint` is mm of world position per pixel,
|
||||||
|
// so this is zoom- and resolution-correct rather than a tuned constant: where the print's own
|
||||||
|
// pattern is finer than this view can resolve, show what the print looks like from here, which is
|
||||||
|
// the entry's perceptual average. The Normal view remains where the per-facet truth lives.
|
||||||
|
float period = (mix_mode == 1) ? 2.0 * max(dither_cell, 0.01) : den * max(layer_height, 0.01);
|
||||||
|
float px = (mix_mode == 1) ? max(footprint.x, footprint.y) : footprint.z;
|
||||||
|
float sharp = clamp(period / max(4.0 * px, 1e-6) - 0.5, 0.0, 1.0);
|
||||||
|
if (sharp <= 0.0)
|
||||||
|
return palette_rgb[index];
|
||||||
|
|
||||||
|
vec3 picked;
|
||||||
|
if (mix_mode == 1) {
|
||||||
|
// Ordered 4x4 Bayer over floor(x / cell), floor(y / cell). The CPU's table
|
||||||
|
// 0 8 2 10
|
||||||
|
// 12 4 14 6
|
||||||
|
// 3 11 1 9
|
||||||
|
// 15 7 13 5
|
||||||
|
// is 4 * bayer2(x % 2, y % 2) + bayer2(x / 2, y / 2), which needs no array (GLSL 1.10 has
|
||||||
|
// no constant arrays).
|
||||||
|
float cell = max(dither_cell, 0.01);
|
||||||
|
float gx = mod(floor(pos.x / cell), 4.0);
|
||||||
|
float gy = mod(floor(pos.y / cell), 4.0);
|
||||||
|
float bayer = 4.0 * bayer2(mod(gx, 2.0), mod(gy, 2.0)) + bayer2(floor(gx / 2.0), floor(gy / 2.0));
|
||||||
|
picked = filament_rgb[(num / den > (bayer + 0.5) / 16.0) ? a : b];
|
||||||
|
} else {
|
||||||
|
// Z bands: one per band height, the band's phase in the a/b cycle picks the filament. Both
|
||||||
|
// operands are integer-valued, so the half keeps "phase < num" exact under float rounding.
|
||||||
|
float slot = floor(pos.z / max(layer_height, 0.01));
|
||||||
|
float phase = mod(slot, den);
|
||||||
|
picked = filament_rgb[(phase < num - 0.5) ? a : b];
|
||||||
|
}
|
||||||
|
return mix(palette_rgb[index], picked, sharp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@@ -243,6 +296,9 @@ void main()
|
|||||||
// World millimetres throughout, like the bake - see the 140 variant.
|
// World millimetres throughout, like the bake - see the 140 variant.
|
||||||
vec3 triangle_normal = normalize(cross(dFdx(world_pos.xyz), dFdy(world_pos.xyz)));
|
vec3 triangle_normal = normalize(cross(dFdx(world_pos.xyz), dFdy(world_pos.xyz)));
|
||||||
vec3 tex_pos = world_pos.xyz - tex_anchor; // the frame the texture is projected in, as the bake does
|
vec3 tex_pos = world_pos.xyz - tex_anchor; // the frame the texture is projected in, as the bake does
|
||||||
|
// World mm per pixel, for pre-filtering the interleave in printed_color(). Taken here because the
|
||||||
|
// albedo branch at the end of main() is non-uniform control flow, where derivatives are undefined.
|
||||||
|
vec3 pos_fwidth = fwidth(world_pos.xyz);
|
||||||
if (volume_mirrored)
|
if (volume_mirrored)
|
||||||
triangle_normal = -triangle_normal;
|
triangle_normal = -triangle_normal;
|
||||||
|
|
||||||
@@ -364,6 +420,6 @@ void main()
|
|||||||
// orientation and scale about the volume's origin, see texture_displacement_bake_frame()), so
|
// orientation and scale about the volume's origin, see texture_displacement_bake_frame()), so
|
||||||
// measuring z from the bed instead shifted the band phase by the volume origin's height - a
|
// measuring z from the bed instead shifted the band phase by the volume origin's height - a
|
||||||
// different filament in the same place than the bake produces.
|
// different filament in the same place than the bake produces.
|
||||||
albedo = printed_color(nearest_palette_entry(texture2D(color_tex, color_uv).rgb));
|
albedo = printed_color(nearest_palette_entry(texture2D(color_tex, color_uv).rgb), tex_pos, triangle_normal, pos_fwidth);
|
||||||
gl_FragColor = vec4(vec3(intensity.y) + albedo * intensity.x, uniform_color.a);
|
gl_FragColor = vec4(vec3(intensity.y) + albedo * intensity.x, uniform_color.a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -78,8 +77,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// dot product of world normal with up direction, used for slope shading
|
// z component of normal vector in world coordinate used for slope shading
|
||||||
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
@@ -88,7 +87,7 @@ void main()
|
|||||||
color = LightBlue;
|
color = LightBlue;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
}
|
}
|
||||||
else if( dot(transformed_normal, slope.up_direction) < slope.normal_z - EPSILON)
|
else if( transformed_normal.z < slope.normal_z - EPSILON)
|
||||||
{
|
{
|
||||||
color = color * 0.5 + LightRed * 0.5;
|
color = color * 0.5 + LightRed * 0.5;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
vec3 up_direction;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -47,8 +46,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// dot product of world normal with up direction, used for slope shading
|
// z component of normal vector in world coordinate used for slope shading
|
||||||
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
if (is_outline) {
|
if (is_outline) {
|
||||||
|
|||||||
@@ -88,13 +88,19 @@ uniform vec3 palette_lab[64];
|
|||||||
uniform vec3 palette_rgb[64];
|
uniform vec3 palette_rgb[64];
|
||||||
uniform int palette_count;
|
uniform int palette_count;
|
||||||
uniform bool pure_only; // match against single filaments only (flat-colour image)
|
uniform bool pure_only; // match against single filaments only (flat-colour image)
|
||||||
// How each entry prints. Every entry names a single filament: a mix is given its own mixed filament
|
// How each entry prints. A pure entry is one filament (a == b); a mix interleaves filaments a and b,
|
||||||
// slot, whose components the slicer alternates per print layer, so the fragment just looks that slot's
|
// num parts of a in every den, and the print shows that interleave rather than the entry's average
|
||||||
// colour up.
|
// colour. The fragment resolves it exactly as GLGizmoTextureDisplacement::make_mix_resolver() does
|
||||||
|
// per triangle on the CPU, so the preview shows the pattern the bake will print.
|
||||||
uniform int palette_a[64];
|
uniform int palette_a[64];
|
||||||
uniform int palette_b[64];
|
uniform int palette_b[64];
|
||||||
|
uniform int palette_num[64];
|
||||||
|
uniform int palette_den[64];
|
||||||
uniform vec3 filament_rgb[16];
|
uniform vec3 filament_rgb[16];
|
||||||
uniform int filament_count;
|
uniform int filament_count;
|
||||||
|
uniform int mix_mode; // ColorMixMode: 0 Z bands, 1 XY dither, 2 auto
|
||||||
|
uniform float layer_height; // mm; one Z band per print layer
|
||||||
|
uniform float dither_cell; // mm; one XY dither cell
|
||||||
uniform sampler2D color_tex; // the layer's colour image, sampled at the same uv as the height
|
uniform sampler2D color_tex; // the layer's colour image, sampled at the same uv as the height
|
||||||
uniform bool has_color_tex;
|
uniform bool has_color_tex;
|
||||||
uniform bool volume_mirrored;
|
uniform bool volume_mirrored;
|
||||||
@@ -289,16 +295,63 @@ int nearest_palette_entry(vec3 rgb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// One 2x2 Bayer cell, {0, 2; 3, 1}, for x and y in {0, 1}.
|
// One 2x2 Bayer cell, {0, 2; 3, 1}, for x and y in {0, 1}.
|
||||||
|
float bayer2(float x, float y) { return 2.0 * x + 3.0 * y - 4.0 * x * y; }
|
||||||
|
|
||||||
// The colour the printer lays down at world point `pos` for palette entry `index`. Every entry names a
|
// The colour the printer lays down at world point `pos` for palette entry `index`: its filament, or
|
||||||
// single filament: a mix is given its own mixed filament slot, whose components the slicer alternates
|
// for a mix whichever of its two filaments this point falls on. Mirrors make_mix_resolver() on the
|
||||||
// per print layer, so there is nothing left to interleave here.
|
// CPU, floors on the band/cell size included. All the modular arithmetic is done in floats with
|
||||||
vec3 printed_color(int index)
|
// mod(), which wraps negative coordinates the way the CPU's ((v % n) + n) % n does and needs no
|
||||||
|
// integer % (not available on every GLSL 1.10 target).
|
||||||
|
vec3 printed_color(int index, vec3 pos, vec3 normal, vec3 footprint)
|
||||||
{
|
{
|
||||||
int a = palette_a[index];
|
int a = palette_a[index];
|
||||||
if (a < 0 || a >= filament_count)
|
int b = palette_b[index];
|
||||||
|
if (a < 0 || a >= filament_count || b < 0 || b >= filament_count)
|
||||||
return palette_rgb[index]; // no filament to resolve to: the entry's own colour
|
return palette_rgb[index]; // no filament to resolve to: the entry's own colour
|
||||||
return filament_rgb[a];
|
if (a == b)
|
||||||
|
return filament_rgb[a];
|
||||||
|
float num = float(palette_num[index]);
|
||||||
|
float den = float(palette_den[index]);
|
||||||
|
// Auto: bands where the surface is steeper than ~45 degrees, the dominant filament elsewhere.
|
||||||
|
if (mix_mode == 2 && abs(normal.z) >= 0.7)
|
||||||
|
return filament_rgb[(num * 2.0 >= den) ? a : b];
|
||||||
|
|
||||||
|
// Pre-filter. The interleave is an ordered dither the eye is meant to blend away, and no dither
|
||||||
|
// blends when it is drawn at less than a few pixels per period - it aliases, which is what turned
|
||||||
|
// every upright wall into horizontal streaks: the Z band cycle is den * layer_height (around a
|
||||||
|
// millimetre), and every pixel of a row on a vertical wall shares one z, so each row came out as a
|
||||||
|
// 1-bit threshold of the image at that row's phase. `footprint` is mm of world position per pixel,
|
||||||
|
// so this is zoom- and resolution-correct rather than a tuned constant: where the print's own
|
||||||
|
// pattern is finer than this view can resolve, show what the print looks like from here, which is
|
||||||
|
// the entry's perceptual average. The Normal view remains where the per-facet truth lives.
|
||||||
|
float period = (mix_mode == 1) ? 2.0 * max(dither_cell, 0.01) : den * max(layer_height, 0.01);
|
||||||
|
float px = (mix_mode == 1) ? max(footprint.x, footprint.y) : footprint.z;
|
||||||
|
float sharp = clamp(period / max(4.0 * px, 1e-6) - 0.5, 0.0, 1.0);
|
||||||
|
if (sharp <= 0.0)
|
||||||
|
return palette_rgb[index];
|
||||||
|
|
||||||
|
vec3 picked;
|
||||||
|
if (mix_mode == 1) {
|
||||||
|
// Ordered 4x4 Bayer over floor(x / cell), floor(y / cell). The CPU's table
|
||||||
|
// 0 8 2 10
|
||||||
|
// 12 4 14 6
|
||||||
|
// 3 11 1 9
|
||||||
|
// 15 7 13 5
|
||||||
|
// is 4 * bayer2(x % 2, y % 2) + bayer2(x / 2, y / 2), which needs no array (GLSL 1.10 has
|
||||||
|
// no constant arrays).
|
||||||
|
float cell = max(dither_cell, 0.01);
|
||||||
|
float gx = mod(floor(pos.x / cell), 4.0);
|
||||||
|
float gy = mod(floor(pos.y / cell), 4.0);
|
||||||
|
float bayer = 4.0 * bayer2(mod(gx, 2.0), mod(gy, 2.0)) + bayer2(floor(gx / 2.0), floor(gy / 2.0));
|
||||||
|
picked = filament_rgb[(num / den > (bayer + 0.5) / 16.0) ? a : b];
|
||||||
|
} else {
|
||||||
|
// Z bands: one per band height, the band's phase in the a/b cycle picks the filament. Both
|
||||||
|
// operands are integer-valued, so the half keeps "phase < num" exact under float rounding.
|
||||||
|
float slot = floor(pos.z / max(layer_height, 0.01));
|
||||||
|
float phase = mod(slot, den);
|
||||||
|
picked = filament_rgb[(phase < num - 0.5) ? a : b];
|
||||||
|
}
|
||||||
|
return mix(palette_rgb[index], picked, sharp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@@ -311,6 +364,9 @@ void main()
|
|||||||
// world position and perturb the world normal.
|
// world position and perturb the world normal.
|
||||||
vec3 triangle_normal = normalize(cross(dFdx(world_pos.xyz), dFdy(world_pos.xyz)));
|
vec3 triangle_normal = normalize(cross(dFdx(world_pos.xyz), dFdy(world_pos.xyz)));
|
||||||
vec3 tex_pos = world_pos.xyz - tex_anchor; // the frame the texture is projected in, as the bake does
|
vec3 tex_pos = world_pos.xyz - tex_anchor; // the frame the texture is projected in, as the bake does
|
||||||
|
// World mm per pixel, for pre-filtering the interleave in printed_color(). Taken here because the
|
||||||
|
// albedo branch at the end of main() is non-uniform control flow, where derivatives are undefined.
|
||||||
|
vec3 pos_fwidth = fwidth(world_pos.xyz);
|
||||||
if (volume_mirrored)
|
if (volume_mirrored)
|
||||||
triangle_normal = -triangle_normal;
|
triangle_normal = -triangle_normal;
|
||||||
|
|
||||||
@@ -452,6 +508,6 @@ void main()
|
|||||||
// orientation and scale about the volume's origin, see texture_displacement_bake_frame()), so
|
// orientation and scale about the volume's origin, see texture_displacement_bake_frame()), so
|
||||||
// measuring z from the bed instead shifted the band phase by the volume origin's height - a
|
// measuring z from the bed instead shifted the band phase by the volume origin's height - a
|
||||||
// different filament in the same place than the bake produces.
|
// different filament in the same place than the bake produces.
|
||||||
albedo = printed_color(nearest_palette_entry(texture(color_tex, color_uv).rgb));
|
albedo = printed_color(nearest_palette_entry(texture(color_tex, color_uv).rgb), tex_pos, triangle_normal, pos_fwidth);
|
||||||
out_color = vec4(vec3(intensity.y) + albedo * intensity.x, uniform_color.a);
|
out_color = vec4(vec3(intensity.y) + albedo * intensity.x, uniform_color.a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,11 +167,6 @@ OBSOLETE_KEYS = {
|
|||||||
"filament_load_time", "filament_unload_time", "smooth_coefficient",
|
"filament_load_time", "filament_unload_time", "smooth_coefficient",
|
||||||
"overhang_totally_speed", "silent_mode", "overhang_speed_classic",
|
"overhang_totally_speed", "silent_mode", "overhang_speed_classic",
|
||||||
"anisotropic_surfaces",
|
"anisotropic_surfaces",
|
||||||
# Belt printer options retired before the feature shipped (#16236).
|
|
||||||
"belt_slice_rotation_global", "preslice_remap_x", "preslice_remap_y", "preslice_remap_z",
|
|
||||||
"preslice_remap_global", "belt_support_z_offset_mode", "first_layer_plane",
|
|
||||||
"first_layer_plane_offset", "belt_preslice_global", "gcode_back_transform",
|
|
||||||
"belt_support_floor_mode", "first_layer_plane_thickness",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Keys renamed at some point, whose old and new spellings must never co-exist:
|
# Keys renamed at some point, whose old and new spellings must never co-exist:
|
||||||
|
|||||||
+1
-7
@@ -91,12 +91,6 @@ if (SLIC3R_GUI)
|
|||||||
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
||||||
|
|
||||||
find_package(wxInspector REQUIRED)
|
find_package(wxInspector REQUIRED)
|
||||||
# wxInspector 1.0.0 installs its headers but accidentally declares the
|
|
||||||
# INSTALL_INTERFACE include directory PRIVATE, so its imported target does
|
|
||||||
# not expose them to consumers. Restore the package prefix include path until
|
|
||||||
# the upstream export is fixed.
|
|
||||||
get_filename_component(WXINSPECTOR_PREFIX "${wxInspector_DIR}/../../.." ABSOLUTE)
|
|
||||||
target_include_directories(wxInspector::wxInspector INTERFACE "${WXINSPECTOR_PREFIX}/include")
|
|
||||||
|
|
||||||
# wxInspector's exported interface names the release wxWidgets import
|
# wxInspector's exported interface names the release wxWidgets import
|
||||||
# libraries, which a Debug build cannot link. wx is linked above instead.
|
# libraries, which a Debug build cannot link. wx is linked above instead.
|
||||||
@@ -192,7 +186,7 @@ endif ()
|
|||||||
# Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries.
|
# Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries.
|
||||||
if (SLIC3R_GUI)
|
if (SLIC3R_GUI)
|
||||||
# target_link_libraries(OrcaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES})
|
# target_link_libraries(OrcaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES})
|
||||||
target_link_libraries(OrcaSlicer libslic3r_gui wxInspector::wxInspector)
|
target_link_libraries(OrcaSlicer libslic3r_gui)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Generate debug symbols even in release mode.
|
# Generate debug symbols even in release mode.
|
||||||
target_link_options(OrcaSlicer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
target_link_options(OrcaSlicer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||||
|
|||||||
+13
-46
@@ -3435,14 +3435,9 @@ int CLI::run(int argc, char **argv)
|
|||||||
max_self_index = std::max(max_self_index, v);
|
max_self_index = std::max(max_self_index, v);
|
||||||
min_self_index = std::min(min_self_index, v);
|
min_self_index = std::min(min_self_index, v);
|
||||||
}
|
}
|
||||||
// And a project saved with FEWER filaments than are now loaded (a
|
if (max_self_index > filament_count || min_self_index < 1) {
|
||||||
// one-filament project sliced with two --load-filaments) leaves the tables half filled:
|
BOOST_LOG_TRIVIAL(warning) << boost::format("filament_self_index range [%1%, %2%] is invalid for filament_count %3%, regenerating")
|
||||||
// the variant matching below then reads past filament_extruder_variant and
|
% min_self_index % max_self_index % filament_count;
|
||||||
// set_with_restore_2 throws an uncaught size error. Regenerate in that case too.
|
|
||||||
if (max_self_index > filament_count || min_self_index < 1 || max_self_index < filament_count
|
|
||||||
|| (int) filament_self_index_opt->values.size() < filament_count) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << boost::format("filament_self_index range [%1%, %2%] (size %4%) is invalid for filament_count %3%, regenerating")
|
|
||||||
% min_self_index % max_self_index % filament_count % filament_self_index_opt->values.size();
|
|
||||||
need_regenerate_self_index = true;
|
need_regenerate_self_index = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3533,10 +3528,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
std::vector<std::string>& filament_variants = curr_variant_opt->values;
|
std::vector<std::string>& filament_variants = curr_variant_opt->values;
|
||||||
filament_variants.resize(filament_count, get_extruder_variant_string(etDirectDrive, nvtStandard));
|
filament_variants.resize(filament_count, get_extruder_variant_string(etDirectDrive, nvtStandard));
|
||||||
}
|
}
|
||||||
// See the filament_self_index note above: one variant per filament for
|
|
||||||
// the filaments the project did not know about.
|
|
||||||
if ((int) curr_variant_opt->values.size() < filament_count)
|
|
||||||
curr_variant_opt->values.resize(filament_count, get_extruder_variant_string(etDirectDrive, nvtStandard));
|
|
||||||
const ConfigOptionStrings *new_variant_opt = dynamic_cast<const ConfigOptionStrings*>(config.option("filament_extruder_variant", true));
|
const ConfigOptionStrings *new_variant_opt = dynamic_cast<const ConfigOptionStrings*>(config.option("filament_extruder_variant", true));
|
||||||
|
|
||||||
std::vector<int> new_variant_indice;
|
std::vector<int> new_variant_indice;
|
||||||
@@ -3545,7 +3536,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
|
|
||||||
for (int i = 0; i < new_variant_count; i++)
|
for (int i = 0; i < new_variant_count; i++)
|
||||||
{
|
{
|
||||||
for (int j = old_start_indice[filament_index - 1]; j < old_start_indice[filament_index - 1] + old_variant_count && j < (int) curr_variant_opt->values.size(); j++)
|
for (int j = old_start_indice[filament_index - 1]; j < old_start_indice[filament_index - 1] + old_variant_count; j++)
|
||||||
{
|
{
|
||||||
if (curr_variant_opt->values[j] == new_variant_opt->values[i]) {
|
if (curr_variant_opt->values[j] == new_variant_opt->values[i]) {
|
||||||
new_variant_indice[i] = j;
|
new_variant_indice[i] = j;
|
||||||
@@ -3597,18 +3588,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt);
|
ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt);
|
||||||
const ConfigOptionVectorBase* opt_vec_src = static_cast<const ConfigOptionVectorBase*>(source_opt);
|
const ConfigOptionVectorBase* opt_vec_src = static_cast<const ConfigOptionVectorBase*>(source_opt);
|
||||||
//set with index
|
//set with index
|
||||||
try {
|
opt_vec_dst->set_with_restore_2(opt_vec_src, new_variant_indice, old_start_indice[filament_index - 1], old_variant_count);
|
||||||
// A project with fewer filaments than are loaded: grow the
|
|
||||||
// destination to the filament's slot first (set_with_restore_2 only restores).
|
|
||||||
if (opt_vec_src->size() > 0 && opt_vec_dst->size() < size_t(old_start_indice[filament_index - 1] + old_variant_count))
|
|
||||||
opt_vec_dst->resize(size_t(old_start_indice[filament_index - 1] + old_variant_count), opt_vec_src);
|
|
||||||
opt_vec_dst->set_with_restore_2(opt_vec_src, new_variant_indice, old_start_indice[filament_index - 1], old_variant_count);
|
|
||||||
} catch (const std::exception &ex) { // Was an uncaught abort
|
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("filament %1%: option %2% could not be applied: %3%") % filament_index % opt_key % ex.what();
|
|
||||||
boost::nowide::cerr << "filament " << filament_index << ": option " << opt_key << " could not be applied: " << ex.what() << std::endl;
|
|
||||||
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info);
|
|
||||||
flush_and_exit(CLI_CONFIG_FILE_ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -3657,16 +3637,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
if (filament_options_with_variant.find(opt_key) != filament_options_with_variant.end()) {
|
if (filament_options_with_variant.find(opt_key) != filament_options_with_variant.end()) {
|
||||||
std::vector<int> temp_variant_indice;
|
std::vector<int> temp_variant_indice;
|
||||||
temp_variant_indice.resize(new_variant_count, -1);
|
temp_variant_indice.resize(new_variant_count, -1);
|
||||||
try {
|
opt_vec_dst->set_with_restore_2(opt_vec_src, temp_variant_indice, old_start_indice[filament_index - 1], old_variant_count, true);
|
||||||
if (opt_vec_src->size() > 0 && opt_vec_dst->size() < size_t(old_start_indice[filament_index - 1] + old_variant_count)) // See above
|
|
||||||
opt_vec_dst->resize(size_t(old_start_indice[filament_index - 1] + old_variant_count), opt_vec_src);
|
|
||||||
opt_vec_dst->set_with_restore_2(opt_vec_src, temp_variant_indice, old_start_indice[filament_index - 1], old_variant_count, true);
|
|
||||||
} catch (const std::exception &ex) { // Was an uncaught abort
|
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("filament %1%: option %2% could not be applied: %3%") % filament_index % opt_key % ex.what();
|
|
||||||
boost::nowide::cerr << "filament " << filament_index << ": option " << opt_key << " could not be applied: " << ex.what() << std::endl;
|
|
||||||
record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info);
|
|
||||||
flush_and_exit(CLI_CONFIG_FILE_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_key == "filament_extruder_variant")
|
if (opt_key == "filament_extruder_variant")
|
||||||
new_variant_counts[filament_index - 1] = opt_vec_src->size();
|
new_variant_counts[filament_index - 1] = opt_vec_src->size();
|
||||||
@@ -4182,10 +4153,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%, set disable_wipe_tower_after_mapping back to false due to wrapping detect")%__LINE__;
|
BOOST_LOG_TRIVIAL(info) << boost::format("%1%, set disable_wipe_tower_after_mapping back to false due to wrapping detect")%__LINE__;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Belt printers never get the classic wipe tower (see Print::has_wipe_tower()), so reserve no space for it.
|
|
||||||
const ConfigOptionBool* belt_printer_opt = m_print_config.option<ConfigOptionBool>("belt_printer");
|
|
||||||
const bool is_belt_printer = belt_printer_opt && belt_printer_opt->value;
|
|
||||||
|
|
||||||
auto timelapse_type_opt = m_print_config.option("timelapse_type");
|
auto timelapse_type_opt = m_print_config.option("timelapse_type");
|
||||||
bool is_smooth_timelapse = false;
|
bool is_smooth_timelapse = false;
|
||||||
if (enable_timelapse && timelapse_type_opt && (timelapse_type_opt->getInt() == TimelapseType::tlSmooth))
|
if (enable_timelapse && timelapse_type_opt && (timelapse_type_opt->getInt() == TimelapseType::tlSmooth))
|
||||||
@@ -4423,11 +4390,11 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto check_plate_wipe_tower = [get_print_sequence, is_smooth_timelapse, is_belt_printer](Slic3r::GUI::PartPlate* plate, int plate_index, DynamicPrintConfig& print_config, plate_obj_size_info_t &plate_obj_size_info) {
|
auto check_plate_wipe_tower = [get_print_sequence, is_smooth_timelapse](Slic3r::GUI::PartPlate* plate, int plate_index, DynamicPrintConfig& print_config, plate_obj_size_info_t &plate_obj_size_info) {
|
||||||
plate_obj_size_info.obj_bbox= plate->get_objects_bounding_box();
|
plate_obj_size_info.obj_bbox= plate->get_objects_bounding_box();
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, object bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}")
|
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, object bbox: min {%2%, %3%, %4%} - max {%5%, %6%, %7%}")
|
||||||
%(plate_index+1) %plate_obj_size_info.obj_bbox.min.x() % plate_obj_size_info.obj_bbox.min.y() % plate_obj_size_info.obj_bbox.min.z() %plate_obj_size_info.obj_bbox.max.x() % plate_obj_size_info.obj_bbox.max.y() % plate_obj_size_info.obj_bbox.max.z();
|
%(plate_index+1) %plate_obj_size_info.obj_bbox.min.x() % plate_obj_size_info.obj_bbox.min.y() % plate_obj_size_info.obj_bbox.min.z() %plate_obj_size_info.obj_bbox.max.x() % plate_obj_size_info.obj_bbox.max.y() % plate_obj_size_info.obj_bbox.max.z();
|
||||||
if (is_belt_printer || !print_config.has("wipe_tower_x")) {
|
if (!print_config.has("wipe_tower_x")) {
|
||||||
plate_obj_size_info.has_wipe_tower = false;
|
plate_obj_size_info.has_wipe_tower = false;
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("can not found wipe_tower_x in config, set to no wipe tower");
|
BOOST_LOG_TRIVIAL(info) << boost::format("can not found wipe_tower_x in config, set to no wipe tower");
|
||||||
return;
|
return;
|
||||||
@@ -5298,7 +5265,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_belt_printer && ((!arrange_cfg.is_seq_print && (assemble_plate.filaments_count > 1)) || (enable_wrapping_detect && !current_wrapping_exclude_area.empty())))
|
if ((!arrange_cfg.is_seq_print && (assemble_plate.filaments_count > 1))||(enable_wrapping_detect && !current_wrapping_exclude_area.empty()))
|
||||||
{
|
{
|
||||||
//prepare the wipe tower
|
//prepare the wipe tower
|
||||||
int plate_count = partplate_list.get_plate_count();
|
int plate_count = partplate_list.get_plate_count();
|
||||||
@@ -5450,7 +5417,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
bool is_seq_print = false;
|
bool is_seq_print = false;
|
||||||
get_print_sequence(cur_plate, m_print_config, is_seq_print);
|
get_print_sequence(cur_plate, m_print_config, is_seq_print);
|
||||||
|
|
||||||
if (!is_belt_printer && !is_seq_print && (assemble_plate.filaments_count > 1) && !has_wipe_tower_position)
|
if (!is_seq_print && (assemble_plate.filaments_count > 1) && !has_wipe_tower_position)
|
||||||
{
|
{
|
||||||
//prepare the wipe tower
|
//prepare the wipe tower
|
||||||
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
||||||
@@ -5618,7 +5585,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
};
|
};
|
||||||
const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0;
|
const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0;
|
||||||
|
|
||||||
if (!is_belt_printer && plate_needs_wipe_tower(max_filament_count))
|
if (plate_needs_wipe_tower(max_filament_count))
|
||||||
{
|
{
|
||||||
//prepare the wipe tower
|
//prepare the wipe tower
|
||||||
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
||||||
@@ -5725,7 +5692,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found single object mode");
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found single object mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_belt_printer && m_print_config.has("wipe_tower_x") && (is_smooth_timelapse || !arrange_cfg.is_seq_print || (selected.size() <= 1))) {
|
if (m_print_config.has("wipe_tower_x") && (is_smooth_timelapse || !arrange_cfg.is_seq_print || (selected.size() <= 1))) {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
if (duplicate_count > 0) {
|
if (duplicate_count > 0) {
|
||||||
@@ -6350,7 +6317,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
// The stored (or default) tower position may not fit the tower these plates
|
// The stored (or default) tower position may not fit the tower these plates
|
||||||
// need, and no CLI placement site runs on a plain slice - mirror the GUI's
|
// need, and no CLI placement site runs on a plain slice - mirror the GUI's
|
||||||
// reload clamp and fit every plate's tower into the printable area first.
|
// reload clamp and fit every plate's tower into the printable area first.
|
||||||
if (!is_belt_printer && m_print_config.option<ConfigOptionBool>("enable_prime_tower", true)->value) {
|
if (m_print_config.option<ConfigOptionBool>("enable_prime_tower", true)->value) {
|
||||||
for (int index = 0; index < partplate_list.get_plate_count(); index++) {
|
for (int index = 0; index < partplate_list.get_plate_count(); index++) {
|
||||||
if ((plate_to_slice != 0) && (plate_to_slice != (index + 1)))
|
if ((plate_to_slice != 0) && (plate_to_slice != (index + 1)))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ Vec2d place_wipe_tower(DynamicPrintConfig &cfg, const Vec2d ¢er)
|
|||||||
std::string slice_two_color_cube_and_export(DynamicPrintConfig cfg, bool is_bbl, bool by_object)
|
std::string slice_two_color_cube_and_export(DynamicPrintConfig cfg, bool is_bbl, bool by_object)
|
||||||
{
|
{
|
||||||
const Vec2d center = printable_area_center(cfg);
|
const Vec2d center = printable_area_center(cfg);
|
||||||
const bool belt = cfg.opt_bool("belt_printer");
|
|
||||||
std::vector<Vec2d> cube_mins;
|
std::vector<Vec2d> cube_mins;
|
||||||
if (by_object) {
|
if (by_object) {
|
||||||
// By-object printing fires the hook only without a wipe tower, and rules out clumping detection and
|
// By-object printing fires the hook only without a wipe tower, and rules out clumping detection and
|
||||||
@@ -213,12 +212,6 @@ std::string slice_two_color_cube_and_export(DynamicPrintConfig cfg, bool is_bbl,
|
|||||||
cfg.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
|
cfg.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
|
||||||
cfg.set_key_value("skirt_loops", new ConfigOptionInt(0));
|
cfg.set_key_value("skirt_loops", new ConfigOptionInt(0));
|
||||||
cube_mins = {center + Vec2d(-20., -5.), center + Vec2d(10., -5.)};
|
cube_mins = {center + Vec2d(-20., -5.), center + Vec2d(10., -5.)};
|
||||||
} else if (belt) {
|
|
||||||
// A belt object's slicing Z starts at the belt below its leading end, well below its first
|
|
||||||
// printed layer, so a height range in slicing Z does not map onto the part. Two cubes one
|
|
||||||
// behind the other along the belt, the second on filament 2, give the one filament change
|
|
||||||
// instead (the purge prism is an object the GUI adds, so there is no tower to place).
|
|
||||||
cube_mins = {center - Vec2d(5., 15.), center + Vec2d(-5., 5.)};
|
|
||||||
} else {
|
} else {
|
||||||
// Clumping detection changes the tower footprint, so turn it on before placing the tower.
|
// Clumping detection changes the tower footprint, so turn it on before placing the tower.
|
||||||
if (!cfg.opt_string("wrapping_detection_gcode").empty())
|
if (!cfg.opt_string("wrapping_detection_gcode").empty())
|
||||||
@@ -236,20 +229,14 @@ std::string slice_two_color_cube_and_export(DynamicPrintConfig cfg, bool is_bbl,
|
|||||||
obj->name = "cube"; // populates [input_filename_base] the way a loaded model does
|
obj->name = "cube"; // populates [input_filename_base] the way a loaded model does
|
||||||
obj->add_volume(m);
|
obj->add_volume(m);
|
||||||
obj->add_instance();
|
obj->add_instance();
|
||||||
if (belt && !by_object) {
|
// Filament 2 is used only above z=4, so the upper layers carry a single filament change.
|
||||||
// The second cube along the belt is on filament 2 (see cube_mins above).
|
DynamicPrintConfig range_config;
|
||||||
if (&cube_min == &cube_mins.back())
|
range_config.set_key_value("extruder", new ConfigOptionInt(2));
|
||||||
obj->config.set_key_value("extruder", new ConfigOptionInt(2));
|
// Every range must carry a layer_height; use the process's own so a fine nozzle (e.g. 0.15 mm
|
||||||
} else {
|
// printing ~0.1 mm layers) isn't forced to a height its extrusion width can't support - that
|
||||||
// Filament 2 is used only above z=4, so the upper layers carry a single filament change.
|
// trips Flow::with_spacing.
|
||||||
DynamicPrintConfig range_config;
|
range_config.set_key_value("layer_height", new ConfigOptionFloat(cfg.opt_float("layer_height")));
|
||||||
range_config.set_key_value("extruder", new ConfigOptionInt(2));
|
obj->layer_config_ranges[{4.0, 10.0}].assign_config(std::move(range_config));
|
||||||
// Every range must carry a layer_height; use the process's own so a fine nozzle (e.g. 0.15 mm
|
|
||||||
// printing ~0.1 mm layers) isn't forced to a height its extrusion width can't support - that
|
|
||||||
// trips Flow::with_spacing.
|
|
||||||
range_config.set_key_value("layer_height", new ConfigOptionFloat(cfg.opt_float("layer_height")));
|
|
||||||
obj->layer_config_ranges[{4.0, 10.0}].assign_config(std::move(range_config));
|
|
||||||
}
|
|
||||||
obj->ensure_on_bed();
|
obj->ensure_on_bed();
|
||||||
print.auto_assign_extruders(obj);
|
print.auto_assign_extruders(obj);
|
||||||
}
|
}
|
||||||
@@ -534,16 +521,11 @@ int slice_all_printers(const std::string &vendor, const std::string &outdir)
|
|||||||
const std::string filament_name = bundle.filaments.get_selected_preset_name();
|
const std::string filament_name = bundle.filaments.get_selected_preset_name();
|
||||||
const std::string what = "Printer \"" + printer + "\"";
|
const std::string what = "Printer \"" + printer + "\"";
|
||||||
const std::string file_base = sanitize_filename(vendor_name) + "__" + sanitize_filename(printer);
|
const std::string file_base = sanitize_filename(vendor_name) + "__" + sanitize_filename(printer);
|
||||||
// A belt printer has no wipe tower (it purges into a prism object on the belt), so its
|
|
||||||
// filament change is the plain tool change set_extruder() emits rather than the tower's block.
|
|
||||||
const bool belt = bundle.printers.get_selected_preset().config.opt_bool("belt_printer");
|
|
||||||
const std::string marker = belt ? "\nT1\n" : "CP TOOLCHANGE START";
|
|
||||||
if (const std::string out = slice_selection(bundle, what, false, outdir, file_base); out.empty())
|
if (const std::string out = slice_selection(bundle, what, false, outdir, file_base); out.empty())
|
||||||
++failures;
|
++failures;
|
||||||
else if (out.find(marker) == std::string::npos) {
|
else if (out.find("CP TOOLCHANGE START") == std::string::npos) {
|
||||||
// The filament change never fired, so change_filament_gcode was not exercised.
|
// The filament change never rode the tower, so change_filament_gcode was not exercised.
|
||||||
BOOST_LOG_TRIVIAL(error) << what << " sliced but the filament change never fired (no "
|
BOOST_LOG_TRIVIAL(error) << what << " sliced but the filament change never fired (no CP TOOLCHANGE START)";
|
||||||
<< (belt ? "T1" : "CP TOOLCHANGE START") << ")";
|
|
||||||
++failures;
|
++failures;
|
||||||
}
|
}
|
||||||
cover(bundle.prints.get_selected_preset());
|
cover(bundle.prints.get_selected_preset());
|
||||||
|
|||||||
@@ -299,15 +299,7 @@ Points get_shrink_bedpts(const DynamicPrintConfig* print_cfg, const ArrangeParam
|
|||||||
template<class PConf>
|
template<class PConf>
|
||||||
void fill_config(PConf& pcfg, const ArrangeParams ¶ms) {
|
void fill_config(PConf& pcfg, const ArrangeParams ¶ms) {
|
||||||
|
|
||||||
if (params.is_belt) {
|
if (params.is_seq_print) {
|
||||||
// Pack from the end of the belt that prints first, and keep the pile on the
|
|
||||||
// bed when it is larger than the room around that end.
|
|
||||||
pcfg.starting_point = !params.belt_reversed ? PConf::Alignment::BOTTOM_LEFT :
|
|
||||||
params.belt_axis == 1 ? PConf::Alignment::TOP_LEFT :
|
|
||||||
PConf::Alignment::BOTTOM_RIGHT;
|
|
||||||
pcfg.clamp_to_bin = true;
|
|
||||||
}
|
|
||||||
else if (params.is_seq_print) {
|
|
||||||
// Start placing the items from the center of the print bed
|
// Start placing the items from the center of the print bed
|
||||||
pcfg.starting_point = PConf::Alignment::BOTTOM_LEFT;
|
pcfg.starting_point = PConf::Alignment::BOTTOM_LEFT;
|
||||||
}
|
}
|
||||||
@@ -452,50 +444,6 @@ protected:
|
|||||||
return bindist;
|
return bindist;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Belt printers pack from the end of the belt that prints first, and a corner
|
|
||||||
// packer's checks (pile inside the bin, pack origin) apply to them as well.
|
|
||||||
bool corner_packing() const { return params.is_belt || m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT; }
|
|
||||||
|
|
||||||
static double at(const Box::PointType &pt, int i) { return double(i == 0 ? getX(pt) : getY(pt)); }
|
|
||||||
|
|
||||||
// Position along the belt in print order: increasing from the end that prints first.
|
|
||||||
double belt_pos(const Box::PointType &pt) const { return params.belt_reversed ? -at(pt, params.belt_axis) : at(pt, params.belt_axis); }
|
|
||||||
double belt_start(const Box &bb) const { return belt_pos(params.belt_reversed ? bb.maxCorner() : bb.minCorner()); }
|
|
||||||
double belt_end(const Box &bb) const { return belt_pos(params.belt_reversed ? bb.minCorner() : bb.maxCorner()); }
|
|
||||||
|
|
||||||
// The corner of the bin the belt pile grows from.
|
|
||||||
Box::PointType belt_origin() const
|
|
||||||
{
|
|
||||||
const Box bb = sl::boundingBox(m_bin);
|
|
||||||
auto o = bb.minCorner();
|
|
||||||
if (params.belt_reversed) {
|
|
||||||
if (params.belt_axis == 0) setX(o, getX(bb.maxCorner()));
|
|
||||||
else setY(o, getY(bb.maxCorner()));
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An item's far edge in print order is what it costs (so a row fills across the
|
|
||||||
// belt before the pile advances), with a slight pull toward the near lateral
|
|
||||||
// edge and the same penalty as the bottom-left heuristic for sitting outside
|
|
||||||
// the corner.
|
|
||||||
double dist_along_belt(const Box &ibb)
|
|
||||||
{
|
|
||||||
const Box bin = sl::boundingBox(m_bin);
|
|
||||||
const int l = 1 - params.belt_axis;
|
|
||||||
const double lat = at(ibb.minCorner(), l) - at(bin.minCorner(), l);
|
|
||||||
double d = belt_end(ibb) - belt_start(bin);
|
|
||||||
d += lat < 0 ? 10 * -lat : 0.1 * lat;
|
|
||||||
if (double behind = belt_start(ibb) - belt_start(bin); behind < 0)
|
|
||||||
d += 10 * -behind;
|
|
||||||
return norm(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
double corner_bindist(const Box &ibb, const Slic3r::Point &origin_pack)
|
|
||||||
{
|
|
||||||
return params.is_belt ? dist_along_belt(ibb) : dist_for_BOTTOM_LEFT(ibb, origin_pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
double dist_to_bin(const Box& ibb, const Slic3r::Point& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment)
|
double dist_to_bin(const Box& ibb, const Slic3r::Point& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment)
|
||||||
{
|
{
|
||||||
double bindist = 0;
|
double bindist = 0;
|
||||||
@@ -585,8 +533,8 @@ protected:
|
|||||||
|
|
||||||
// The smalles distance from the arranged pile center:
|
// The smalles distance from the arranged pile center:
|
||||||
double dist = norm(*(std::min_element(dists.begin(), dists.end())));
|
double dist = norm(*(std::min_element(dists.begin(), dists.end())));
|
||||||
if (corner_packing()) {
|
if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT) {
|
||||||
double bindist = corner_bindist(ibb, origin_pack);
|
double bindist = dist_for_BOTTOM_LEFT(ibb, origin_pack);
|
||||||
score = 0.2 * dist + 0.8 * bindist;
|
score = 0.2 * dist + 0.8 * bindist;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -643,8 +591,8 @@ protected:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LAST_BIG_ITEM: {
|
case LAST_BIG_ITEM: {
|
||||||
if (corner_packing()) {
|
if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT) {
|
||||||
score = corner_bindist(ibb, origin_pack);
|
score = dist_for_BOTTOM_LEFT(ibb, origin_pack);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (m_pilebb.defined)
|
if (m_pilebb.defined)
|
||||||
@@ -659,8 +607,8 @@ protected:
|
|||||||
// already processed bigger items.
|
// already processed bigger items.
|
||||||
// No need to play around with the anchor points, the center will be
|
// No need to play around with the anchor points, the center will be
|
||||||
// just fine for small items
|
// just fine for small items
|
||||||
if (corner_packing())
|
if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT)
|
||||||
score = corner_bindist(ibb, origin_pack);
|
score = dist_for_BOTTOM_LEFT(ibb, origin_pack);
|
||||||
else {
|
else {
|
||||||
// Align mainly around existing items
|
// Align mainly around existing items
|
||||||
score = 0.8 * norm(pl::distance(ibb.center(), bigbb.center()))+ 0.2*norm(pl::distance(ibb.center(), origin_pack));
|
score = 0.8 * norm(pl::distance(ibb.center(), bigbb.center()))+ 0.2*norm(pl::distance(ibb.center(), origin_pack));
|
||||||
@@ -761,28 +709,6 @@ protected:
|
|||||||
score += 1 * (new_extruder_cnt-last_extruder_cnt);
|
score += 1 * (new_extruder_cnt-last_extruder_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On a belt the parts print in belt order, so every colour change between
|
|
||||||
// parts is a filament change. Items arrive sorted by extruder and the pile
|
|
||||||
// grows from the leading end; keep each colour's run contiguous by charging
|
|
||||||
// an item for every packed item of another colour it does not fully follow,
|
|
||||||
// counting the tilted layers that reach belt_tilt_slope * height past that
|
|
||||||
// item's far edge.
|
|
||||||
if (params.is_belt && !params.is_seq_print) {
|
|
||||||
const std::set<int> item_colours(item.extrude_ids.begin(), item.extrude_ids.end());
|
|
||||||
const double item_start = belt_start(ibb);
|
|
||||||
for (Item &p : m_items) {
|
|
||||||
if (p.is_virt_object)
|
|
||||||
continue;
|
|
||||||
const std::set<int> p_colours(p.extrude_ids.begin(), p.extrude_ids.end());
|
|
||||||
const bool same_colour = std::includes(item_colours.begin(), item_colours.end(), p_colours.begin(), p_colours.end())
|
|
||||||
|| std::includes(p_colours.begin(), p_colours.end(), item_colours.begin(), item_colours.end());
|
|
||||||
if (same_colour)
|
|
||||||
continue;
|
|
||||||
if (item_start < belt_end(p.boundingBox()) + scaled(p.height * params.belt_tilt_slope))
|
|
||||||
score += 10.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_tuple(score, fullbb);
|
return std::make_tuple(score, fullbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -859,8 +785,7 @@ public:
|
|||||||
|
|
||||||
auto binbb = sl::boundingBox(m_bin);
|
auto binbb = sl::boundingBox(m_bin);
|
||||||
|
|
||||||
auto starting_point = this->params.is_belt ? belt_origin() :
|
auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? binbb.minCorner() : binbb.center();
|
||||||
cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? binbb.minCorner() : binbb.center();
|
|
||||||
// if we have wipe tower, items should be arranged around wipe tower
|
// if we have wipe tower, items should be arranged around wipe tower
|
||||||
for (Item itm : items) {
|
for (Item itm : items) {
|
||||||
if (itm.is_wipe_tower) {
|
if (itm.is_wipe_tower) {
|
||||||
@@ -1011,7 +936,7 @@ std::function<double(const Item &, const ItemGroup&)> AutoArranger<ExPolygon>::g
|
|||||||
auto mp = m_merged_pile;
|
auto mp = m_merged_pile;
|
||||||
mp.emplace_back(itm.transformedShape());
|
mp.emplace_back(itm.transformedShape());
|
||||||
auto chull = sl::convexHull(mp);
|
auto chull = sl::convexHull(mp);
|
||||||
if (corner_packing())
|
if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT)
|
||||||
{
|
{
|
||||||
if (!sl::isInside(chull, m_bin))
|
if (!sl::isInside(chull, m_bin))
|
||||||
score += LARGE_COST_TO_REJECT;
|
score += LARGE_COST_TO_REJECT;
|
||||||
|
|||||||
@@ -146,13 +146,6 @@ struct ArrangeParams {
|
|||||||
float nozzle_height = 0;
|
float nozzle_height = 0;
|
||||||
float printable_height = 256.0;
|
float printable_height = 256.0;
|
||||||
Vec2d align_center{ 0.5,0.5 };
|
Vec2d align_center{ 0.5,0.5 };
|
||||||
// Belt printer: items print in the order they lie along the belt axis, from
|
|
||||||
// its low end unless belt_reversed, and a part's top prints
|
|
||||||
// belt_tilt_slope * height further along it than its base.
|
|
||||||
bool is_belt = false;
|
|
||||||
int belt_axis = 1; // 0 = X, 1 = Y
|
|
||||||
bool belt_reversed = false;
|
|
||||||
float belt_tilt_slope = 1.f; // cot(belt tilt angle), 0 when the belt is not tilted
|
|
||||||
|
|
||||||
ArrangePolygons excluded_regions; // regions cant't be used
|
ArrangePolygons excluded_regions; // regions cant't be used
|
||||||
ArrangePolygons nonprefered_regions; // regions can be used but not prefered
|
ArrangePolygons nonprefered_regions; // regions can be used but not prefered
|
||||||
|
|||||||
@@ -1,562 +0,0 @@
|
|||||||
#include <limits>
|
|
||||||
#include "BeltBrim.hpp"
|
|
||||||
|
|
||||||
#include "ClipperUtils.hpp"
|
|
||||||
#include "Flow.hpp"
|
|
||||||
#include "Layer.hpp"
|
|
||||||
#include "Polygon.hpp"
|
|
||||||
#include "Print.hpp"
|
|
||||||
#include "ShortestPath.hpp"
|
|
||||||
#include "Support/BeltFloorContext.hpp"
|
|
||||||
#include "BoundingBox.hpp"
|
|
||||||
#include "ExPolygon.hpp"
|
|
||||||
#include "ExtrusionEntity.hpp"
|
|
||||||
#include "ExtrusionEntityCollection.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "Polyline.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "libslic3r.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- scaling
|
|
||||||
|
|
||||||
static inline Point scale_u_point(const Point &p, int from_axis, double factor)
|
|
||||||
{
|
|
||||||
// llround, not a cast: casting truncates toward zero, so a round trip would
|
|
||||||
// walk every vertex toward the origin by up to one unit per pass.
|
|
||||||
return from_axis == 0 ?
|
|
||||||
Point(coord_t(std::llround(double(p.x()) * factor)), p.y()) :
|
|
||||||
Point(p.x(), coord_t(std::llround(double(p.y()) * factor)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void scale_u_polygon(Polygon &poly, int from_axis, double factor)
|
|
||||||
{
|
|
||||||
for (Point &p : poly.points)
|
|
||||||
p = scale_u_point(p, from_axis, factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExPolygons belt_scale_u(const ExPolygons &src, const BeltBrimFrame &frame, double factor)
|
|
||||||
{
|
|
||||||
ExPolygons out = src;
|
|
||||||
for (ExPolygon &ex : out) {
|
|
||||||
scale_u_polygon(ex.contour, frame.from_axis, factor);
|
|
||||||
for (Polygon &hole : ex.holes)
|
|
||||||
scale_u_polygon(hole, frame.from_axis, factor);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
Polylines belt_scale_u(const Polylines &src, const BeltBrimFrame &frame, double factor)
|
|
||||||
{
|
|
||||||
Polylines out = src;
|
|
||||||
for (Polyline &pl : out)
|
|
||||||
for (Point &p : pl.points)
|
|
||||||
p = scale_u_point(p, frame.from_axis, factor);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- sweep
|
|
||||||
|
|
||||||
ExPolygons sweep_ex(const ExPolygons &src, const Point &t)
|
|
||||||
{
|
|
||||||
if (src.empty())
|
|
||||||
return {};
|
|
||||||
if (t == Point(0, 0))
|
|
||||||
return src;
|
|
||||||
|
|
||||||
// One parallelogram per boundary edge. Together with P and P + t these
|
|
||||||
// cover the Minkowski sum exactly: for any q = p + s*t with p in P and
|
|
||||||
// s in [0, 1], let s* be the smallest lambda >= 0 with q - lambda*t in P.
|
|
||||||
// Either s* == 0 (so q is in P) or q - s* * t lies on some boundary edge e,
|
|
||||||
// putting q in that edge's parallelogram. Hole edges must be included, or
|
|
||||||
// holes narrower than t along t would wrongly survive the sweep.
|
|
||||||
Polygons quads;
|
|
||||||
for (const ExPolygon &ex : src)
|
|
||||||
for (size_t c = 0; c < ex.num_contours(); ++ c)
|
|
||||||
for (const Line &e : ex.contour_or_hole(c).lines()) {
|
|
||||||
if (e.a == e.b)
|
|
||||||
continue;
|
|
||||||
Polygon q;
|
|
||||||
q.points = { e.a, e.b, e.b + t, e.a + t };
|
|
||||||
// The non-zero fill rule counts a clockwise ring as -1, which
|
|
||||||
// would punch a hole instead of adding material. Edges parallel
|
|
||||||
// to t give a zero-area quad; Clipper discards those harmlessly.
|
|
||||||
if (q.is_clockwise())
|
|
||||||
q.reverse();
|
|
||||||
quads.emplace_back(std::move(q));
|
|
||||||
}
|
|
||||||
|
|
||||||
ExPolygons shifted = src;
|
|
||||||
for (ExPolygon &ex : shifted)
|
|
||||||
ex.translate(t);
|
|
||||||
|
|
||||||
// union_ex(ExPolygons, Polygons) uses pftNonZero, which is the fill rule the
|
|
||||||
// argument above relies on.
|
|
||||||
return union_ex(union_ex(src, shifted), quads);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- brim region
|
|
||||||
|
|
||||||
ExPolygons belt_brim_region(const ExPolygons &footprint_flat,
|
|
||||||
bool has_outer,
|
|
||||||
bool has_inner,
|
|
||||||
coord_t brim_width,
|
|
||||||
coord_t object_gap,
|
|
||||||
coord_t leading,
|
|
||||||
coord_t lateral,
|
|
||||||
const BeltBrimFrame &frame)
|
|
||||||
{
|
|
||||||
if (footprint_flat.empty() || (! has_outer && ! has_inner))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
ExPolygons out;
|
|
||||||
|
|
||||||
if (has_outer) {
|
|
||||||
// Offset the outer ring from the contours only, so a hole cannot punch
|
|
||||||
// through it. Same reasoning as the plate brim in Brim.cpp.
|
|
||||||
Polygons contours;
|
|
||||||
contours.reserve(footprint_flat.size());
|
|
||||||
for (const ExPolygon &ex : footprint_flat)
|
|
||||||
contours.emplace_back(ex.contour);
|
|
||||||
|
|
||||||
// Inner and outer boundary offset from the same polygon, to avoid
|
|
||||||
// round-off mismatch between them.
|
|
||||||
ExPolygons inner = offset_ex(contours, float(object_gap), jtRound, SCALED_RESOLUTION);
|
|
||||||
|
|
||||||
// Close the interior before offsetting outwards. A belt contact patch is often a
|
|
||||||
// narrow, broken-up strip, and the offset rings of two islands less than
|
|
||||||
// 2 x brim_width apart merge and fill the space between them - space that lies
|
|
||||||
// UNDER the part, which is not what "outer brim" means. Closing also swallows
|
|
||||||
// holes in the patch for the same reason. Concavity-filling only, so an apron or
|
|
||||||
// any other outward protrusion is untouched.
|
|
||||||
ExPolygons envelope = brim_width > 0 ? closing_ex(inner, float(brim_width)) : inner;
|
|
||||||
|
|
||||||
ExPolygons base = envelope;
|
|
||||||
if (leading > 0) {
|
|
||||||
// Sweep downhill from the gapped keep-out, so the apron is contiguous with
|
|
||||||
// the ring instead of starting inside the gap.
|
|
||||||
const Point t = frame.from_axis == 0 ?
|
|
||||||
Point(frame.downhill_sign() * leading, 0) :
|
|
||||||
Point(0, frame.downhill_sign() * leading);
|
|
||||||
base = union_ex(base, sweep_ex(envelope, t));
|
|
||||||
}
|
|
||||||
if (lateral > 0) {
|
|
||||||
// Across the belt, both ways. Swept from `base` so the apron is widened
|
|
||||||
// too, and in the flattened frame the cross-belt axis is unscaled, so this
|
|
||||||
// distance is already a true on-belt distance.
|
|
||||||
const Point t = frame.from_axis == 0 ? Point(0, lateral) : Point(lateral, 0);
|
|
||||||
ExPolygons widened = union_ex(sweep_ex(base, t), sweep_ex(base, Point(-t.x(), -t.y())));
|
|
||||||
base = union_ex(base, to_polygons(widened));
|
|
||||||
}
|
|
||||||
ExPolygons outer = offset_ex(base, float(brim_width), jtRound, SCALED_RESOLUTION);
|
|
||||||
expolygons_append(out, diff_ex(outer, envelope));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_inner) {
|
|
||||||
// Holes reversed so a negative offset grows inward, mirroring Brim.cpp.
|
|
||||||
// No apron here: an apron growing into a hole interior is never useful.
|
|
||||||
Polygons holes;
|
|
||||||
for (const ExPolygon &ex : footprint_flat)
|
|
||||||
polygons_append(holes, ex.holes);
|
|
||||||
polygons_reverse(holes);
|
|
||||||
if (! holes.empty()) {
|
|
||||||
ExPolygons hole_inner = offset_ex(holes, - float(brim_width + object_gap));
|
|
||||||
ExPolygons hole_outer = offset_ex(holes, - float(object_gap));
|
|
||||||
expolygons_append(out, intersection_ex(diff_ex(hole_outer, hole_inner), holes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return union_ex(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- line lattice
|
|
||||||
|
|
||||||
std::vector<coord_t> belt_brim_line_positions(coord_t u_lo,
|
|
||||||
coord_t u_hi,
|
|
||||||
coord_t pitch_u,
|
|
||||||
coord_t u_anchor)
|
|
||||||
{
|
|
||||||
std::vector<coord_t> out;
|
|
||||||
if (pitch_u <= 0 || u_hi <= u_lo)
|
|
||||||
return out;
|
|
||||||
|
|
||||||
// Walk the lattice from just below u_lo. Integer arithmetic throughout, so
|
|
||||||
// the half-open interval needs no epsilon: a point landing exactly on u_hi
|
|
||||||
// belongs to the next band.
|
|
||||||
int64_t k = int64_t(std::floor(double(u_lo - u_anchor) / double(pitch_u))) - 1;
|
|
||||||
while (u_anchor + coord_t(k) * pitch_u < u_lo)
|
|
||||||
++ k;
|
|
||||||
for (;; ++ k) {
|
|
||||||
const coord_t u = u_anchor + coord_t(k) * pitch_u;
|
|
||||||
if (u >= u_hi)
|
|
||||||
break;
|
|
||||||
out.emplace_back(u);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- pipeline
|
|
||||||
|
|
||||||
// A band of the belt surface as an explicit box, clamped to `bounds` along the
|
|
||||||
// shear axis. Deliberately not BeltFloorContext::surface_polygon(): those
|
|
||||||
// half-planes span +-1000 mm, which is wasteful to clip against and dangerous to
|
|
||||||
// feed through the flattening scale.
|
|
||||||
static Polygon band_box(const BoundingBox &bounds, int from_axis, coordf_t u_lo, coordf_t u_hi)
|
|
||||||
{
|
|
||||||
coord_t lo = scale_(u_lo);
|
|
||||||
coord_t hi = scale_(u_hi);
|
|
||||||
const coord_t bmin = from_axis == 0 ? bounds.min.x() : bounds.min.y();
|
|
||||||
const coord_t bmax = from_axis == 0 ? bounds.max.x() : bounds.max.y();
|
|
||||||
lo = std::max(lo, bmin);
|
|
||||||
hi = std::min(hi, bmax);
|
|
||||||
Polygon poly;
|
|
||||||
if (hi <= lo)
|
|
||||||
return poly;
|
|
||||||
if (from_axis == 0)
|
|
||||||
poly.points = { Point(lo, bounds.min.y()), Point(hi, bounds.min.y()),
|
|
||||||
Point(hi, bounds.max.y()), Point(lo, bounds.max.y()) };
|
|
||||||
else
|
|
||||||
poly.points = { Point(bounds.min.x(), lo), Point(bounds.max.x(), lo),
|
|
||||||
Point(bounds.max.x(), hi), Point(bounds.min.x(), hi) };
|
|
||||||
return poly;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExPolygons belt_brim_clip_leading_edge(const ExPolygons ®ion, const BeltBrimFrame &frame, coordf_t u_cut)
|
|
||||||
{
|
|
||||||
if (region.empty())
|
|
||||||
return region;
|
|
||||||
BoundingBox keep_bb = get_extents(region);
|
|
||||||
keep_bb.offset(scale_(1.));
|
|
||||||
const bool low_side = frame.downhill_sign() < 0; // downhill is -u
|
|
||||||
const Polygon keep = band_box(keep_bb, frame.from_axis,
|
|
||||||
low_side ? unscale<double>(frame.from_axis == 0 ? keep_bb.min.x() : keep_bb.min.y()) : u_cut,
|
|
||||||
low_side ? u_cut : unscale<double>(frame.from_axis == 0 ? keep_bb.max.x() : keep_bb.max.y()));
|
|
||||||
return keep.empty() ? ExPolygons{} : intersection_ex(region, Polygons{ keep });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything the per-band line generator needs, gathered once per object.
|
|
||||||
struct BeltBrimContext
|
|
||||||
{
|
|
||||||
BeltFloorContext ctx;
|
|
||||||
BeltBrimFrame frame;
|
|
||||||
ExPolygons region; // brim region, object-local slicing XY
|
|
||||||
BoundingBox region_bbox;
|
|
||||||
Flow brim_flow;
|
|
||||||
coord_t pitch_u = 0;
|
|
||||||
coord_t u_anchor = 0;
|
|
||||||
double in_plane_pitch = 0.; // mm
|
|
||||||
};
|
|
||||||
|
|
||||||
// Emit the cross-belt brim lines that belong to the band [print_z - height, print_z].
|
|
||||||
static void belt_brim_band_paths(const BeltBrimContext &bc,
|
|
||||||
coordf_t print_z,
|
|
||||||
coordf_t height,
|
|
||||||
const Polygons &obstacles,
|
|
||||||
ExtrusionEntityCollection &out,
|
|
||||||
ExPolygons &areas_out)
|
|
||||||
{
|
|
||||||
coordf_t u_lo = bc.ctx.cutoff_u(print_z - height);
|
|
||||||
coordf_t u_hi = bc.ctx.cutoff_u(print_z);
|
|
||||||
if (u_lo > u_hi)
|
|
||||||
std::swap(u_lo, u_hi);
|
|
||||||
|
|
||||||
// How wide this band is measured ON the belt, versus one nominal bead.
|
|
||||||
const double band_in_plane = (u_hi - u_lo) * bc.frame.u_stretch();
|
|
||||||
|
|
||||||
// Fraction of the layer height at which a line sits above the belt. Toward the
|
|
||||||
// downhill edge, so the sheet is reasonably thick while the nozzle stays clear of
|
|
||||||
// the belt itself.
|
|
||||||
static constexpr double BAND_CLEARANCE_FRACTION = 0.75;
|
|
||||||
|
|
||||||
std::vector<coord_t> us;
|
|
||||||
double uniform_clearance = 0.; // 0 => derive per line from its own position
|
|
||||||
double line_pitch = bc.in_plane_pitch;
|
|
||||||
// One line also serves a band up to half a bead wider than the nominal pitch (a 0.3 mm
|
|
||||||
// first layer at 45 degrees): its flow is matched to the band, so the bead is that much
|
|
||||||
// wider. Two lattice lines in such a band would land almost on top of each other.
|
|
||||||
if (band_in_plane <= 1.5 * bc.in_plane_pitch + EPSILON) {
|
|
||||||
// Steep belt, which is the normal case: the band is narrower than one bead, so
|
|
||||||
// exactly one line fits. Place it at a FIXED fraction of the band rather than
|
|
||||||
// on a nominal-spacing lattice. On a lattice each line lands at an arbitrary
|
|
||||||
// point in its band, the clearance sweeps [0, height] from band to band, and the
|
|
||||||
// bead width therefore varies by 2x - visible as ragged, uneven brim lines.
|
|
||||||
// Anchoring to the band makes the clearance identical everywhere, so every bead
|
|
||||||
// is the same width.
|
|
||||||
//
|
|
||||||
// The spacing is then whatever the bands give (height / sin(tilt) on the belt)
|
|
||||||
// rather than the nominal bead spacing, so the flow below is matched to THAT
|
|
||||||
// pitch. Matched flow at the real pitch is what keeps the sheet uniform and
|
|
||||||
// gap-free; using nominal flow at band spacing would over-feed it.
|
|
||||||
us.push_back(scale_(bc.ctx.cutoff_u(print_z - BAND_CLEARANCE_FRACTION * height)));
|
|
||||||
uniform_clearance = BAND_CLEARANCE_FRACTION * height;
|
|
||||||
line_pitch = band_in_plane;
|
|
||||||
} else {
|
|
||||||
// Shallow belt: the band is wider than a bead, so it takes several lines and they
|
|
||||||
// have to sit on the nominal lattice. Their clearances then differ, and so do
|
|
||||||
// their widths - unavoidable here, but shallow belts are the rare case.
|
|
||||||
us = belt_brim_line_positions(scale_(u_lo), scale_(u_hi), bc.pitch_u, bc.u_anchor);
|
|
||||||
}
|
|
||||||
if (us.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Polygons region_polys = to_polygons(bc.region);
|
|
||||||
|
|
||||||
// One lattice line at a time: the clearance - and therefore the extrusion
|
|
||||||
// volume - is a property of the line's u, so the pieces of different lines
|
|
||||||
// must not be pooled before the flow is resolved.
|
|
||||||
// Overshoot the region so the clip, not the line's ends, decides the extent.
|
|
||||||
const coord_t margin = coord_t(SCALED_EPSILON) + 1;
|
|
||||||
coord_t u_prev = std::numeric_limits<coord_t>::min();
|
|
||||||
for (coord_t u : us) {
|
|
||||||
// Nozzle-to-belt clearance for this line. Constant along the line, because the
|
|
||||||
// belt height depends only on the shear-axis coordinate. Band-anchored lines
|
|
||||||
// share one clearance by construction; lattice lines (shallow belts, or a first
|
|
||||||
// layer thick enough that the band is wider than a bead) each get their own.
|
|
||||||
//
|
|
||||||
// A lattice line can fall where the belt is only a hair below the band's print_z.
|
|
||||||
// The bead there would be laid scraping the belt while its flow is sized for a
|
|
||||||
// taller cell, so it is moved uphill to the same fraction of the band the
|
|
||||||
// single-line case uses. (The clearance is along slice Z; the real gap under the
|
|
||||||
// nozzle is clearance x cos(tilt), 0.53 h at 45 degrees for the 0.75 fraction.)
|
|
||||||
double clearance = uniform_clearance;
|
|
||||||
if (clearance <= 0.) {
|
|
||||||
const Point probe = bc.frame.from_axis == 0 ? Point(u, 0) : Point(0, u);
|
|
||||||
clearance = print_z - bc.ctx.floor_print_z(probe);
|
|
||||||
if (clearance < BAND_CLEARANCE_FRACTION * height) {
|
|
||||||
clearance = BAND_CLEARANCE_FRACTION * height;
|
|
||||||
u = scale_(bc.ctx.cutoff_u(print_z - clearance));
|
|
||||||
}
|
|
||||||
clearance = std::min(clearance, height);
|
|
||||||
}
|
|
||||||
// A line moved uphill can land on, or almost on, its neighbour; two beads closer
|
|
||||||
// than half a pitch would be laid into the same cell.
|
|
||||||
if (u_prev != std::numeric_limits<coord_t>::min() && std::abs(u - u_prev) < bc.pitch_u / 2)
|
|
||||||
continue;
|
|
||||||
u_prev = u;
|
|
||||||
|
|
||||||
Polyline line;
|
|
||||||
if (bc.frame.from_axis == 0)
|
|
||||||
line.points = { Point(u, coord_t(bc.region_bbox.min.y() - margin)),
|
|
||||||
Point(u, coord_t(bc.region_bbox.max.y() + margin)) };
|
|
||||||
else
|
|
||||||
line.points = { Point(coord_t(bc.region_bbox.min.x() - margin), u),
|
|
||||||
Point(coord_t(bc.region_bbox.max.x() + margin), u) };
|
|
||||||
|
|
||||||
Polylines pieces = intersection_pl(Polylines{ line }, region_polys);
|
|
||||||
if (! obstacles.empty())
|
|
||||||
pieces = diff_pl(pieces, obstacles);
|
|
||||||
if (pieces.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// with_cross_section, not with_height: it reaches the prescribed volume while
|
|
||||||
// KEEPING the extrusion spacing, so the bead is sized to fill exactly one
|
|
||||||
// pitch x clearance cell of the sheet.
|
|
||||||
const Flow f = bc.brim_flow.with_cross_section(float(line_pitch * clearance));
|
|
||||||
|
|
||||||
// Footprint of these beads, for the first-layer convex hull and bbox.
|
|
||||||
for (const Polygon &p : offset(pieces, 0.5f * float(f.scaled_width())))
|
|
||||||
areas_out.emplace_back(ExPolygon(p));
|
|
||||||
|
|
||||||
extrusion_entities_append_paths(out.entities, chain_polylines(std::move(pieces)),
|
|
||||||
erBrim, f.mm3_per_mm(), f.width(), float(clearance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Union of everything extruded at `print_z` that the brim must keep clear of, expressed
|
|
||||||
// in `self`'s local slicing frame. Includes `self` itself: its slice at this Z can
|
|
||||||
// overhang outside the belt footprint and land in the brim ring, which the flattened
|
|
||||||
// brim_object_gap - a belt-plane separation - does not cover.
|
|
||||||
//
|
|
||||||
// SEQUENCING: this reads every object's layers and this object's own support layers.
|
|
||||||
// Another object's support step shifts that object's layer Z into the object frame for
|
|
||||||
// the duration of the run (PrintObject::_generate_support_material()), so the brims must
|
|
||||||
// not overlap with the parallel support step: Print::process() generates them one object
|
|
||||||
// after the other once that step is over (PrintObject::generate_belt_brim()), and an
|
|
||||||
// object that arrives on or leaves the plate invalidates the other brim owners' support
|
|
||||||
// step (PrintApply.cpp) so their brims are clipped against what is there now. Only this
|
|
||||||
// object's supports are dodged; another object's support at the same Z is not.
|
|
||||||
// `region_bbox` bounds the brim; anything outside it cannot clip a brim line, so whole
|
|
||||||
// objects are skipped without materialising their polygons. On a typical plate the
|
|
||||||
// objects do not overlap and every foreign object drops out here, which matters because
|
|
||||||
// this runs once per band - hundreds of times per object.
|
|
||||||
static Polygons belt_brim_obstacles(const Print &print, const PrintObject &self,
|
|
||||||
const BoundingBox ®ion_bbox, coordf_t print_z, coordf_t tol)
|
|
||||||
{
|
|
||||||
const Point shift_self = self.instances().empty() ? Point(0, 0)
|
|
||||||
: self.instances().front().shift_without_plate_offset();
|
|
||||||
Polygons out;
|
|
||||||
for (const PrintObject *o : print.objects()) {
|
|
||||||
const bool is_self = (o == &self);
|
|
||||||
for (const PrintInstance &inst : o->instances()) {
|
|
||||||
const Point delta = inst.shift_without_plate_offset() - shift_self;
|
|
||||||
if (const Layer *l = o->get_layer_at_printz(print_z, tol)) {
|
|
||||||
BoundingBox lb = get_extents(l->lslices);
|
|
||||||
lb.translate(delta.x(), delta.y());
|
|
||||||
if (lb.overlap(region_bbox)) {
|
|
||||||
Polygons ps = to_polygons(l->lslices);
|
|
||||||
for (Polygon &p : ps)
|
|
||||||
p.translate(delta);
|
|
||||||
polygons_append(out, std::move(ps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (! is_self)
|
|
||||||
continue;
|
|
||||||
if (const SupportLayer *sl = o->get_support_layer_at_printz(print_z, tol)) {
|
|
||||||
Polygons ps = sl->support_fills.polygons_covered_by_spacing();
|
|
||||||
for (Polygon &p : ps)
|
|
||||||
p.translate(delta);
|
|
||||||
polygons_append(out, std::move(ps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (out.size() < 2)
|
|
||||||
return out; // union_() of 0 or 1 polygons is pure overhead
|
|
||||||
return union_(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void make_belt_brim(PrintObject &object)
|
|
||||||
{
|
|
||||||
object.clear_belt_brim();
|
|
||||||
if (! object.has_belt_brim())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Print &print = *object.print();
|
|
||||||
BeltBrimContext bc;
|
|
||||||
if (! bc.ctx.init(object.slicing_parameters(), print.config()))
|
|
||||||
return;
|
|
||||||
bc.frame = BeltBrimFrame{ bc.ctx.shear_factor(), bc.ctx.from_axis() };
|
|
||||||
|
|
||||||
const size_t nlayers = object.layers().size();
|
|
||||||
if (nlayers == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 1. Belt footprint: the union of each layer's slice clipped to that layer's
|
|
||||||
// own contact band. This is the object's bottom face, which on a belt is
|
|
||||||
// spread over every layer instead of sitting in layer 0.
|
|
||||||
ExPolygons footprint_acc;
|
|
||||||
// The first layer that touches the belt: where the leading-edge brim is cut.
|
|
||||||
const Layer *first_contact = nullptr;
|
|
||||||
for (size_t i = 0; i < nlayers; ++ i) {
|
|
||||||
const Layer &layer = *object.layers()[i];
|
|
||||||
if (layer.lslices.empty())
|
|
||||||
continue;
|
|
||||||
// print_z - height, not the previous layer's print_z: variable layer
|
|
||||||
// heights make the latter wrong.
|
|
||||||
coordf_t u_lo = bc.ctx.cutoff_u(layer.print_z - layer.height);
|
|
||||||
coordf_t u_hi = bc.ctx.cutoff_u(layer.print_z);
|
|
||||||
if (u_lo > u_hi)
|
|
||||||
std::swap(u_lo, u_hi);
|
|
||||||
BoundingBox bb = get_extents(layer.lslices);
|
|
||||||
bb.offset(scale_(1.));
|
|
||||||
const Polygon band = band_box(bb, bc.frame.from_axis, u_lo, u_hi);
|
|
||||||
if (band.empty())
|
|
||||||
continue;
|
|
||||||
ExPolygons contact = intersection_ex(layer.lslices, Polygons{ band });
|
|
||||||
if (contact.empty())
|
|
||||||
continue;
|
|
||||||
if (first_contact == nullptr)
|
|
||||||
first_contact = &layer;
|
|
||||||
expolygons_append(footprint_acc, std::move(contact));
|
|
||||||
}
|
|
||||||
const ExPolygons footprint = union_ex(footprint_acc);
|
|
||||||
if (footprint.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 2. Brim region, offset in the flattened (true on-belt) metric.
|
|
||||||
const PrintObjectConfig &cfg = object.config();
|
|
||||||
bc.brim_flow = print.brim_flow();
|
|
||||||
const double flow_w = bc.brim_flow.scaled_spacing() * SCALING_FACTOR;
|
|
||||||
// Quantize to an even number of lines, as the plate brim does.
|
|
||||||
const coord_t width = scale_(std::floor(cfg.brim_width.value / flow_w / 2) * flow_w * 2);
|
|
||||||
const coord_t leading = scale_(cfg.leading_brim_length.value);
|
|
||||||
const coord_t lateral = scale_(cfg.extra_brim_width.value);
|
|
||||||
const coord_t gap = scale_(cfg.brim_object_gap.value);
|
|
||||||
|
|
||||||
// Belt printers collapse Auto / Mouse ear / Painted to outer-only: the auto width
|
|
||||||
// heuristic and flat ear discs have no meaning on a tilted plane. Leading-edge-only
|
|
||||||
// is an outer brim too; it is narrowed down to the first contact below.
|
|
||||||
const BrimType bt = cfg.brim_type.value;
|
|
||||||
const bool has_outer = bt == btOuterOnly || bt == btOuterAndInner
|
|
||||||
|| bt == btAutoBrim || bt == btEar || bt == btPainted
|
|
||||||
|| bt == btLeadingEdgeOnly;
|
|
||||||
const bool has_inner = bt == btInnerOnly || bt == btOuterAndInner;
|
|
||||||
|
|
||||||
bc.region = belt_unflatten(
|
|
||||||
belt_brim_region(belt_flatten(footprint, bc.frame), has_outer, has_inner,
|
|
||||||
width, gap, leading, lateral, bc.frame),
|
|
||||||
bc.frame);
|
|
||||||
|
|
||||||
if (bt == btLeadingEdgeOnly && first_contact != nullptr && ! bc.region.empty())
|
|
||||||
// The cut is the uphill edge of the first contact's band: everything past it
|
|
||||||
// belongs to later contacts. The first contact is the first layer that touches
|
|
||||||
// the belt (step 1), neither layers().front(), an empty lead-in layer, nor the
|
|
||||||
// first layer with geometry, which is an overhang's tip when the part overhangs
|
|
||||||
// its leading end: both lie ahead of the part.
|
|
||||||
bc.region = belt_brim_clip_leading_edge(bc.region, bc.frame, bc.ctx.cutoff_u(first_contact->print_z));
|
|
||||||
|
|
||||||
if (bc.region.empty())
|
|
||||||
return;
|
|
||||||
bc.region_bbox = get_extents(bc.region);
|
|
||||||
|
|
||||||
// 3. Line lattice. Fixed pitch in the flattened metric, anchored at the
|
|
||||||
// footprint's leading-most edge so lines stay collinear across
|
|
||||||
// disconnected islands and across the apron prologue.
|
|
||||||
bc.pitch_u = std::max<coord_t>(1, coord_t(bc.brim_flow.scaled_spacing() * bc.frame.cos_tilt()));
|
|
||||||
bc.in_plane_pitch = unscale<double>(bc.pitch_u) * bc.frame.u_stretch();
|
|
||||||
{
|
|
||||||
const BoundingBox fbb = get_extents(footprint);
|
|
||||||
const bool low_side = bc.frame.shear > 0.;
|
|
||||||
bc.u_anchor = bc.frame.from_axis == 0 ? (low_side ? fbb.min.x() : fbb.max.x())
|
|
||||||
: (low_side ? fbb.min.y() : fbb.max.y());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Bands coincident with an object layer.
|
|
||||||
std::vector<ExtrusionEntityCollection> by_layer(nlayers);
|
|
||||||
std::vector<ExPolygons> areas_by_layer(nlayers);
|
|
||||||
for (size_t i = 0; i < nlayers; ++ i) {
|
|
||||||
const Layer &layer = *object.layers()[i];
|
|
||||||
const Polygons obstacles = belt_brim_obstacles(print, object, bc.region_bbox, layer.print_z, 0.5 * layer.height);
|
|
||||||
belt_brim_band_paths(bc, layer.print_z, layer.height, obstacles, by_layer[i], areas_by_layer[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Apron prologue: the part of the region downhill of the object's first
|
|
||||||
// layer, which has no object layer to ride on.
|
|
||||||
std::vector<BeltBrimBand> prologue;
|
|
||||||
{
|
|
||||||
const Layer &first = *object.layers().front();
|
|
||||||
const coordf_t h = first.height;
|
|
||||||
const bool low_side = bc.frame.shear > 0.;
|
|
||||||
const coord_t u_lead_s = bc.frame.from_axis == 0
|
|
||||||
? (low_side ? bc.region_bbox.min.x() : bc.region_bbox.max.x())
|
|
||||||
: (low_side ? bc.region_bbox.min.y() : bc.region_bbox.max.y());
|
|
||||||
const coordf_t u_lead = unscale<double>(u_lead_s);
|
|
||||||
// print_z at which the belt surface crosses the region's leading edge.
|
|
||||||
const coordf_t z_lead = bc.ctx.shear_factor() * u_lead
|
|
||||||
+ bc.ctx.floor_offset() + bc.ctx.z_shift();
|
|
||||||
if (h > EPSILON)
|
|
||||||
for (coordf_t z = first.print_z - h; z > z_lead - h; z -= h) {
|
|
||||||
const Polygons obstacles = belt_brim_obstacles(print, object, bc.region_bbox, z, 0.5 * h);
|
|
||||||
BeltBrimBand band;
|
|
||||||
band.print_z = z;
|
|
||||||
band.height = h;
|
|
||||||
belt_brim_band_paths(bc, z, h, obstacles, band.fills, band.areas);
|
|
||||||
if (! band.fills.empty())
|
|
||||||
prologue.emplace_back(std::move(band));
|
|
||||||
}
|
|
||||||
// Lowest Z first, so collect_layers_to_print sees them in print order.
|
|
||||||
std::reverse(prologue.begin(), prologue.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
object.set_belt_brim(std::move(by_layer), std::move(areas_by_layer), std::move(prologue));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
#ifndef slic3r_BeltBrim_hpp_
|
|
||||||
#define slic3r_BeltBrim_hpp_
|
|
||||||
|
|
||||||
#include "ExPolygon.hpp"
|
|
||||||
#include "ExtrusionEntityCollection.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "Polyline.hpp"
|
|
||||||
#include "libslic3r.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// Belt-printer brim geometry.
|
|
||||||
//
|
|
||||||
// A belt printer slices in a ROTATED frame, so the belt surface is not the
|
|
||||||
// Z=0 bed plane but a tilted plane in slicing space:
|
|
||||||
//
|
|
||||||
// z_slicing(u) = shear * u + floor_offset + z_shift, u = X or Y
|
|
||||||
//
|
|
||||||
// where `shear == tan(tilt)` (SlicingParameters::belt_floor_shear_factor) and
|
|
||||||
// the axis is selected by SlicingParameters::belt_floor_from_axis. See
|
|
||||||
// Support/BeltFloorContext.hpp for the canonical accessors.
|
|
||||||
//
|
|
||||||
// Consequences that drive everything in this file:
|
|
||||||
//
|
|
||||||
// * A horizontal slicing layer touches the belt only along a narrow strip at
|
|
||||||
// its leading edge, `layer_height / shear` wide (~0.2 mm at 45 degrees).
|
|
||||||
// The object's belt footprint - its bottom face - is therefore spread over
|
|
||||||
// every layer, not contained in layer 0.
|
|
||||||
// * Distances measured in slicing XY are NOT on-belt distances: moving `du`
|
|
||||||
// along the shear axis travels `du / cos(tilt)` across the belt. So brim
|
|
||||||
// offsets have to be taken in a "flattened" space where the shear axis is
|
|
||||||
// stretched by `1 / cos(tilt)`, then mapped back.
|
|
||||||
// * Brim ahead of the part (downhill) lies at slicing Z BELOW the object's
|
|
||||||
// first layer, because the object's layer 0 is precisely its leading
|
|
||||||
// contact with the belt.
|
|
||||||
//
|
|
||||||
// Everything here is pure geometry on ExPolygons/Polylines so it can be unit
|
|
||||||
// tested without a Print. Keep user-visible strings out of this file: it is
|
|
||||||
// not listed in localization/i18n/list.txt.
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// Tilt window within which the BELT plane, not the bed plane, is the adhesion
|
|
||||||
// surface. Below ~1 degree a belt is a flat bed as far as adhesion goes, and the
|
|
||||||
// contact band would be layer_height/sin(tilt) - tens of millimetres - so the
|
|
||||||
// ordinary plate brim is both correct and cheaper. Above ~85 degrees the whole
|
|
||||||
// brim compresses into a sliver and is not worth generating.
|
|
||||||
inline constexpr double BELT_BRIM_MIN_TILT_DEG = 1.;
|
|
||||||
inline constexpr double BELT_BRIM_MAX_TILT_DEG = 85.;
|
|
||||||
|
|
||||||
// Description of the tilted belt plane, reduced to what the brim geometry needs.
|
|
||||||
struct BeltBrimFrame
|
|
||||||
{
|
|
||||||
// tan(tilt). Sign selects which way is downhill.
|
|
||||||
double shear = 0.;
|
|
||||||
// 0 = X, 1 = Y. Matches BeltFloorContext::from_axis().
|
|
||||||
int from_axis = 1;
|
|
||||||
|
|
||||||
// 1 / cos(tilt). Stretch factor that turns a projected distance along
|
|
||||||
// `from_axis` into the true distance travelled across the belt.
|
|
||||||
double u_stretch() const { return std::sqrt(1. + shear * shear); }
|
|
||||||
// cos(tilt). The inverse mapping.
|
|
||||||
double cos_tilt() const { return 1. / this->u_stretch(); }
|
|
||||||
// Downhill is where the belt surface is lower, i.e. printed earlier, i.e.
|
|
||||||
// the leading edge of the part. For shear > 0 that is -u.
|
|
||||||
int downhill_sign() const { return shear > 0. ? -1 : +1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Scale only the `from_axis` component by `factor`, rounding to nearest.
|
|
||||||
//
|
|
||||||
// Deliberately not MultiPoint::scale(fx, fy) / ExPolygon::scale(fx, fy): those
|
|
||||||
// truncate toward zero, which is asymmetric about the origin and loses up to a
|
|
||||||
// full coordinate unit per vertex on every round trip.
|
|
||||||
ExPolygons belt_scale_u(const ExPolygons &src, const BeltBrimFrame &frame, double factor);
|
|
||||||
Polylines belt_scale_u(const Polylines &src, const BeltBrimFrame &frame, double factor);
|
|
||||||
|
|
||||||
// Into / out of the space where Euclidean offsets equal true on-belt distances.
|
|
||||||
inline ExPolygons belt_flatten(const ExPolygons &src, const BeltBrimFrame &frame)
|
|
||||||
{ return belt_scale_u(src, frame, frame.u_stretch()); }
|
|
||||||
inline ExPolygons belt_unflatten(const ExPolygons &src, const BeltBrimFrame &frame)
|
|
||||||
{ return belt_scale_u(src, frame, frame.cos_tilt()); }
|
|
||||||
|
|
||||||
// Minkowski sum of `src` with the segment [0, t]: the region swept by sliding
|
|
||||||
// `src` along t. Used to grow the brim downhill for "extra brim width".
|
|
||||||
//
|
|
||||||
// Implemented as union_(P, P + t, {parallelogram per boundary edge}) over ALL
|
|
||||||
// contours including holes, with every parallelogram forced counter-clockwise
|
|
||||||
// so the non-zero fill rule closes holes narrower than t along the sweep
|
|
||||||
// direction. A hole survives exactly when it is wider than |t| measured along
|
|
||||||
// t - not when it is wider in its narrowest Euclidean direction.
|
|
||||||
ExPolygons sweep_ex(const ExPolygons &src, const Point &t);
|
|
||||||
|
|
||||||
// "Leading edge only": keep the part of a brim region (unflattened, slicing XY)
|
|
||||||
// at or downhill of the object's first contact with the belt, so the part is
|
|
||||||
// supported as it lands and nothing is printed alongside it afterwards. `u_cut`
|
|
||||||
// is the uphill edge of the first layer's contact band along `frame.from_axis`,
|
|
||||||
// in mm (BeltFloorContext::cutoff_u of the first layer); downhill is the side
|
|
||||||
// `frame.downhill_sign()` points to.
|
|
||||||
ExPolygons belt_brim_clip_leading_edge(const ExPolygons ®ion, const BeltBrimFrame &frame, coordf_t u_cut);
|
|
||||||
|
|
||||||
// Brim region for one already-flattened belt footprint. All lengths are scaled
|
|
||||||
// and measured in the flattened (true on-belt) metric.
|
|
||||||
//
|
|
||||||
// `has_outer` / `has_inner` are the resolved BrimType: belt printers collapse
|
|
||||||
// Auto / Mouse ear / Painted to outer-only, so the caller does that mapping and
|
|
||||||
// this function never needs PrintConfig.
|
|
||||||
//
|
|
||||||
// Two directional extras are applied to the footprint before the outer offset, so
|
|
||||||
// each one buys reach in one direction only:
|
|
||||||
//
|
|
||||||
// `leading` (leading_brim_length) sweeps the footprint DOWNHILL along the belt,
|
|
||||||
// so every leading-facing edge gains an apron ahead of it.
|
|
||||||
// `lateral` (extra_brim_width) sweeps it BOTH WAYS across the belt, widening
|
|
||||||
// the brim sideways without pushing it further ahead or behind.
|
|
||||||
//
|
|
||||||
// Neither is applied to the inner (hole) ring.
|
|
||||||
ExPolygons belt_brim_region(const ExPolygons &footprint_flat,
|
|
||||||
bool has_outer,
|
|
||||||
bool has_inner,
|
|
||||||
coord_t brim_width,
|
|
||||||
coord_t object_gap,
|
|
||||||
coord_t leading,
|
|
||||||
coord_t lateral,
|
|
||||||
const BeltBrimFrame &frame);
|
|
||||||
|
|
||||||
// Brim line positions for one layer band.
|
|
||||||
//
|
|
||||||
// Lines sit on a fixed lattice `u_anchor + k * pitch_u` so the on-belt spacing
|
|
||||||
// between neighbouring brim lines is constant regardless of how the lattice
|
|
||||||
// falls across layer bands. Snapping to band centres instead would quantise
|
|
||||||
// the spacing to whole bands and under-deposit by ~35% at 45 degrees.
|
|
||||||
//
|
|
||||||
// The band is half-open, [u_lo, u_hi), so every lattice point belongs to
|
|
||||||
// exactly one band: none duplicated at a boundary, none dropped. A band
|
|
||||||
// narrower than the pitch simply yields nothing; a band much wider (shallow
|
|
||||||
// tilt) yields several lines.
|
|
||||||
std::vector<coord_t> belt_brim_line_positions(coord_t u_lo,
|
|
||||||
coord_t u_hi,
|
|
||||||
coord_t pitch_u,
|
|
||||||
coord_t u_anchor);
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- pipeline
|
|
||||||
|
|
||||||
// One brim-only layer printed BEFORE the object's first layer, carrying the
|
|
||||||
// apron that has to be stuck to the belt ahead of the part.
|
|
||||||
//
|
|
||||||
// Deliberately not a Layer subclass. A synthetic Layer would inherit id()
|
|
||||||
// semantics that leak into initial-layer temperature selection, the spiral vase
|
|
||||||
// probe, gradual interpolation, avoid-crossing-perimeters and cooling, all of
|
|
||||||
// which key off Layer::id() == 0 or off a layer's regions. A plain record
|
|
||||||
// carries only what the emitter needs.
|
|
||||||
//
|
|
||||||
// `height` is the LAYER height, used for the Z move and ordering metadata only.
|
|
||||||
// Each extrusion path inside `fills` carries its own height, equal to that
|
|
||||||
// line's nozzle-to-belt clearance, which varies across the band.
|
|
||||||
struct BeltBrimBand
|
|
||||||
{
|
|
||||||
coordf_t print_z = 0.;
|
|
||||||
coordf_t height = 0.;
|
|
||||||
// erBrim paths in the object's local slicing frame, untranslated.
|
|
||||||
ExtrusionEntityCollection fills;
|
|
||||||
// Footprint of those paths, for the first-layer convex hull / bbox.
|
|
||||||
ExPolygons areas;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PrintObject;
|
|
||||||
|
|
||||||
// Generate the belt brim for one object: fills its per-object-layer bands and
|
|
||||||
// its apron prologue. No-op unless PrintObject::has_belt_brim().
|
|
||||||
//
|
|
||||||
// Runs inside posSupportMaterial rather than the brim step, because the prologue
|
|
||||||
// print_z values must exist before ToolOrdering is built at psWipeTower.
|
|
||||||
void make_belt_brim(PrintObject &object);
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
|
|
||||||
#endif // slic3r_BeltBrim_hpp_
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#include "BeltGCode.hpp"
|
|
||||||
#include "GCodeWriter.hpp"
|
|
||||||
#include "GCode/BeltKinematics.hpp"
|
|
||||||
#include "BeltTransform.hpp"
|
|
||||||
#include "Print.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "libslic3r.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
void BeltGCode::init_belt_writer(Print &print)
|
|
||||||
{
|
|
||||||
// Axis remap and build volume max are set by base GCode after init_belt_writer
|
|
||||||
// returns; set_kinematics() replays them, so install order does not matter.
|
|
||||||
install_belt_kinematics(m_writer, print.config());
|
|
||||||
m_writer.set_force_normal_lift(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeltGCode::write_belt_header(GCodeOutputStream &file, const Print &print)
|
|
||||||
{
|
|
||||||
const auto &full_cfg = print.full_print_config();
|
|
||||||
// Slicing rotation: the belt tilt (axis + angle) and the single source of truth
|
|
||||||
// for the physical tilt the G-code viewer uses to enable belt view.
|
|
||||||
file.write_format("; belt_slice_rotation = %s\n", full_cfg.opt_serialize("belt_slice_rotation").c_str());
|
|
||||||
file.write_format("; belt_slice_rotation_angle = %.1f\n", print.config().belt_slice_rotation_angle.value);
|
|
||||||
// Machine-frame transform: shear (cot) + scale (1/|sin|) derived from the belt
|
|
||||||
// tilt angle (or belt_frame_tilt_angle when decoupled).
|
|
||||||
file.write_format("; belt_frame_tilt_decouple = %d\n", print.config().belt_frame_tilt_decouple.value ? 1 : 0);
|
|
||||||
file.write_format("; belt_frame_tilt_angle = %.1f\n", print.config().belt_frame_tilt_angle.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeltGCode::on_set_origin(const PrintObject * /*obj*/, const Point & /*inst_shift*/)
|
|
||||||
{
|
|
||||||
// Matches the per-instance Z-offset added in PrintObjectSlice.cpp: transform
|
|
||||||
// the origin through the belt pipeline so that back_transform(T * origin) =
|
|
||||||
// origin (correct machine position). The back_transform applied during
|
|
||||||
// G-code emission is the inverse of the forward transform.
|
|
||||||
|
|
||||||
// Adjust origin: transform through belt forward pipeline so that
|
|
||||||
// the back-transform correctly recovers model-space positions.
|
|
||||||
Transform3d T = BeltTransformPipeline::build_forward_transform(m_config);
|
|
||||||
Vec2d cur_origin = this->origin();
|
|
||||||
Vec3d origin3d(cur_origin.x(), cur_origin.y(), 0.);
|
|
||||||
Vec3d adjusted = T.linear() * origin3d;
|
|
||||||
this->set_origin(Vec2d(adjusted.x(), adjusted.y()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GCode.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "Print.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// Belt-printer-specific GCode export.
|
|
||||||
//
|
|
||||||
// Inherits from GCode and overrides virtual hooks to:
|
|
||||||
// - Install a BeltKinematics on the GCodeWriter
|
|
||||||
// - Write belt configuration to the G-code header
|
|
||||||
// - Adjust the origin for global pre-slice transforms when switching instances
|
|
||||||
// (Arc fitting is disabled for belt printers by BeltKinematics::supports_arc_moves(),
|
|
||||||
// which the base GCode::should_disable_arc_fitting() consults -- no override needed.)
|
|
||||||
class BeltGCode : public GCode
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void init_belt_writer(Print &print) override;
|
|
||||||
void write_belt_header(GCodeOutputStream &file, const Print &print) override;
|
|
||||||
void on_set_origin(const PrintObject *obj, const Point &inst_shift) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,433 +0,0 @@
|
|||||||
// ORCA-Belt: backend of the belt purge tower (the belt replacement for the
|
|
||||||
// classic wipe/prime tower).
|
|
||||||
//
|
|
||||||
// Kept in its own translation unit so the belt-purge logic stays out of the way
|
|
||||||
// of unrelated upstream changes to Print.cpp / PrintObjectSlice.cpp and carries
|
|
||||||
// no regression risk for normal printers: none of these methods do anything
|
|
||||||
// unless the print is a belt printer with the belt purge tower enabled.
|
|
||||||
//
|
|
||||||
// Print::has_belt_purge_tower() - is the belt purge tower active?
|
|
||||||
// Print::_align_belt_purge_layers() - snap the prism's layer grid onto the
|
|
||||||
// printed objects' grid
|
|
||||||
// Print::_plan_belt_purge() - route filament-change purging into the
|
|
||||||
// prism (flush-into-objects), no wipe tower
|
|
||||||
// PrintObject::belt_shift_layer_grid() - shift a sliced layer grid
|
|
||||||
// PrintObject::belt_truncate_layers_above() - cancel the prism past the last swap
|
|
||||||
//
|
|
||||||
// (Declarations live in Print.hpp alongside the rest of the Print interface.)
|
|
||||||
|
|
||||||
#include "Print.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "Exception.hpp"
|
|
||||||
#include "GCode/ToolOrdering.hpp"
|
|
||||||
#include "Layer.hpp"
|
|
||||||
#include "ExtrusionEntity.hpp"
|
|
||||||
#include "ExtrusionEntityCollection.hpp"
|
|
||||||
#include "I18N.hpp"
|
|
||||||
#include "format.hpp"
|
|
||||||
#include "LocalesUtils.hpp"
|
|
||||||
#include "libslic3r.h"
|
|
||||||
#include "BeltBrim.hpp"
|
|
||||||
#include "PrintBase.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <functional>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// Belt purge prism: purging after filament changes is routed into a sliced
|
|
||||||
// prism object via the flush-into-objects machinery instead of a wipe tower.
|
|
||||||
bool Print::has_belt_purge_tower() const
|
|
||||||
{
|
|
||||||
// Its own purge-tower "type", gated by the belt-only enable_belt_purge_tower
|
|
||||||
// option (not the classic enable_prime_tower).
|
|
||||||
if (!(m_config.belt_printer.value
|
|
||||||
&& m_config.enable_belt_purge_tower.value
|
|
||||||
&& !m_config.spiral_mode.value
|
|
||||||
&& m_config.filament_diameter.values.size() > 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return std::any_of(m_objects.begin(), m_objects.end(), [](const PrintObject *object) {
|
|
||||||
return object->config().belt_purge_tower_object.value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Belt mode: align ALL objects on the plate (the printed objects AND the purge
|
|
||||||
// prism) onto one common layer grid, so the prism can absorb every toolchange.
|
|
||||||
//
|
|
||||||
// After belt slicing each object's layer print_z carries a per-object global z
|
|
||||||
// offset (mesh-vertex-scan belt_z_shift + instance-Y-dependent terms), so
|
|
||||||
// objects at different belt-Y positions get layer grids with DIFFERENT residues
|
|
||||||
// (mod layer height). Purge marking looks absorbers up with
|
|
||||||
// get_layer_at_printz(lt.print_z, EPSILON), so a toolchange on object B only
|
|
||||||
// absorbs into the prism if the prism has a layer at B's print_z. Snapping only
|
|
||||||
// the prism to one object therefore worked for a single (assembled) multi-color
|
|
||||||
// object but failed with multiple separate objects — the prism could follow only
|
|
||||||
// one grid, and toolchanges on the others went unabsorbed ("multiple layer
|
|
||||||
// grids" warning).
|
|
||||||
//
|
|
||||||
// Fix: pick one reference grid (the tallest object) and shift every object onto
|
|
||||||
// it. Each shift is at most half a layer height — a sub-100µm move along the
|
|
||||||
// belt, the very same mechanism the per-object global_z_offset already uses, and
|
|
||||||
// it keeps each object internally consistent (belt_shift_layer_grid moves the
|
|
||||||
// object's layers, its support layers, and its belt floor together). Equal layer
|
|
||||||
// height across objects is enforced by Print::validate(), so once residues match
|
|
||||||
// every object steps on the same lattice {ref_offset + k*h} and every toolchange
|
|
||||||
// layer coincides with a prism layer.
|
|
||||||
void Print::_align_belt_purge_layers()
|
|
||||||
{
|
|
||||||
PrintObject *prism = nullptr;
|
|
||||||
for (PrintObject *po : m_objects)
|
|
||||||
if (po->config().belt_purge_tower_object.value && !po->layers().empty()) {
|
|
||||||
prism = po;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (prism == nullptr || prism->layers().empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const double h = prism->config().layer_height.value;
|
|
||||||
if (h <= EPSILON)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Grid residue of an object's layer grid: identical for all of an object's
|
|
||||||
// layers above the first since they step by h.
|
|
||||||
auto grid_offset = [h](const PrintObject *po) -> double {
|
|
||||||
if (po->layers().empty())
|
|
||||||
return 0.;
|
|
||||||
const double z = po->layers().front()->print_z;
|
|
||||||
return z - std::floor(z / h) * h; // in [0, h)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reference grid: the tallest non-prism object (proxy for the object with
|
|
||||||
// the most toolchange layers — minimizes how far the rest must move).
|
|
||||||
const PrintObject *ref = nullptr;
|
|
||||||
double ref_top = -std::numeric_limits<double>::max();
|
|
||||||
for (const PrintObject *po : m_objects) {
|
|
||||||
if (po->config().belt_purge_tower_object.value || po->layers().empty())
|
|
||||||
continue;
|
|
||||||
const double top = po->layers().back()->print_z;
|
|
||||||
if (top > ref_top) {
|
|
||||||
ref_top = top;
|
|
||||||
ref = po;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ref == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const double ref_offset = grid_offset(ref);
|
|
||||||
|
|
||||||
// Snap every object (printed objects AND the prism) onto the reference grid.
|
|
||||||
for (PrintObject *po : m_objects) {
|
|
||||||
if (po->layers().empty())
|
|
||||||
continue;
|
|
||||||
double delta = ref_offset - grid_offset(po);
|
|
||||||
if (delta > 0.5 * h)
|
|
||||||
delta -= h;
|
|
||||||
else if (delta <= -0.5 * h)
|
|
||||||
delta += h;
|
|
||||||
po->belt_shift_layer_grid(delta); // no-op for the reference object (delta ~ 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Belt mode replacement for _make_wipe_tower(): plan filament-change purging
|
|
||||||
// into the belt purge prism (and any other flush_into_* object) using the
|
|
||||||
// flush-into-objects machinery, without generating classic wipe tower G-code.
|
|
||||||
// The toolchange itself is emitted by GCode::set_extruder() via the
|
|
||||||
// change_filament_gcode macro; the overrides marked here make the new
|
|
||||||
// filament's first extrusions land in the purge prism.
|
|
||||||
void Print::_plan_belt_purge()
|
|
||||||
{
|
|
||||||
m_wipe_tower_data.clear();
|
|
||||||
|
|
||||||
// psWipeTower may be invalidated without posSlice (for example after a
|
|
||||||
// filament-map or tool-ordering change). Restore a prism shortened by the
|
|
||||||
// previous plan so a newly higher toolchange can use its original layers.
|
|
||||||
for (PrintObject *po : m_objects)
|
|
||||||
if (po->config().belt_purge_tower_object.value)
|
|
||||||
po->belt_undo_purge_plan();
|
|
||||||
|
|
||||||
// Must run before ToolOrdering is built: LayerTools merge per-object layer
|
|
||||||
// print_z values, and the prism only absorbs purge where its (snapped)
|
|
||||||
// layers coincide with the toolchange layers.
|
|
||||||
this->_align_belt_purge_layers();
|
|
||||||
|
|
||||||
const unsigned int number_of_extruders = (unsigned int) m_config.filament_colour.values.size();
|
|
||||||
|
|
||||||
// No initial priming extrusions: there is no tower to prime on.
|
|
||||||
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int) -1, false);
|
|
||||||
m_wipe_tower_data.tool_ordering.sort_and_build_data(*this, (unsigned int) -1, false);
|
|
||||||
|
|
||||||
if (m_wipe_tower_data.tool_ordering.empty() || m_wipe_tower_data.tool_ordering.last_extruder() == unsigned(-1))
|
|
||||||
throw Slic3r::SlicingError("The print is empty. The model is not printable with current print settings.");
|
|
||||||
|
|
||||||
// Is there any filament change at all? Not ToolOrdering::has_wipe_tower(): that reads the
|
|
||||||
// FIRST layer's flag, and on a belt the first layer may be a brim apron band, which carries
|
|
||||||
// neither object nor support and so never gets the flag even when the print changes filament.
|
|
||||||
{
|
|
||||||
bool any_change = false;
|
|
||||||
unsigned int cur = m_wipe_tower_data.tool_ordering.first_extruder();
|
|
||||||
for (const auto < : m_wipe_tower_data.tool_ordering.layer_tools())
|
|
||||||
for (const unsigned int e : lt.extruders)
|
|
||||||
if (e != cur) { any_change = true; cur = e; }
|
|
||||||
if (! any_change)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->throw_if_canceled();
|
|
||||||
|
|
||||||
// Flush volumes per filament pair, mirroring the generic wipe tower path:
|
|
||||||
// full flush matrix for single extruder multi material with purging enabled,
|
|
||||||
// plain prime volume otherwise.
|
|
||||||
std::vector<float> flush_matrix(cast<float>(
|
|
||||||
get_flush_volumes_matrix(m_config.flush_volumes_matrix.values, 0, m_config.nozzle_diameter.values.size())));
|
|
||||||
std::vector<std::vector<float>> wipe_volumes;
|
|
||||||
for (unsigned int i = 0; i < number_of_extruders; ++i)
|
|
||||||
wipe_volumes.push_back(std::vector<float>(flush_matrix.begin() + i * number_of_extruders,
|
|
||||||
flush_matrix.begin() + (i + 1) * number_of_extruders));
|
|
||||||
const bool use_flush_matrix = m_config.purge_in_prime_tower && m_config.single_extruder_multi_material;
|
|
||||||
const float flush_multiplier = (float) m_config.flush_multiplier.get_at(0);
|
|
||||||
|
|
||||||
// Cancel the purge prism early: pre-scan the tool ordering for the highest
|
|
||||||
// print_z that actually has a toolchange, then drop the prism's layers above
|
|
||||||
// it so the tower stops at the last color swap (saves filament/time). This
|
|
||||||
// MUST happen before the marking loop below: ensure_perimeters_infills_order
|
|
||||||
// force-overrides the prism's extrusions on every layer (it is a dedicated
|
|
||||||
// flush object), so truncating afterwards would leave dangling overrides
|
|
||||||
// pointing into deleted layers.
|
|
||||||
{
|
|
||||||
// The tool ordering covers the WHOLE print, and the prism is a printed
|
|
||||||
// object in it. Left unbounded, the scan below sees the prism's own
|
|
||||||
// toolchanges on layers above every model object -- the prism runs past
|
|
||||||
// them by design (ramp/height compensation at the tilted ends) -- so
|
|
||||||
// last_tc_z lands at the prism's own top and the truncation cancels
|
|
||||||
// nothing. The tower ends up justifying its own existence.
|
|
||||||
//
|
|
||||||
// Nothing above the tallest printed object can require a color change,
|
|
||||||
// so bound the scan there. On MCTEST5 that is 197 toolchanges spanning
|
|
||||||
// z=154.00..193.20 with the tallest object topping out at 153.80, i.e.
|
|
||||||
// 39.4 mm of tower that no swap ever needed.
|
|
||||||
// Support layers count too: on a belt they can extend above the object's
|
|
||||||
// own top, and a toolchange there is a real one.
|
|
||||||
double obj_top_z = -1.;
|
|
||||||
for (const PrintObject *po : m_objects) {
|
|
||||||
if (po->config().belt_purge_tower_object.value)
|
|
||||||
continue;
|
|
||||||
if (!po->layers().empty())
|
|
||||||
obj_top_z = std::max(obj_top_z, po->layers().back()->print_z);
|
|
||||||
if (!po->support_layers().empty())
|
|
||||||
obj_top_z = std::max(obj_top_z, po->support_layers().back()->print_z);
|
|
||||||
}
|
|
||||||
|
|
||||||
double last_tc_z = -1.;
|
|
||||||
unsigned int cur_ext = m_wipe_tower_data.tool_ordering.first_extruder();
|
|
||||||
for (const auto < : m_wipe_tower_data.tool_ordering.layer_tools()) {
|
|
||||||
// layer_tools() is ordered by print_z ascending.
|
|
||||||
if (obj_top_z >= 0. && lt.print_z > obj_top_z + EPSILON)
|
|
||||||
break;
|
|
||||||
for (const unsigned int e : lt.extruders)
|
|
||||||
if (e != cur_ext) { last_tc_z = lt.print_z; cur_ext = e; }
|
|
||||||
}
|
|
||||||
// Deliberately NOT cancelling the prism outright when no object toolchange
|
|
||||||
// exists: belt_truncate_layers_above(0.) empties m_layers, and an object
|
|
||||||
// with zero layers is not something the rest of the pipeline expects. The
|
|
||||||
// GUI already declines to create a prism unless more than one filament is
|
|
||||||
// in use, so this case is a stale prism, not a hot path -- leave it whole
|
|
||||||
// rather than risk a zero-layer object.
|
|
||||||
if (last_tc_z >= 0.)
|
|
||||||
for (PrintObject *po : m_objects)
|
|
||||||
if (po->config().belt_purge_tower_object.value && !po->layers().empty()) {
|
|
||||||
po->belt_truncate_layers_above(last_tc_z);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The prism only absorbs purge at toolchange layers whose print_z coincides
|
|
||||||
// with one of its own layers.
|
|
||||||
PrintObject *prism_po = nullptr;
|
|
||||||
for (PrintObject *po : m_objects)
|
|
||||||
if (po->config().belt_purge_tower_object.value && !po->layers().empty()) { prism_po = po; break; }
|
|
||||||
|
|
||||||
float total_leftover = 0.f;
|
|
||||||
float worst_layer_leftover = 0.f;
|
|
||||||
double worst_layer_z = 0.;
|
|
||||||
|
|
||||||
unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder();
|
|
||||||
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) {
|
|
||||||
float layer_leftover = 0.f;
|
|
||||||
for (const unsigned int extruder_id : layer_tools.extruders) {
|
|
||||||
if (extruder_id == current_extruder_id)
|
|
||||||
continue;
|
|
||||||
float volume_to_wipe = use_flush_matrix ?
|
|
||||||
wipe_volumes[current_extruder_id][extruder_id] * flush_multiplier :
|
|
||||||
(float) m_config.prime_volume;
|
|
||||||
float leftover = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id,
|
|
||||||
volume_to_wipe);
|
|
||||||
layer_leftover += leftover;
|
|
||||||
current_extruder_id = extruder_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plastic saving: drop the prism's fills that no toolchange on this layer
|
|
||||||
// claimed. At this point the prism's OVERRIDDEN fills are exactly the
|
|
||||||
// purge; the rest would print as solid infill in the prism's own filament
|
|
||||||
// for nothing -- which is the whole prism on a layer with no toolchange
|
|
||||||
// (141 of 692 layers on MCTEST5 before the truncation fix). Perimeters are
|
|
||||||
// left alone so the bar keeps a continuous wall along the belt.
|
|
||||||
//
|
|
||||||
// Non-destructive: the entities are stashed with their positions and put
|
|
||||||
// back by belt_restore_dropped_fills() at the top of the next plan. An
|
|
||||||
// earlier version deleted them outright, which broke replanning when a
|
|
||||||
// later tool ordering needed what this one had not claimed -- that is why
|
|
||||||
// it was removed rather than kept.
|
|
||||||
if (prism_po != nullptr) {
|
|
||||||
const auto &we = layer_tools.wiping_extrusions();
|
|
||||||
prism_po->belt_drop_unclaimed_fills(
|
|
||||||
prism_po->get_layer_at_printz(layer_tools.print_z, EPSILON),
|
|
||||||
[&we, prism_po](const ExtrusionEntity *e) { return we.is_entity_overridden(e, prism_po, 0); });
|
|
||||||
}
|
|
||||||
|
|
||||||
layer_tools.wiping_extrusions().ensure_perimeters_infills_order(*this);
|
|
||||||
if (layer_leftover > 0.f) {
|
|
||||||
total_leftover += layer_leftover;
|
|
||||||
if (layer_leftover > worst_layer_leftover) {
|
|
||||||
worst_layer_leftover = layer_leftover;
|
|
||||||
worst_layer_z = layer_tools.print_z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->throw_if_canceled();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_leftover > 1.f) {
|
|
||||||
this->active_step_add_warning(
|
|
||||||
PrintStateBase::WarningLevel::CRITICAL,
|
|
||||||
Slic3r::format(_u8L("The belt purge tower cannot absorb the full purge volume: %1% mm³ in total could not "
|
|
||||||
"be purged (worst layer: %2% mm³ at height %3%). The print may show color bleeding. "
|
|
||||||
"Increase the belt purge tower width, or reduce flushing volumes."),
|
|
||||||
int(std::ceil(total_leftover)), int(std::ceil(worst_layer_leftover)),
|
|
||||||
Slic3r::float_to_string_decimal_point(worst_layer_z, 2)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Belt mode: shift the sliced layer grid by delta. Mirrors the global_z_offset
|
|
||||||
// application in slice() — layer print_z and belt_floor_z_shift move together
|
|
||||||
// so belt floor clipping stays consistent with the shifted grid. Used by
|
|
||||||
// Print::_align_belt_purge_layers() to snap the purge prism onto the printed
|
|
||||||
// objects' layer grid; |delta| <= half a layer height, i.e. a sub-layer shift
|
|
||||||
// of the prism along the belt.
|
|
||||||
void PrintObject::belt_shift_layer_grid(double delta)
|
|
||||||
{
|
|
||||||
if (std::abs(delta) < EPSILON)
|
|
||||||
return;
|
|
||||||
for (Layer *layer : m_layers)
|
|
||||||
layer->print_z += delta;
|
|
||||||
for (SupportLayer *layer : m_support_layers)
|
|
||||||
layer->print_z += delta;
|
|
||||||
// The brim's apron bands below the first layer carry their own print_z.
|
|
||||||
for (BeltBrimBand &band : m_belt_brim_prologue)
|
|
||||||
band.print_z += delta;
|
|
||||||
m_slicing_params.belt_floor_z_shift += delta;
|
|
||||||
// The grid stays shifted across a support-only or brim-only change (posSlice does
|
|
||||||
// not rerun), so everything slice() derived from it has to follow: the cached floor
|
|
||||||
// that update_slicing_parameters() restores, and the global offset the organic
|
|
||||||
// support layers and the adaptive infill octree are placed with. Left alone, the
|
|
||||||
// next alignment finds a delta of 0 and the floor and the supports sit up to half
|
|
||||||
// a layer off the grid, unlike a fresh slice.
|
|
||||||
if (m_belt_floor_z_shift_cache_valid)
|
|
||||||
m_belt_floor_z_shift_cached += delta;
|
|
||||||
m_belt_global_z_offset += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Belt mode: drop layers strictly above z (used to cancel the purge prism early
|
|
||||||
// once there are no more toolchanges above z, so the tower stops at the last
|
|
||||||
// color swap instead of wasting filament up the rest of the belt). Each layer's
|
|
||||||
// cross-section is already sliced, so removing upper layers does not affect the
|
|
||||||
// last toolchange's coverage. Deletes the Layer objects and clears the new top
|
|
||||||
// layer's upper-layer link. Returns the number of layers removed.
|
|
||||||
size_t PrintObject::belt_truncate_layers_above(coordf_t z)
|
|
||||||
{
|
|
||||||
// A repeated plan always starts from the restored full layer set.
|
|
||||||
assert(m_belt_truncated_layers.empty());
|
|
||||||
size_t keep = m_layers.size();
|
|
||||||
while (keep > 0 && m_layers[keep - 1]->print_z > z + EPSILON)
|
|
||||||
--keep;
|
|
||||||
if (keep >= m_layers.size())
|
|
||||||
return 0;
|
|
||||||
const size_t removed = m_layers.size() - keep;
|
|
||||||
m_belt_truncated_layers.assign(m_layers.begin() + keep, m_layers.end());
|
|
||||||
m_layers.resize(keep);
|
|
||||||
if (!m_layers.empty())
|
|
||||||
m_layers.back()->upper_layer = nullptr;
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plastic saving on the purge prism: keep only the fills a toolchange claimed.
|
|
||||||
//
|
|
||||||
// Called per layer from _plan_belt_purge(), after the real-purge marking and
|
|
||||||
// BEFORE ensure_perimeters_infills_order() -- that pass force-overrides every
|
|
||||||
// remaining fill on the prism (it is a dedicated flush object), so afterwards
|
|
||||||
// everything looks claimed and nothing could be distinguished.
|
|
||||||
size_t PrintObject::belt_drop_unclaimed_fills(Layer *layer, const std::function<bool(const ExtrusionEntity*)> &claimed)
|
|
||||||
{
|
|
||||||
if (layer == nullptr)
|
|
||||||
return 0;
|
|
||||||
size_t dropped = 0;
|
|
||||||
for (size_t ri = 0; ri < layer->regions().size(); ++ri) {
|
|
||||||
LayerRegion *lr = layer->get_region(ri);
|
|
||||||
auto &ents = lr->fills.entities;
|
|
||||||
ExtrusionEntitiesPtr keep;
|
|
||||||
keep.reserve(ents.size());
|
|
||||||
for (size_t i = 0; i < ents.size(); ++i) {
|
|
||||||
if (claimed(ents[i])) {
|
|
||||||
keep.emplace_back(ents[i]);
|
|
||||||
} else {
|
|
||||||
// Stash with its original index so the restore is exact.
|
|
||||||
m_belt_dropped_fills.push_back(BeltDroppedFill{ layer, ri, i, ents[i] });
|
|
||||||
++dropped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ents = std::move(keep);
|
|
||||||
}
|
|
||||||
return dropped;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintObject::belt_restore_dropped_fills()
|
|
||||||
{
|
|
||||||
if (m_belt_dropped_fills.empty())
|
|
||||||
return;
|
|
||||||
// Ascending index per (layer, region): inserting in that order lands every
|
|
||||||
// entity back at its original position, because each insertion shifts only
|
|
||||||
// the entries after it, which are themselves still to be inserted.
|
|
||||||
std::stable_sort(m_belt_dropped_fills.begin(), m_belt_dropped_fills.end(),
|
|
||||||
[](const BeltDroppedFill &a, const BeltDroppedFill &b) {
|
|
||||||
if (a.layer != b.layer) return a.layer < b.layer;
|
|
||||||
if (a.region_idx != b.region_idx) return a.region_idx < b.region_idx;
|
|
||||||
return a.index < b.index;
|
|
||||||
});
|
|
||||||
for (const BeltDroppedFill &d : m_belt_dropped_fills) {
|
|
||||||
auto &ents = d.layer->get_region(d.region_idx)->fills.entities;
|
|
||||||
ents.insert(ents.begin() + std::min(d.index, ents.size()), d.entity);
|
|
||||||
}
|
|
||||||
m_belt_dropped_fills.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintObject::belt_restore_truncated_layers()
|
|
||||||
{
|
|
||||||
if (m_belt_truncated_layers.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_layers.insert(m_layers.end(), m_belt_truncated_layers.begin(), m_belt_truncated_layers.end());
|
|
||||||
m_belt_truncated_layers.clear();
|
|
||||||
for (size_t i = 0; i < m_layers.size(); ++i) {
|
|
||||||
m_layers[i]->lower_layer = i == 0 ? nullptr : m_layers[i - 1];
|
|
||||||
m_layers[i]->upper_layer = i + 1 < m_layers.size() ? m_layers[i + 1] : nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
#include "BeltSliceStrategy.hpp"
|
|
||||||
#include "Model.hpp"
|
|
||||||
#include "BeltTransform.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
void BeltSliceStrategy::apply_preslice_transforms(Transform3d &trafo,
|
|
||||||
const PrintConfig &config,
|
|
||||||
const ModelVolumePtrs &model_volumes,
|
|
||||||
double *out_belt_min_z)
|
|
||||||
{
|
|
||||||
// 1. Belt rotation — the sole mesh-side belt transform (matching
|
|
||||||
// BeltTransformPipeline::build_forward_transform). Only active in
|
|
||||||
// belt-printer mode.
|
|
||||||
bool has_rotation = false;
|
|
||||||
if (config.belt_printer.value) {
|
|
||||||
const Matrix3d rot = BeltTransformPipeline::build_rotation_matrix(config, &has_rotation);
|
|
||||||
if (has_rotation) {
|
|
||||||
Transform3d belt_xform = Transform3d::Identity();
|
|
||||||
belt_xform.linear() = rot;
|
|
||||||
trafo = belt_xform * trafo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_rotation)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 2. Z-shift — detect if the mesh clips below the build plate after the
|
|
||||||
// transforms and lift it. Each mesh vertex must be brought into object space
|
|
||||||
// via mv->get_matrix() before applying the full trafo (which is in object
|
|
||||||
// space). Missing this on assemblies (where per-volume get_matrix() positions
|
|
||||||
// each volume within the object) would compute min_z against mesh-local vertex
|
|
||||||
// coordinates rather than object-space coordinates, so volumes translated along
|
|
||||||
// the slicer's Z axis would be silently excluded from the bound check.
|
|
||||||
|
|
||||||
//
|
|
||||||
// The lift is measured to the lowest point of the SUPPORT region, not of the
|
|
||||||
// mesh: the belt floor (z = shear * u in this rotated frame, u the from-axis
|
|
||||||
// coordinate) runs below every vertex, and under the leading end of an
|
|
||||||
// overhang it lies below the lowest vertex by up to the overhang's length
|
|
||||||
// times the shear. Supports have to reach that floor, and every support
|
|
||||||
// generator works in layers at z >= 0, so z = 0 has to be the lowest floor
|
|
||||||
// point under the footprint. The layers between it and the first vertex
|
|
||||||
// come out empty, which belt slicing already tolerates (the bottom corner
|
|
||||||
// of a tilted part is a point). Vertices on the belt have z == floor, so
|
|
||||||
// for a part resting on the belt this is simply the floor at its leading
|
|
||||||
// extreme, less the frame margin (see BeltTransformPipeline::frame_margin).
|
|
||||||
BeltTransformPipeline::BeltFloorParams floor;
|
|
||||||
const bool has_floor = BeltTransformPipeline::floor_shear(config, floor);
|
|
||||||
double min_z = std::numeric_limits<double>::max();
|
|
||||||
for (const ModelVolume *mv : model_volumes) {
|
|
||||||
if (!mv->is_model_part()) continue;
|
|
||||||
Transform3d vol_trafo = trafo * mv->get_matrix();
|
|
||||||
const auto &its = mv->mesh().its;
|
|
||||||
for (const stl_vertex &v : its.vertices) {
|
|
||||||
Vec3d vm = v.cast<double>();
|
|
||||||
Vec3d pt = vol_trafo * vm;
|
|
||||||
min_z = std::min(min_z, pt.z());
|
|
||||||
if (has_floor)
|
|
||||||
min_z = std::min(min_z, floor.shear_factor * (floor.from_axis == 0 ? pt.x() : pt.y()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_floor && min_z != std::numeric_limits<double>::max())
|
|
||||||
min_z -= BeltTransformPipeline::frame_margin(floor);
|
|
||||||
const double z_shift_val = (min_z < 0. && min_z != std::numeric_limits<double>::max()) ? -min_z : 0.;
|
|
||||||
if (z_shift_val > 0.) {
|
|
||||||
Transform3d z_shift = Transform3d::Identity();
|
|
||||||
z_shift.matrix()(2, 3) = z_shift_val;
|
|
||||||
trafo = z_shift * trafo;
|
|
||||||
}
|
|
||||||
// out_belt_min_z is only meaningful in belt mode.
|
|
||||||
if (out_belt_min_z && config.belt_printer.value) {
|
|
||||||
*out_belt_min_z = (min_z != std::numeric_limits<double>::max()) ? min_z : 0.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "libslic3r.h"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "BeltTransform.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "Model.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// Belt printer pre-slice transform strategy.
|
|
||||||
//
|
|
||||||
// Composes, in order, the mesh transforms applied before slicing on a belt printer:
|
|
||||||
// 1. Belt rotation (the sole mesh-side belt transform; shear & scale are a
|
|
||||||
// g-code-side stage, see MachineFrameTransform)
|
|
||||||
// 2. Per-object Z-shift that lifts the mesh so its slicing frame starts at the
|
|
||||||
// belt below its footprint
|
|
||||||
//
|
|
||||||
// Isolates this belt-specific logic from the generic slicing pipeline in
|
|
||||||
// PrintObjectSlice.cpp.
|
|
||||||
class BeltSliceStrategy
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Apply the belt rotation + Z-shift to `trafo` in place. No-op when no belt
|
|
||||||
// rotation is configured.
|
|
||||||
//
|
|
||||||
// out_belt_min_z (if non-null) receives the minimum mesh Z after the transforms.
|
|
||||||
static void apply_preslice_transforms(Transform3d &trafo,
|
|
||||||
const PrintConfig &config,
|
|
||||||
const ModelVolumePtrs &model_volumes,
|
|
||||||
double *out_belt_min_z = nullptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
#include "BeltTransform.hpp"
|
|
||||||
#include "Model.hpp"
|
|
||||||
#include "BoundingBox.hpp"
|
|
||||||
#include "Config.hpp"
|
|
||||||
#include "Geometry.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "libslic3r.h"
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// ---- Matrix builders ------------------------------------------------------
|
|
||||||
|
|
||||||
Matrix3d BeltTransformPipeline::build_rotation_matrix(const PrintConfig &config, bool *has_rot_out)
|
|
||||||
{
|
|
||||||
BeltRotationAxis axis = config.belt_slice_rotation.value;
|
|
||||||
double angle_deg = config.belt_slice_rotation_angle.value;
|
|
||||||
bool active = axis != BeltRotationAxis::None && std::abs(angle_deg) > EPSILON;
|
|
||||||
if (has_rot_out) *has_rot_out = active;
|
|
||||||
if (!active)
|
|
||||||
return Matrix3d::Identity();
|
|
||||||
double angle_rad = Geometry::deg2rad(angle_deg);
|
|
||||||
Vec3d unit_axis;
|
|
||||||
switch (axis) {
|
|
||||||
case BeltRotationAxis::X: unit_axis = Vec3d::UnitX(); break;
|
|
||||||
case BeltRotationAxis::Y: unit_axis = Vec3d::UnitY(); break;
|
|
||||||
case BeltRotationAxis::Z: unit_axis = Vec3d::UnitZ(); break;
|
|
||||||
default: return Matrix3d::Identity();
|
|
||||||
}
|
|
||||||
return Eigen::AngleAxisd(angle_rad, unit_axis).toRotationMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform3d BeltTransformPipeline::build_forward_transform(const PrintConfig &config)
|
|
||||||
{
|
|
||||||
// Mesh-side belt transform: the rotation. (Shear & scale are a g-code-side
|
|
||||||
// stage, not part of the mesh transform.)
|
|
||||||
Transform3d combined = Transform3d::Identity();
|
|
||||||
combined.linear() = build_rotation_matrix(config);
|
|
||||||
return combined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Belt floor parameters ------------------------------------------------
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Belt floor in the rotated slicer frame: the image of z_machine = 0 under R.
|
|
||||||
// R(+α, X): point (·, y, 0) → (·, cos α · y, sin α · y) ⇒ z = tan(α) · y_s
|
|
||||||
// R(+α, Y): point (x, ·, 0) → (cos α · x, ·, -sin α · x) ⇒ z = -tan(α) · x_s
|
|
||||||
// R(+α, Z): point (·, ·, 0) → (·, ·, 0); no tilt → no floor
|
|
||||||
void belt_floor_shear(BeltRotationAxis rot_axis, double angle_rad, BeltTransformPipeline::BeltFloorParams &out)
|
|
||||||
{
|
|
||||||
double sin_a = std::sin(angle_rad), cos_a = std::cos(angle_rad);
|
|
||||||
switch (rot_axis) {
|
|
||||||
case BeltRotationAxis::X:
|
|
||||||
out.shear_factor = (std::abs(cos_a) > EPSILON) ? sin_a / cos_a : 0.;
|
|
||||||
out.from_axis = 1; // Y
|
|
||||||
break;
|
|
||||||
case BeltRotationAxis::Y:
|
|
||||||
out.shear_factor = (std::abs(cos_a) > EPSILON) ? -sin_a / cos_a : 0.;
|
|
||||||
out.from_axis = 0; // X
|
|
||||||
break;
|
|
||||||
case BeltRotationAxis::Z:
|
|
||||||
default:
|
|
||||||
out.shear_factor = 0.0;
|
|
||||||
out.from_axis = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Z of the belt floor directly under a point of the rotated (unshifted) frame.
|
|
||||||
inline double belt_floor_z(const BeltTransformPipeline::BeltFloorParams &fp, const Vec3d &pt)
|
|
||||||
{
|
|
||||||
return fp.shear_factor * (fp.from_axis == 0 ? pt.x() : pt.y());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BeltTransformPipeline::BeltHeightResult compute_belt_height_and_floor_impl(
|
|
||||||
const PrintConfig &config, const BoundingBoxf3 &bb, double original_height)
|
|
||||||
{
|
|
||||||
BeltTransformPipeline::BeltHeightResult result;
|
|
||||||
result.object_height = original_height;
|
|
||||||
|
|
||||||
// The mesh rotation (the sole mesh-side belt transform).
|
|
||||||
const BeltRotationAxis rot_axis = config.belt_slice_rotation.value;
|
|
||||||
const double rot_angle = config.belt_slice_rotation_angle.value;
|
|
||||||
|
|
||||||
bool has_rotation = rot_axis != BeltRotationAxis::None && std::abs(rot_angle) > EPSILON;
|
|
||||||
if (!has_rotation)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
// Rotation path: sweep the 8 bbox corners through R to get the rotated height,
|
|
||||||
// then derive the belt floor (the image of machine-Z = 0 under R).
|
|
||||||
double angle_rad = Geometry::deg2rad(rot_angle);
|
|
||||||
Vec3d unit_axis;
|
|
||||||
switch (rot_axis) {
|
|
||||||
case BeltRotationAxis::X: unit_axis = Vec3d::UnitX(); break;
|
|
||||||
case BeltRotationAxis::Y: unit_axis = Vec3d::UnitY(); break;
|
|
||||||
case BeltRotationAxis::Z: unit_axis = Vec3d::UnitZ(); break;
|
|
||||||
default: unit_axis = Vec3d::UnitX(); break;
|
|
||||||
}
|
|
||||||
Matrix3d R = Eigen::AngleAxisd(angle_rad, unit_axis).toRotationMatrix();
|
|
||||||
belt_floor_shear(rot_axis, angle_rad, result.floor_params);
|
|
||||||
// The slicing frame starts at the lowest point of the support region: the
|
|
||||||
// lowest belt-floor point under the footprint, not the lowest vertex. The
|
|
||||||
// belt under the leading end of an overhang lies below every vertex of the
|
|
||||||
// part, and supports have to be able to reach it (see
|
|
||||||
// BeltSliceStrategy::apply_preslice_transforms for the exact vertex-scan
|
|
||||||
// counterpart of this bbox estimate).
|
|
||||||
double min_rz = std::numeric_limits<double>::max();
|
|
||||||
double max_rz = std::numeric_limits<double>::lowest();
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
Vec3d c((i & 1) ? bb.max.x() : bb.min.x(),
|
|
||||||
(i & 2) ? bb.max.y() : bb.min.y(),
|
|
||||||
(i & 4) ? bb.max.z() : bb.min.z());
|
|
||||||
Vec3d rc = R * c;
|
|
||||||
double z = rc.z();
|
|
||||||
min_rz = std::min(min_rz, z);
|
|
||||||
max_rz = std::max(max_rz, z);
|
|
||||||
min_rz = std::min(min_rz, belt_floor_z(result.floor_params, rc));
|
|
||||||
}
|
|
||||||
min_rz -= BeltTransformPipeline::frame_margin(result.floor_params);
|
|
||||||
result.object_height = max_rz - min_rz;
|
|
||||||
|
|
||||||
result.floor_params.z_shift = bb.min.z() + ((min_rz < 0.) ? -min_rz : 0.);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
BeltTransformPipeline::BeltHeightResult BeltTransformPipeline::compute_belt_height_and_floor(
|
|
||||||
const PrintConfig &config, const BoundingBoxf3 &bbox, double original_height)
|
|
||||||
{
|
|
||||||
return compute_belt_height_and_floor_impl(config, bbox, original_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BeltTransformPipeline::floor_shear(const PrintConfig &config, BeltFloorParams &out)
|
|
||||||
{
|
|
||||||
out = BeltFloorParams{};
|
|
||||||
const BeltRotationAxis rot_axis = config.belt_slice_rotation.value;
|
|
||||||
const double rot_angle = config.belt_slice_rotation_angle.value;
|
|
||||||
if (rot_axis == BeltRotationAxis::None || std::abs(rot_angle) <= EPSILON)
|
|
||||||
return false;
|
|
||||||
belt_floor_shear(rot_axis, Geometry::deg2rad(rot_angle), out);
|
|
||||||
return std::abs(out.shear_factor) > EPSILON;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "libslic3r.h"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include "BoundingBox.hpp"
|
|
||||||
#include "PrintConfig.hpp"
|
|
||||||
#include "Geometry.hpp"
|
|
||||||
#include "Config.hpp"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
class ModelObject;
|
|
||||||
|
|
||||||
// Shared belt-printer transform math.
|
|
||||||
//
|
|
||||||
// The pre-slice pipeline applied in PrintObjectSlice.cpp is:
|
|
||||||
// trafo_out = z_shift * rotation * trafo_in
|
|
||||||
//
|
|
||||||
// Rotation is the sole mesh-side belt transform; shear & scale are applied
|
|
||||||
// to the g-code instead (see MachineFrameTransform). This class provides the
|
|
||||||
// building blocks so every call site uses the same implementation. z_shift is
|
|
||||||
// object-dependent (computed from mesh vertex bounds) and is NOT included in
|
|
||||||
// build_forward_transform(). The machine-frame shear/scale is derived directly
|
|
||||||
// from the tilt angle in MachineFrameTransform and no longer lives here.
|
|
||||||
//
|
|
||||||
// Design note: this mesh-rotation approach replaced an earlier pre-shear
|
|
||||||
// method (now removed). While that initial pre-shear method was instrumental
|
|
||||||
// in getting belt printer slicing off the ground in the first place, its place is
|
|
||||||
// in the past. A big thank you goes to the Unlayered3D team, who recommended
|
|
||||||
// switching to a pre-slice rotation stage instead. Doing so keeps the slicing
|
|
||||||
// operation isometric — no distortion of the sliced geometry — while the
|
|
||||||
// non-orthogonal machine-axis compensation is confined to a g-code-side shear/scale
|
|
||||||
// derived from the same tilt angle.
|
|
||||||
//
|
|
||||||
// This fixed a number of issues, including several issues noticed by hotcubcar
|
|
||||||
// regarding adaptive infills not working, gyroid becoming anisotropic, and more
|
|
||||||
// that were all mostly resolved as a result of the switch.
|
|
||||||
//
|
|
||||||
// This also means that the pre-slice rotation transform methodology can be used
|
|
||||||
// more cleanly on non-belt printers.
|
|
||||||
// - HarrierPigeon (Joseph Robertson)
|
|
||||||
|
|
||||||
class BeltTransformPipeline
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// ---- Identity checks --------------------------------------------------
|
|
||||||
|
|
||||||
// Whether the G-code axis remap applies at all. The remap fields are only
|
|
||||||
// offered in the belt printer group, so a value left in a profile must not
|
|
||||||
// change a non-belt print: with belt mode off every belt-only key is a no-op.
|
|
||||||
// This is the one place to widen if a non-belt use ever needs them.
|
|
||||||
static bool axis_remap_enabled(const PrintConfig &config) { return config.belt_printer.value; }
|
|
||||||
|
|
||||||
static bool has_rotation(const PrintConfig &config)
|
|
||||||
{
|
|
||||||
return config.belt_slice_rotation.value != BeltRotationAxis::None &&
|
|
||||||
std::abs(config.belt_slice_rotation_angle.value) > EPSILON;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Physical belt tilt derived from the slicing rotation — the single source of
|
|
||||||
// truth for bed rendering, support gravity tilt and the bed-exclusion
|
|
||||||
// projection. Returns the tilt magnitude in degrees split onto the X and Y
|
|
||||||
// build-plate tilt axes according to the rotation axis:
|
|
||||||
// rotation about X → tilt_x = angle (gantry tilts in the YZ plane)
|
|
||||||
// rotation about Y → tilt_y = angle (gantry tilts in the XZ plane)
|
|
||||||
// rotation about Z / None → no tilt (in-plane spin doesn't tilt the belt)
|
|
||||||
// The magnitude uses abs(angle) so a negative rotation still reports a positive
|
|
||||||
// physical tilt.
|
|
||||||
struct PhysicalTilt { double tilt_x_deg = 0.; double tilt_y_deg = 0.; };
|
|
||||||
|
|
||||||
static PhysicalTilt physical_tilt(BeltRotationAxis axis, double angle_deg)
|
|
||||||
{
|
|
||||||
PhysicalTilt t;
|
|
||||||
double mag = std::abs(angle_deg);
|
|
||||||
switch (axis) {
|
|
||||||
case BeltRotationAxis::X: t.tilt_x_deg = mag; break;
|
|
||||||
case BeltRotationAxis::Y: t.tilt_y_deg = mag; break;
|
|
||||||
default: break; // Z / None: no physical tilt
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Matrix builders --------------------------------------------------
|
|
||||||
|
|
||||||
// Build the 3x3 rotation matrix from belt_slice_rotation* config.
|
|
||||||
// Returns Identity if rotation axis is None or angle is ~0.
|
|
||||||
// Also sets has_rot_out if non-null.
|
|
||||||
static Matrix3d build_rotation_matrix(const PrintConfig &config, bool *has_rot_out = nullptr);
|
|
||||||
|
|
||||||
// Forward transform (the rotation) — the mesh-side belt transform that
|
|
||||||
// BeltSliceStrategy applies and BeltBackTransform inverts.
|
|
||||||
// Does NOT include the per-object Z-shift.
|
|
||||||
static Transform3d build_forward_transform(const PrintConfig &config);
|
|
||||||
|
|
||||||
// ---- Belt floor parameters --------------------------------------------
|
|
||||||
|
|
||||||
struct BeltFloorParams {
|
|
||||||
double shear_factor = 0.0;
|
|
||||||
int from_axis = 1;
|
|
||||||
double z_shift = 0.0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Shear factor and from-axis of the belt floor in the rotated slicer frame
|
|
||||||
// (z_floor = shear_factor * u, u = the from-axis coordinate), for the
|
|
||||||
// rotation the config selects. z_shift is left at 0. Returns false (and
|
|
||||||
// zero shear) when the config has no tilt.
|
|
||||||
static bool floor_shear(const PrintConfig &config, BeltFloorParams &out);
|
|
||||||
|
|
||||||
// How far below the lowest belt-floor point under the footprint the slicing
|
|
||||||
// frame starts, in slicing Z. A support column meeting the belt is wider at
|
|
||||||
// its base than at its tip, so under a leading overhang the base reaches ahead
|
|
||||||
// of the part along the belt, and the layers that trim it to the belt plane
|
|
||||||
// lie below that lowest point: 10 mm along the belt.
|
|
||||||
static double frame_margin(const BeltFloorParams &fp) { return 10. * std::abs(fp.shear_factor); }
|
|
||||||
|
|
||||||
// Result of computing belt height + floor params.
|
|
||||||
struct BeltHeightResult {
|
|
||||||
double object_height; // Effective object height after shear/scale
|
|
||||||
BeltFloorParams floor_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compute effective object height and belt floor parameters from config
|
|
||||||
// and the object's bounding box. original_height is the input height
|
|
||||||
// (bb.size().z() or model_object.max_z()).
|
|
||||||
static BeltHeightResult compute_belt_height_and_floor(
|
|
||||||
const PrintConfig &config, const BoundingBoxf3 &bbox,
|
|
||||||
double original_height);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
+1
-14
@@ -474,9 +474,7 @@ static ExPolygons outer_inner_brim_area(const Print& print,
|
|||||||
const bool use_brim_ears = object->config().brim_type == btPainted;
|
const bool use_brim_ears = object->config().brim_type == btPainted;
|
||||||
const bool use_inner_brim_ears = (use_auto_brim_ears || use_brim_ears) && !object->config().brim_ears_outer_only.value;
|
const bool use_inner_brim_ears = (use_auto_brim_ears || use_brim_ears) && !object->config().brim_ears_outer_only.value;
|
||||||
const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_inner_brim_ears;
|
const bool has_inner_brim = brim_type == btInnerOnly || brim_type == btOuterAndInner || use_inner_brim_ears;
|
||||||
// btLeadingEdgeOnly is a belt-printer mode; on a flat bed there is no leading
|
const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || use_auto_brim_ears || use_brim_ears;
|
||||||
// edge, so it degrades to an ordinary outer brim rather than silently to none.
|
|
||||||
const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || brim_type == btLeadingEdgeOnly || use_auto_brim_ears || use_brim_ears;
|
|
||||||
coord_t ear_detection_length = scale_(object->config().brim_ears_detection_length.value);
|
coord_t ear_detection_length = scale_(object->config().brim_ears_detection_length.value);
|
||||||
coordf_t brim_ears_max_angle = object->config().brim_ears_max_angle.value;
|
coordf_t brim_ears_max_angle = object->config().brim_ears_max_angle.value;
|
||||||
//ORCA: Select brim base slices from EFC-compensated outline when enabled.
|
//ORCA: Select brim base slices from EFC-compensated outline when enabled.
|
||||||
@@ -891,17 +889,6 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
|
|||||||
std::vector<unsigned int>& printExtruders,
|
std::vector<unsigned int>& printExtruders,
|
||||||
std::map<ObjectInstanceID, ExPolygons>* objectBrimAreasByInstanceOut)
|
std::map<ObjectInstanceID, ExPolygons>* objectBrimAreasByInstanceOut)
|
||||||
{
|
{
|
||||||
// Belt printers never use the flat plate brim.
|
|
||||||
//
|
|
||||||
// With a tilted belt the brim has to be laid onto the belt plane over many layers,
|
|
||||||
// which BeltBrim.cpp does during posSupportMaterial. With an untilted belt this
|
|
||||||
// could in principle fall through and produce an ordinary brim, but it would never
|
|
||||||
// reach the G-code: the plate brim is emitted out of skirt_brim_groups(), which
|
|
||||||
// _make_skirt() builds, and that returns early for every belt printer. Running the
|
|
||||||
// generator anyway would just burn time on geometry nobody prints.
|
|
||||||
if (print.config().belt_printer.value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::map<ObjectInstanceID, ExPolygons> brimAreaMap;
|
std::map<ObjectInstanceID, ExPolygons> brimAreaMap;
|
||||||
Flow flow = print.brim_flow();
|
Flow flow = print.brim_flow();
|
||||||
ExPolygons islands_area_ex = outer_inner_brim_area(print,
|
ExPolygons islands_area_ex = outer_inner_brim_area(print,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
indexed_triangle_set bounding_mesh(bool scale=true) const;
|
indexed_triangle_set bounding_mesh(bool scale=true) const;
|
||||||
|
|
||||||
// Center of the print bed, unscaled.
|
// Center of the print bed, unscaled.
|
||||||
Vec2d bed_center() const { return get_extents(m_bed_shape).center(); }
|
Vec2d bed_center() const { return to_2d(m_bboxf.center()); }
|
||||||
// Convex hull of polygon(), scaled.
|
// Convex hull of polygon(), scaled.
|
||||||
const Polygon& convex_hull() const { return m_convex_hull; }
|
const Polygon& convex_hull() const { return m_convex_hull; }
|
||||||
// Smallest enclosing circle of polygon(), scaled.
|
// Smallest enclosing circle of polygon(), scaled.
|
||||||
|
|||||||
@@ -85,15 +85,6 @@ set(lisbslic3r_sources
|
|||||||
BoundingBox.hpp
|
BoundingBox.hpp
|
||||||
BridgeDetector.cpp
|
BridgeDetector.cpp
|
||||||
BridgeDetector.hpp
|
BridgeDetector.hpp
|
||||||
BeltBrim.cpp
|
|
||||||
BeltBrim.hpp
|
|
||||||
BeltGCode.cpp
|
|
||||||
BeltGCode.hpp
|
|
||||||
BeltPurge.cpp
|
|
||||||
BeltSliceStrategy.cpp
|
|
||||||
BeltSliceStrategy.hpp
|
|
||||||
BeltTransform.cpp
|
|
||||||
BeltTransform.hpp
|
|
||||||
Brim.cpp
|
Brim.cpp
|
||||||
BrimEarsPoint.hpp
|
BrimEarsPoint.hpp
|
||||||
Brim.hpp
|
Brim.hpp
|
||||||
@@ -180,8 +171,6 @@ set(lisbslic3r_sources
|
|||||||
Fill/FillPlanePath.hpp
|
Fill/FillPlanePath.hpp
|
||||||
Fill/FillRectilinear.cpp
|
Fill/FillRectilinear.cpp
|
||||||
Fill/FillRectilinear.hpp
|
Fill/FillRectilinear.hpp
|
||||||
Fill/FillTpmsAdaptive.cpp
|
|
||||||
Fill/FillTpmsAdaptive.hpp
|
|
||||||
Fill/FillTpmsD.cpp
|
Fill/FillTpmsD.cpp
|
||||||
Fill/FillTpmsD.hpp
|
Fill/FillTpmsD.hpp
|
||||||
Fill/FillTpmsFK.cpp
|
Fill/FillTpmsFK.cpp
|
||||||
@@ -243,14 +232,6 @@ set(lisbslic3r_sources
|
|||||||
GCode/AdaptivePAProcessor.hpp
|
GCode/AdaptivePAProcessor.hpp
|
||||||
GCode/AvoidCrossingPerimeters.cpp
|
GCode/AvoidCrossingPerimeters.cpp
|
||||||
GCode/AvoidCrossingPerimeters.hpp
|
GCode/AvoidCrossingPerimeters.hpp
|
||||||
GCode/BeltBackTransform.cpp
|
|
||||||
GCode/BeltBackTransform.hpp
|
|
||||||
GCode/MachineFrameTransform.cpp
|
|
||||||
GCode/MachineFrameTransform.hpp
|
|
||||||
GCode/BeltKinematics.cpp
|
|
||||||
GCode/BeltKinematics.hpp
|
|
||||||
GCode/MachineKinematics.cpp
|
|
||||||
GCode/MachineKinematics.hpp
|
|
||||||
GCode/ConflictChecker.cpp
|
GCode/ConflictChecker.cpp
|
||||||
GCode/ConflictChecker.hpp
|
GCode/ConflictChecker.hpp
|
||||||
GCode/CoolingBuffer.cpp
|
GCode/CoolingBuffer.cpp
|
||||||
@@ -472,8 +453,6 @@ set(lisbslic3r_sources
|
|||||||
SlicingAdaptive.hpp
|
SlicingAdaptive.hpp
|
||||||
Slicing.cpp
|
Slicing.cpp
|
||||||
Slicing.hpp
|
Slicing.hpp
|
||||||
Support/BeltFloorContext.cpp
|
|
||||||
Support/BeltFloorContext.hpp
|
|
||||||
Support/SupportCommon.cpp
|
Support/SupportCommon.cpp
|
||||||
Support/SupportCommon.hpp
|
Support/SupportCommon.hpp
|
||||||
Support/SupportLayer.hpp
|
Support/SupportLayer.hpp
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user