diff --git a/.doxygen b/.doxygen
index fb8ae5f045..d557f6ba85 100644
--- a/.doxygen
+++ b/.doxygen
@@ -48,7 +48,7 @@ PROJECT_NAME = OrcaSlicer
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.6.3
+PROJECT_NUMBER = latest
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -68,7 +68,7 @@ PROJECT_LOGO = ./resources/images/OrcaSlicer_32px.png
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = ../
+OUTPUT_DIRECTORY = .
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# sub-directories (in 2 levels) under the output directory of each output format
@@ -1059,7 +1059,11 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
-EXCLUDE_PATTERNS =
+EXCLUDE_PATTERNS = */deps/*
+EXCLUDE_PATTERNS = */build/*
+EXCLUDE_PATTERNS = */deps_src/*
+
+
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@@ -1286,7 +1290,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_OUTPUT = OrcaSlicer_Dev_Document
+HTML_OUTPUT = internal_docs
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
@@ -1565,7 +1569,7 @@ TOC_EXPAND = NO
# protocol see https://www.sitemaps.org
# This tag requires that the tag GENERATE_HTML is set to YES.
-SITEMAP_URL =
+SITEMAP_URL = internals.orcaslicer.com
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml
index 1e944a7667..0cae85189b 100644
--- a/.github/workflows/build_all.yml
+++ b/.github/workflows/build_all.yml
@@ -94,7 +94,7 @@ jobs:
- name: Apt-Install Dependencies
uses: ./.github/actions/apt-install-deps
- name: Restore Test Artifact
- uses: actions/download-artifact@v6
+ uses: actions/download-artifact@v7
with:
name: ${{ github.sha }}-tests
- uses: lukka/get-cmake@latest
@@ -106,7 +106,7 @@ jobs:
tar -xvf build_tests.tar
scripts/run_unit_tests.sh
- name: Upload Test Logs
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
if: ${{ failure() }}
with:
name: unit-test-logs
@@ -170,7 +170,7 @@ jobs:
arch: ${{ matrix.variant.arch }}
upload-artifact: false
- name: Upload artifacts Flatpak
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml
index 045f9f7f2a..c6288330a1 100644
--- a/.github/workflows/build_deps.yml
+++ b/.github/workflows/build_deps.yml
@@ -35,7 +35,7 @@ jobs:
# So building XOR cache loading.
# We use `lookup-only` to skip pulling cache.
- name: load cached deps
- uses: actions/cache/restore@v4
+ uses: actions/cache/restore@v5
id: cache-load
with:
path: ${{ env.DEPS_PATH }}
@@ -97,7 +97,7 @@ jobs:
- name: Upload OrcaSlicer_dep director(ies) for use later
if: ${{ !cancelled() && ! env.ACT}}
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.DEPS_PATH }}
@@ -106,7 +106,7 @@ jobs:
- name: Save cache from main branch
if: ${{ !cancelled() && github.ref == 'refs/heads/main' && steps.cache-load.outputs.cache-hit != 'true' }}
- uses: actions/cache/save@v4
+ uses: actions/cache/save@v5
with:
path: ${{ env.DEPS_PATH }}
key: ${{ steps.cache-load.outputs.cache-primary-key }}
diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml
index 986ac4059c..d70b4c9200 100644
--- a/.github/workflows/build_orca.yml
+++ b/.github/workflows/build_orca.yml
@@ -31,7 +31,7 @@ jobs:
lfs: 'true'
- name: Download deps artifacts
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v7
with:
name: ${{ inputs.artifact-name }}
path: ${{ inputs.artifact-path }}
@@ -180,14 +180,14 @@ jobs:
- name: Upload artifacts mac
if: inputs.os == 'macos-14'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_Mac_universal_${{ env.ver }}
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
- name: Upload OrcaSlicer_profile_validator DMG mac
if: inputs.os == 'macos-14'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_profile_validator_Mac_universal_DMG_${{ env.ver }}
path: ${{ github.workspace }}/OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
@@ -254,28 +254,28 @@ jobs:
- name: Upload artifacts Win zip
if: inputs.os == 'windows-latest'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_Windows_${{ env.ver }}_portable
path: ${{ github.workspace }}/build/OrcaSlicer
- name: Upload artifacts Win installer
if: inputs.os == 'windows-latest'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_Windows_${{ env.ver }}
path: ${{ github.workspace }}/build/OrcaSlicer*.exe
- name: Upload artifacts Win PDB
if: inputs.os == 'windows-latest'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: PDB
path: ${{ github.workspace }}/build/src/Release/Debug_PDB_${{ env.ver }}_for_developers_only.7z
- name: Upload OrcaSlicer_profile_validator Win
if: inputs.os == 'windows-latest'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_profile_validator_Windows_${{ env.ver }}
path: ${{ github.workspace }}/build/src/Release/OrcaSlicer_profile_validator.exe
@@ -335,7 +335,7 @@ jobs:
# and doesn't preserve file permissions
- name: Upload Test Artifact
if: inputs.os == 'ubuntu-24.04'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: ${{ github.sha }}-tests
overwrite: true
@@ -357,7 +357,7 @@ jobs:
env:
ubuntu-ver: ${{ (inputs.os == 'ubuntu-20.04' && '2004') || (inputs.os == 'ubuntu-24.04' && '2404') || '' }}
ubuntu-ver-str: ${{ (inputs.os == 'ubuntu-24.04' && '_Ubuntu2404') || '' }}
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_Linux_ubuntu_${{ env.ubuntu-ver }}_${{ env.ver }}
path: './build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}_${{ env.ver }}.AppImage'
@@ -366,7 +366,7 @@ jobs:
if: ${{ ! env.ACT && inputs.os == 'ubuntu-20.04' || inputs.os == 'ubuntu-24.04' }}
env:
ubuntu-ver: ${{ (inputs.os == 'ubuntu-20.04' && '2004') || (inputs.os == 'ubuntu-24.04' && '2404') || '' }}
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v6
with:
name: OrcaSlicer_profile_validator_Linux_ubuntu_${{ env.ubuntu-ver }}_${{ env.ver }}
path: './build/src/Release/OrcaSlicer_profile_validator'
diff --git a/.github/workflows/doxygen-docs.yml b/.github/workflows/doxygen-docs.yml
new file mode 100644
index 0000000000..f30c3e0d0e
--- /dev/null
+++ b/.github/workflows/doxygen-docs.yml
@@ -0,0 +1,78 @@
+name: Generate Doxygen Documentation
+
+on:
+ schedule:
+ - cron: '0 0 * * 1' # Every Monday at midnight UTC
+ workflow_dispatch: # Manual trigger
+
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: true
+
+jobs:
+ build-and-deploy:
+ name: Build and Deploy Docs
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ # Only run on main branch of the main repository
+ if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main'
+ permissions:
+ contents: read
+ steps:
+ - uses: thejerrybao/setup-swap-space@v1
+ with:
+ swap-space-path: /swapfile
+ swap-size-gb: 8
+ remove-existing-swap-files: true
+
+ - name: Checkout repository
+ uses: actions/checkout@v6
+
+ - name: Install Doxygen and Graphviz
+ run: |
+ set -euo pipefail
+ sudo apt-get update
+ sudo apt-get install -y doxygen graphviz
+
+ - name: Generate documentation
+ run: |
+ set -euo pipefail
+ # Override DOT_NUM_THREADS to avoid parallel dot race condition bug
+ sed -i 's/^DOT_NUM_THREADS.*/DOT_NUM_THREADS = 1/' .doxygen
+ doxygen .doxygen
+ # Verify documentation was generated
+ if [ ! -f "internal_docs/index.html" ]; then
+ echo "Error: Documentation generation failed - index.html not found"
+ exit 1
+ fi
+ - name: Install Rclone
+ run: |
+ set -euo pipefail
+ sudo -v
+ curl -fsSL https://rclone.org/install.sh | sudo bash
+
+ - name: optimize
+ run: |
+ set -euo pipefail
+ rm -f internal_docs/Nodes.xml internal_docs/Tokens.xml
+ find internal_docs -name "*.map" -type f -delete || true
+ find internal_docs -name "*.md5" -type f -delete || true
+
+ - name: upload
+ # We configure rclone dynamically using environment variables
+ run: |
+ set -euo pipefail
+ # Remove existing config if it exists to avoid conflicts
+ rclone config delete cloudflare 2>/dev/null || true
+ rclone config create cloudflare s3 \
+ provider Cloudflare \
+ access_key_id ${{ secrets.R2_ACCESS_KEY_ID }} \
+ secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }} \
+ endpoint ${{ secrets.R2_ENDPOINT }}
+
+ rclone sync internal_docs/ cloudflare:orcaslicer-internals \
+ --progress \
+ --transfers 512 \
+ --checkers 512
+
+ echo "Documentation upload completed successfully"
\ No newline at end of file
diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
index 336636bbcc..d5fe5a35d2 100644
--- a/.github/workflows/shellcheck.yml
+++ b/.github/workflows/shellcheck.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Cache shellcheck download
id: cache-shellcheck-v0_11
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/shellcheck
key: ${{ runner.os }}-shellcheck-v0_11
diff --git a/.gitignore b/.gitignore
index 09abcc8dee..5b369a47fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,4 @@ deps_src/build/
test.js
/.cache/
.clangd
+internal_docs/
diff --git a/README.md b/README.md
index 59fb76034b..afd418ea0a 100644
--- a/README.md
+++ b/README.md
@@ -44,19 +44,19 @@ If you come across any of these in search results, please report them as
# Main features
-- **[Advanced Calibration Tools](https://github.com/OrcaSlicer/OrcaSlicer/wiki/Calibration)**
+- **[Advanced Calibration Tools](https://www.orcaslicer.com/wiki/Calibration)**
Comprehensive suite: temperature towers, flow rate, retraction & more for optimal performance.
-- **[Precise Wall](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_precision#precise-wall) and [Seam Control](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_seam)**
+- **[Precise Wall](https://www.orcaslicer.com/wiki/quality_settings_precision#precise-wall) and [Seam Control](https://www.orcaslicer.com/wiki/quality_settings_seam)**
Adjust outer wall spacing and apply scarf seams to enhance print accuracy.
-- **[Sandwich Mode](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_wall_and_surfaces#innerouterinner) and [Polyholes](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_precision#polyholes) Support**
- Use varied infill [patterns](https://github.com/OrcaSlicer/OrcaSlicer/wiki/strength_settings_patterns) and accurate hole shapes for improved clarity.
-- **[Overhang](https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_overhangs) and [Support Optimization](https://github.com/OrcaSlicer/OrcaSlicer/wiki#support-settings)**
+- **[Sandwich Mode](https://www.orcaslicer.com/wiki/quality_settings_wall_and_surfaces#innerouterinner) and [Polyholes](https://www.orcaslicer.com/wiki/quality_settings_precision#polyholes) Support**
+ Use varied infill [patterns](https://www.orcaslicer.com/wiki/strength_settings_patterns) and accurate hole shapes for improved clarity.
+- **[Overhang](https://www.orcaslicer.com/wiki/quality_settings_overhangs) and [Support Optimization](https://www.orcaslicer.com/wiki#support-settings)**
Modify geometry for printable overhangs with precise support placement.
-- **[Granular Controls and Customization](https://github.com/OrcaSlicer/OrcaSlicer/wiki#process-settings)**
+- **[Granular Controls and Customization](https://www.orcaslicer.com/wiki#process-settings)**
Fine-tune print speed, layer height, pressure, and temperature with precision.
- **Network Printer Support**
Seamless integration with Klipper, PrusaLink, and OctoPrint for remote control.
-- **[Mouse Ear Brims](https://github.com/OrcaSlicer/OrcaSlicer/wiki/others_settings_brim) & [Adaptive Bed Mesh](https://github.com/OrcaSlicer/OrcaSlicer/wiki/printer_basic_information_adaptive_bed_mesh)**
+- **[Mouse Ear Brims](https://www.orcaslicer.com/wiki/others_settings_brim) & [Adaptive Bed Mesh](https://www.orcaslicer.com/wiki/printer_basic_information_adaptive_bed_mesh)**
Automatic brims and adaptive mesh calibration ensure consistent adhesion.
- **User-Friendly Interface**
Intuitive drag-and-drop design with pre-made profiles for popular printers.
@@ -68,10 +68,10 @@ If you come across any of these in search results, please report them as
# Wiki
-The [wiki](https://github.com/OrcaSlicer/OrcaSlicer/wiki) aims to provide a detailed explanation of the slicer settings, including how to maximize their use and how to calibrate and set up your printer.
+The [wiki](https://www.orcaslicer.com/wiki) aims to provide a detailed explanation of the slicer settings, including how to maximize their use and how to calibrate and set up your printer.
-- **[Access the wiki here](https://github.com/OrcaSlicer/OrcaSlicer/wiki)**
-- **[Contribute to the wiki](https://github.com/OrcaSlicer/OrcaSlicer/wiki/How-to-wiki)**
+- **[Access the wiki here](https://www.orcaslicer.com/wiki)**
+- **[Contribute to the wiki](https://www.orcaslicer.com/wiki/How-to-wiki)**
# Download
@@ -144,7 +144,7 @@ winget install --id=SoftFever.OrcaSlicer -e
# How to Compile
-All updated build instructions for Windows, macOS, and Linux are now available on the official [OrcaSlicer Wiki - How to build](https://github.com/OrcaSlicer/OrcaSlicer/wiki/How-to-build) page.
+All updated build instructions for Windows, macOS, and Linux are now available on the official [OrcaSlicer Wiki - How to build](https://www.orcaslicer.com/wiki/How-to-build) page.
Please refer to the wiki to ensure you're following the latest and most accurate steps for your platform.
diff --git a/deps/Qhull/Qhull.cmake b/deps/Qhull/Qhull.cmake
index 9376700428..97667021c0 100644
--- a/deps/Qhull/Qhull.cmake
+++ b/deps/Qhull/Qhull.cmake
@@ -1,11 +1,11 @@
include(GNUInstallDirs)
orcaslicer_add_cmake_project(Qhull
- URL "https://github.com/qhull/qhull/archive/v8.0.1.zip"
- URL_HASH SHA256=5287f5edd6a0372588f5d6640799086a4033d89d19711023ef8229dd9301d69b
+ URL "https://github.com/qhull/qhull/archive/v8.0.2.zip"
+ URL_HASH SHA256=a378e9a39e718e289102c20d45632f873bfdc58a7a5f924246ea4b176e185f1e
CMAKE_ARGS
-DINCLUDE_INSTALL_DIR=${CMAKE_INSTALL_INCLUDEDIR}
)
if (MSVC)
add_debug_dep(dep_Qhull)
-endif ()
\ No newline at end of file
+endif ()
diff --git a/deps_src/CMakeLists.txt b/deps_src/CMakeLists.txt
index 5c4e62b99f..390cffad30 100644
--- a/deps_src/CMakeLists.txt
+++ b/deps_src/CMakeLists.txt
@@ -10,13 +10,13 @@ add_subdirectory(earcut)
add_subdirectory(fast_float)
add_subdirectory(nanosvg)
add_subdirectory(nlohmann)
-add_subdirectory(spline) # Header-only spline library
add_subdirectory(stb_dxt) # Header-only STB DXT compression library
# Static libraries
add_subdirectory(Shiny)
add_subdirectory(admesh)
add_subdirectory(clipper)
+add_subdirectory(clipper2)
add_subdirectory(expat)
add_subdirectory(glu-libtess)
add_subdirectory(hidapi)
diff --git a/deps_src/README_CMAKE_INTERFACES.md b/deps_src/README_CMAKE_INTERFACES.md
index 78a806fc0b..6ab88c63af 100644
--- a/deps_src/README_CMAKE_INTERFACES.md
+++ b/deps_src/README_CMAKE_INTERFACES.md
@@ -24,18 +24,7 @@ target_link_libraries(your_target PRIVATE semver::semver)
target_link_libraries(your_target PRIVATE hints)
```
-### 3. **spline** (Interface Library)
-- **Type**: Interface library (header-only)
-- **Target**: `spline` or `spline::spline`
-- **Headers**: `spline.h`
-- **Usage**:
-```cmake
-target_link_libraries(your_target PRIVATE spline)
-# or
-target_link_libraries(your_target PRIVATE spline::spline)
-```
-
-### 4. **stb_dxt** (Interface Library)
+### 3. **stb_dxt** (Interface Library)
- **Type**: Interface library (header-only)
- **Target**: `stb_dxt` or `stb_dxt::stb_dxt`
- **Headers**: `stb_dxt.h`
@@ -53,10 +42,9 @@ target_link_libraries(your_target PRIVATE stb_dxt::stb_dxt)
1. **In your CMakeLists.txt**, simply link the library:
```cmake
add_executable(my_app main.cpp)
-target_link_libraries(my_app
- PRIVATE
+target_link_libraries(my_app
+ PRIVATE
semver::semver # For version parsing
- spline::spline # For spline interpolation
stb_dxt::stb_dxt # For DXT texture compression
hints # For hints functionality
)
@@ -67,9 +55,6 @@ target_link_libraries(my_app
// For semver
#include
-// For spline
-#include
-
// For stb_dxt
#include
@@ -100,7 +85,6 @@ target_link_libraries(mycomponent
PUBLIC
semver::semver # Version handling is part of public API
PRIVATE
- spline::spline # Used internally for interpolation
stb_dxt::stb_dxt # Used internally for texture compression
)
diff --git a/src/clipper2/CMakeLists.txt b/deps_src/clipper2/CMakeLists.txt
similarity index 100%
rename from src/clipper2/CMakeLists.txt
rename to deps_src/clipper2/CMakeLists.txt
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h
diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper2_z.hpp b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper2_z.hpp
similarity index 100%
rename from src/clipper2/Clipper2Lib/include/clipper2/clipper2_z.hpp
rename to deps_src/clipper2/Clipper2Lib/include/clipper2/clipper2_z.hpp
diff --git a/src/clipper2/Clipper2Lib/src/clipper.engine.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp
similarity index 100%
rename from src/clipper2/Clipper2Lib/src/clipper.engine.cpp
rename to deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp
diff --git a/src/clipper2/Clipper2Lib/src/clipper.offset.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp
similarity index 100%
rename from src/clipper2/Clipper2Lib/src/clipper.offset.cpp
rename to deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp
diff --git a/src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp
similarity index 100%
rename from src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp
rename to deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp
diff --git a/src/clipper2/Clipper2Lib/src/clipper2_z.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp
similarity index 100%
rename from src/clipper2/Clipper2Lib/src/clipper2_z.cpp
rename to deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp
diff --git a/deps_src/spline/CMakeLists.txt b/deps_src/spline/CMakeLists.txt
deleted file mode 100644
index ee6d5c9cb3..0000000000
--- a/deps_src/spline/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-cmake_minimum_required(VERSION 3.13)
-project(spline)
-
-# Create interface library for spline (header-only library)
-add_library(spline INTERFACE)
-
-# Set include directories for the interface library
-target_include_directories(spline SYSTEM
- INTERFACE
- $
- $
-)
-
-# Add compile features
-target_compile_features(spline INTERFACE cxx_std_11)
-
-# Create an alias for consistent naming
-add_library(spline::spline ALIAS spline)
-
-# Install headers if needed
-install(FILES
- spline.h
- DESTINATION include/spline
-)
-
-# Install the interface library
-install(TARGETS spline
- EXPORT splineTargets
- INCLUDES DESTINATION include
-)
-
-# Export the targets
-install(EXPORT splineTargets
- FILE splineTargets.cmake
- NAMESPACE spline::
- DESTINATION lib/cmake/spline
-)
diff --git a/deps_src/spline/spline.h b/deps_src/spline/spline.h
deleted file mode 100644
index 4b1ddd6134..0000000000
--- a/deps_src/spline/spline.h
+++ /dev/null
@@ -1,944 +0,0 @@
-/*
- * spline.h
- *
- * simple cubic spline interpolation library without external
- * dependencies
- *
- * ---------------------------------------------------------------------
- * Copyright (C) 2011, 2014, 2016, 2021 Tino Kluge (ttk448 at gmail.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- * ---------------------------------------------------------------------
- *
- */
-
-
-#ifndef TK_SPLINE_H
-#define TK_SPLINE_H
-
-#include
-#include
-#include
-#include
-#include
-#ifdef HAVE_SSTREAM
-#include
-#include
-#endif // HAVE_SSTREAM
-
-// not ideal but disable unused-function warnings
-// (we get them because we have implementations in the header file,
-// and this is because we want to be able to quickly separate them
-// into a cpp file if necessary)
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-
-namespace tk
-{
-
-// spline interpolation
-class spline
-{
-public:
- // spline types
- enum spline_type {
- linear = 10, // linear interpolation
- cspline = 30, // cubic splines (classical C^2)
- cspline_hermite = 31 // cubic hermite splines (local, only C^1)
- };
-
- // boundary condition type for the spline end-points
- enum bd_type {
- first_deriv = 1,
- second_deriv = 2,
- not_a_knot = 3
- };
-
-protected:
- std::vector m_x,m_y; // x,y coordinates of points
- // interpolation parameters
- // f(x) = a_i + b_i*(x-x_i) + c_i*(x-x_i)^2 + d_i*(x-x_i)^3
- // where a_i = y_i, or else it won't go through grid points
- std::vector m_b,m_c,m_d; // spline coefficients
- double m_c0; // for left extrapolation
- spline_type m_type;
- bd_type m_left, m_right;
- double m_left_value, m_right_value;
- bool m_made_monotonic;
- void set_coeffs_from_b(); // calculate c_i, d_i from b_i
- size_t find_closest(double x) const; // closest idx so that m_x[idx]<=x
-
-public:
- // default constructor: set boundary condition to be zero curvature
- // at both ends, i.e. natural splines
- spline(): m_type(cspline),
- m_left(second_deriv), m_right(second_deriv),
- m_left_value(0.0), m_right_value(0.0), m_made_monotonic(false)
- {
- ;
- }
- spline(const std::vector& X, const std::vector& Y,
- spline_type type = cspline,
- bool make_monotonic = false,
- bd_type left = second_deriv, double left_value = 0.0,
- bd_type right = second_deriv, double right_value = 0.0
- ):
- m_type(type),
- m_left(left), m_right(right),
- m_left_value(left_value), m_right_value(right_value),
- m_made_monotonic(false) // false correct here: make_monotonic() sets it
- {
- this->set_points(X,Y,m_type);
- if(make_monotonic) {
- this->make_monotonic();
- }
- }
-
-
- // modify boundary conditions: if called it must be before set_points()
- void set_boundary(bd_type left, double left_value,
- bd_type right, double right_value);
-
- // set all data points (cubic_spline=false means linear interpolation)
- void set_points(const std::vector& x,
- const std::vector& y,
- spline_type type=cspline);
-
- // adjust coefficients so that the spline becomes piecewise monotonic
- // where possible
- // this is done by adjusting slopes at grid points by a non-negative
- // factor and this will break C^2
- // this can also break boundary conditions if adjustments need to
- // be made at the boundary points
- // returns false if no adjustments have been made, true otherwise
- bool make_monotonic();
-
- // evaluates the spline at point x
- double operator() (double x) const;
- double deriv(int order, double x) const;
-
- // solves for all x so that: spline(x) = y
- std::vector solve(double y, bool ignore_extrapolation=true) const;
-
- // returns the input data points
- std::vector get_x() const { return m_x; }
- std::vector get_y() const { return m_y; }
- double get_x_min() const { assert(!m_x.empty()); return m_x.front(); }
- double get_x_max() const { assert(!m_x.empty()); return m_x.back(); }
-
-#ifdef HAVE_SSTREAM
- // spline info string, i.e. spline type, boundary conditions etc.
- std::string info() const;
-#endif // HAVE_SSTREAM
-
-};
-
-
-
-namespace internal
-{
-
-// band matrix solver
-class band_matrix
-{
-private:
- std::vector< std::vector > m_upper; // upper band
- std::vector< std::vector > m_lower; // lower band
-public:
- band_matrix() {}; // constructor
- band_matrix(int dim, int n_u, int n_l); // constructor
- ~band_matrix() {}; // destructor
- void resize(int dim, int n_u, int n_l); // init with dim,n_u,n_l
- int dim() const; // matrix dimension
- int num_upper() const
- {
- return (int)m_upper.size()-1;
- }
- int num_lower() const
- {
- return (int)m_lower.size()-1;
- }
- // access operator
- double & operator () (int i, int j); // write
- double operator () (int i, int j) const; // read
- // we can store an additional diagonal (in m_lower)
- double& saved_diag(int i);
- double saved_diag(int i) const;
- void lu_decompose();
- std::vector r_solve(const std::vector& b) const;
- std::vector l_solve(const std::vector& b) const;
- std::vector lu_solve(const std::vector& b,
- bool is_lu_decomposed=false);
-
-};
-
-double get_eps();
-
-std::vector solve_cubic(double a, double b, double c, double d,
- int newton_iter=0);
-
-} // namespace internal
-
-
-
-
-// ---------------------------------------------------------------------
-// implementation part, which could be separated into a cpp file
-// ---------------------------------------------------------------------
-
-// spline implementation
-// -----------------------
-
-void spline::set_boundary(spline::bd_type left, double left_value,
- spline::bd_type right, double right_value)
-{
- assert(m_x.size()==0); // set_points() must not have happened yet
- m_left=left;
- m_right=right;
- m_left_value=left_value;
- m_right_value=right_value;
-}
-
-
-void spline::set_coeffs_from_b()
-{
- assert(m_x.size()==m_y.size());
- assert(m_x.size()==m_b.size());
- assert(m_x.size()>2);
- size_t n=m_b.size();
- if(m_c.size()!=n)
- m_c.resize(n);
- if(m_d.size()!=n)
- m_d.resize(n);
-
- for(size_t i=0; i& x,
- const std::vector& y,
- spline_type type)
-{
- assert(x.size()==y.size());
- assert(x.size()>=3);
- // not-a-knot with 3 points has many solutions
- if(m_left==not_a_knot || m_right==not_a_knot)
- assert(x.size()>=4);
- m_type=type;
- m_made_monotonic=false;
- m_x=x;
- m_y=y;
- int n = (int) x.size();
- // check strict monotonicity of input vector x
- for(int i=0; i rhs(n);
- for(int i=1; i2);
- bool modified = false;
- const int n=(int)m_x.size();
- // make sure: input data monotonic increasing --> b_i>=0
- // input data monotonic decreasing --> b_i<=0
- for(int i=0; i=m_y[i]) && (m_y[i]>=m_y[ip1]) && m_b[i]>0.0) ) {
- modified=true;
- m_b[i]=0.0;
- }
- }
- // if input data is monotonic (b[i], b[i+1], avg have all the same sign)
- // ensure a sufficient criteria for monotonicity is satisfied:
- // sqrt(b[i]^2+b[i+1]^2) <= 3 |avg|, with avg=(y[i+1]-y[i])/h,
- for(int i=0; i=0.0 && m_b[i+1]>=0.0 && avg>0.0) ||
- (m_b[i]<=0.0 && m_b[i+1]<=0.0 && avg<0.0) ) {
- // input data is monotonic
- double r = sqrt(m_b[i]*m_b[i]+m_b[i+1]*m_b[i+1])/std::fabs(avg);
- if(r>3.0) {
- // sufficient criteria for monotonicity: r<=3
- // adjust b[i] and b[i+1]
- modified=true;
- m_b[i] *= (3.0/r);
- m_b[i+1] *= (3.0/r);
- }
- }
- }
-
- if(modified==true) {
- set_coeffs_from_b();
- m_made_monotonic=true;
- }
-
- return modified;
-}
-
-// return the closest idx so that m_x[idx] <= x (return 0 if x::const_iterator it;
- it=std::upper_bound(m_x.begin(),m_x.end(),x); // *it > x
- size_t idx = std::max( int(it-m_x.begin())-1, 0); // m_x[idx] <= x
- return idx;
-}
-
-double spline::operator() (double x) const
-{
- // polynomial evaluation using Horner's scheme
- // TODO: consider more numerically accurate algorithms, e.g.:
- // - Clenshaw
- // - Even-Odd method by A.C.R. Newbery
- // - Compensated Horner Scheme
- size_t n=m_x.size();
- size_t idx=find_closest(x);
-
- double h=x-m_x[idx];
- double interpol;
- if(xm_x[n-1]) {
- // extrapolation to the right
- interpol=(m_c[n-1]*h + m_b[n-1])*h + m_y[n-1];
- } else {
- // interpolation
- interpol=((m_d[idx]*h + m_c[idx])*h + m_b[idx])*h + m_y[idx];
- }
- return interpol;
-}
-
-double spline::deriv(int order, double x) const
-{
- assert(order>0);
- size_t n=m_x.size();
- size_t idx = find_closest(x);
-
- double h=x-m_x[idx];
- double interpol;
- if(xm_x[n-1]) {
- // extrapolation to the right
- switch(order) {
- case 1:
- interpol=2.0*m_c[n-1]*h + m_b[n-1];
- break;
- case 2:
- interpol=2.0*m_c[n-1];
- break;
- default:
- interpol=0.0;
- break;
- }
- } else {
- // interpolation
- switch(order) {
- case 1:
- interpol=(3.0*m_d[idx]*h + 2.0*m_c[idx])*h + m_b[idx];
- break;
- case 2:
- interpol=6.0*m_d[idx]*h + 2.0*m_c[idx];
- break;
- case 3:
- interpol=6.0*m_d[idx];
- break;
- default:
- interpol=0.0;
- break;
- }
- }
- return interpol;
-}
-
-std::vector spline::solve(double y, bool ignore_extrapolation) const
-{
- std::vector x; // roots for the entire spline
- std::vector root; // roots for each piecewise cubic
- const size_t n=m_x.size();
-
- // left extrapolation
- if(ignore_extrapolation==false) {
- root = internal::solve_cubic(m_y[0]-y,m_b[0],m_c0,0.0,1);
- for(size_t j=0; j0) ? (m_x[i]-m_x[i-1]) : 0.0;
- double eps = internal::get_eps()*512.0*std::min(h,1.0);
- if( (-eps<=root[j]) && (root[j]0 && x.back()+eps > new_root) {
- x.back()=new_root; // avoid spurious duplicate roots
- } else {
- x.push_back(new_root);
- }
- }
- }
- }
-
- // right extrapolation
- if(ignore_extrapolation==false) {
- root = internal::solve_cubic(m_y[n-1]-y,m_b[n-1],m_c[n-1],0.0,1);
- for(size_t j=0; j0);
- assert(n_u>=0);
- assert(n_l>=0);
- m_upper.resize(n_u+1);
- m_lower.resize(n_l+1);
- for(size_t i=0; i0) {
- return (int)m_upper[0].size();
- } else {
- return 0;
- }
-}
-
-
-// defines the new operator (), so that we can access the elements
-// by A(i,j), index going from i=0,...,dim()-1
-double & band_matrix::operator () (int i, int j)
-{
- int k=j-i; // what band is the entry
- assert( (i>=0) && (i=0) && (j diagonal, k<0 lower left part, k>0 upper right part
- if(k>=0) return m_upper[k][i];
- else return m_lower[-k][i];
-}
-double band_matrix::operator () (int i, int j) const
-{
- int k=j-i; // what band is the entry
- assert( (i>=0) && (i=0) && (j diagonal, k<0 lower left part, k>0 upper right part
- if(k>=0) return m_upper[k][i];
- else return m_lower[-k][i];
-}
-// second diag (used in LU decomposition), saved in m_lower
-double band_matrix::saved_diag(int i) const
-{
- assert( (i>=0) && (i=0) && (idim(); i++) {
- assert(this->operator()(i,i)!=0.0);
- this->saved_diag(i)=1.0/this->operator()(i,i);
- j_min=std::max(0,i-this->num_lower());
- j_max=std::min(this->dim()-1,i+this->num_upper());
- for(int j=j_min; j<=j_max; j++) {
- this->operator()(i,j) *= this->saved_diag(i);
- }
- this->operator()(i,i)=1.0; // prevents rounding errors
- }
-
- // Gauss LR-Decomposition
- for(int k=0; kdim(); k++) {
- i_max=std::min(this->dim()-1,k+this->num_lower()); // num_lower not a mistake!
- for(int i=k+1; i<=i_max; i++) {
- assert(this->operator()(k,k)!=0.0);
- x=-this->operator()(i,k)/this->operator()(k,k);
- this->operator()(i,k)=-x; // assembly part of L
- j_max=std::min(this->dim()-1,k+this->num_upper());
- for(int j=k+1; j<=j_max; j++) {
- // assembly part of R
- this->operator()(i,j)=this->operator()(i,j)+x*this->operator()(k,j);
- }
- }
- }
-}
-// solves Ly=b
-std::vector band_matrix::l_solve(const std::vector& b) const
-{
- assert( this->dim()==(int)b.size() );
- std::vector x(this->dim());
- int j_start;
- double sum;
- for(int i=0; idim(); i++) {
- sum=0;
- j_start=std::max(0,i-this->num_lower());
- for(int j=j_start; joperator()(i,j)*x[j];
- x[i]=(b[i]*this->saved_diag(i)) - sum;
- }
- return x;
-}
-// solves Rx=y
-std::vector band_matrix::r_solve(const std::vector& b) const
-{
- assert( this->dim()==(int)b.size() );
- std::vector x(this->dim());
- int j_stop;
- double sum;
- for(int i=this->dim()-1; i>=0; i--) {
- sum=0;
- j_stop=std::min(this->dim()-1,i+this->num_upper());
- for(int j=i+1; j<=j_stop; j++) sum += this->operator()(i,j)*x[j];
- x[i]=( b[i] - sum ) / this->operator()(i,i);
- }
- return x;
-}
-
-std::vector band_matrix::lu_solve(const std::vector& b,
- bool is_lu_decomposed)
-{
- assert( this->dim()==(int)b.size() );
- std::vector x,y;
- if(is_lu_decomposed==false) {
- this->lu_decompose();
- }
- y=this->l_solve(b);
- x=this->r_solve(y);
- return x;
-}
-
-// machine precision of a double, i.e. the successor of 1 is 1+eps
-double get_eps()
-{
- //return std::numeric_limits::epsilon(); // __DBL_EPSILON__
- return 2.2204460492503131e-16; // 2^-52
-}
-
-// solutions for a + b*x = 0
-std::vector solve_linear(double a, double b)
-{
- std::vector x; // roots
- if(b==0.0) {
- if(a==0.0) {
- // 0*x = 0
- x.resize(1);
- x[0] = 0.0; // any x solves it but we need to pick one
- return x;
- } else {
- // 0*x + ... = 0, no solution
- return x;
- }
- } else {
- x.resize(1);
- x[0] = -a/b;
- return x;
- }
-}
-
-// solutions for a + b*x + c*x^2 = 0
-std::vector solve_quadratic(double a, double b, double c,
- int newton_iter=0)
-{
- if(c==0.0) {
- return solve_linear(a,b);
- }
- // rescale so that we solve x^2 + 2p x + q = (x+p)^2 + q - p^2 = 0
- double p=0.5*b/c;
- double q=a/c;
- double discr = p*p-q;
- const double eps=0.5*internal::get_eps();
- double discr_err = (6.0*(p*p)+3.0*fabs(q)+fabs(discr))*eps;
-
- std::vector x; // roots
- if(fabs(discr)<=discr_err) {
- // discriminant is zero --> one root
- x.resize(1);
- x[0] = -p;
- } else if(discr<0) {
- // no root
- } else {
- // two roots
- x.resize(2);
- x[0] = -p - sqrt(discr);
- x[1] = -p + sqrt(discr);
- }
-
- // improve solution via newton steps
- for(size_t i=0; i1e-8) {
- x[i] -= f/f1;
- }
- }
- }
-
- return x;
-}
-
-// solutions for the cubic equation: a + b*x +c*x^2 + d*x^3 = 0
-// this is a naive implementation of the analytic solution without
-// optimisation for speed or numerical accuracy
-// newton_iter: number of newton iterations to improve analytical solution
-// see also
-// gsl: gsl_poly_solve_cubic() in solve_cubic.c
-// octave: roots.m - via eigenvalues of the Frobenius companion matrix
-std::vector solve_cubic(double a, double b, double c, double d,
- int newton_iter)
-{
- if(d==0.0) {
- return solve_quadratic(a,b,c,newton_iter);
- }
-
- // convert to normalised form: a + bx + cx^2 + x^3 = 0
- if(d!=1.0) {
- a/=d;
- b/=d;
- c/=d;
- }
-
- // convert to depressed cubic: z^3 - 3pz - 2q = 0
- // via substitution: z = x + c/3
- std::vector z; // roots of the depressed cubic
- double p = -(1.0/3.0)*b + (1.0/9.0)*(c*c);
- double r = 2.0*(c*c)-9.0*b;
- double q = -0.5*a - (1.0/54.0)*(c*r);
- double discr=p*p*p-q*q; // discriminant
- // calculating numerical round-off errors with assumptions:
- // - each operation is precise but each intermediate result x
- // when stored has max error of x*eps
- // - only multiplication with a power of 2 introduces no new error
- // - a,b,c,d and some fractions (e.g. 1/3) have rounding errors eps
- // - p_err << |p|, q_err << |q|, ... (this is violated in rare cases)
- // would be more elegant to use boost::numeric::interval
- const double eps = internal::get_eps();
- double p_err = eps*((3.0/3.0)*fabs(b)+(4.0/9.0)*(c*c)+fabs(p));
- double r_err = eps*(6.0*(c*c)+18.0*fabs(b)+fabs(r));
- double q_err = 0.5*fabs(a)*eps + (1.0/54.0)*fabs(c)*(r_err+fabs(r)*3.0*eps)
- + fabs(q)*eps;
- double discr_err = (p*p) * (3.0*p_err + fabs(p)*2.0*eps)
- + fabs(q) * (2.0*q_err + fabs(q)*eps) + fabs(discr)*eps;
-
- // depending on the discriminant we get different solutions
- if(fabs(discr)<=discr_err) {
- // discriminant zero: one or two real roots
- if(fabs(p)<=p_err) {
- // p and q are zero: single root
- z.resize(1);
- z[0] = 0.0; // triple root
- } else {
- z.resize(2);
- z[0] = 2.0*q/p; // single root
- z[1] = -0.5*z[0]; // double root
- }
- } else if(discr>0) {
- // three real roots: via trigonometric solution
- z.resize(3);
- double ac = (1.0/3.0) * acos( q/(p*sqrt(p)) );
- double sq = 2.0*sqrt(p);
- z[0] = sq * cos(ac);
- z[1] = sq * cos(ac-2.0*M_PI/3.0);
- z[2] = sq * cos(ac-4.0*M_PI/3.0);
- } else if (discr<0.0) {
- // single real root: via Cardano's fromula
- z.resize(1);
- double sgnq = (q >= 0 ? 1 : -1);
- double basis = fabs(q) + sqrt(-discr);
- double C = sgnq * pow(basis, 1.0/3.0); // c++11 has std::cbrt()
- z[0] = C + p/C;
- }
- for(size_t i=0; i1e-8) {
- z[i] -= f/f1;
- }
- }
- }
- // ensure if a=0 we get exactly x=0 as root
- // TODO: remove this fudge
- if(a==0.0) {
- assert(z.size()>0); // cubic should always have at least one root
- double xmin=fabs(z[0]);
- size_t imin=0;
- for(size_t i=1; ifabs(z[i])) {
- xmin=fabs(z[i]);
- imin=i;
- }
- }
- z[imin]=0.0; // replace the smallest absolute value with 0
- }
- std::sort(z.begin(), z.end());
- return z;
-}
-
-
-} // namespace internal
-
-
-} // namespace tk
-
-
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic pop
-#endif
-
-#endif /* TK_SPLINE_H */
diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot
index accaf4ea66..4901a6b7a5 100644
--- a/localization/i18n/OrcaSlicer.pot
+++ b/localization/i18n/OrcaSlicer.pot
@@ -11108,6 +11108,19 @@ msgid ""
"easily."
msgstr ""
+msgid "Brim follows compensated outline"
+msgstr ""
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+
msgid "Brim ears"
msgstr ""
diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po
index cfb35a2480..d29d05b06b 100644
--- a/localization/i18n/ca/OrcaSlicer_ca.po
+++ b/localization/i18n/ca/OrcaSlicer_ca.po
@@ -12177,6 +12177,26 @@ msgstr ""
"Un espai entre la línia de la Vora d'Adherència més interna i l'objecte pot "
"fer que la Vora d'Adherència s'elimini més fàcilment"
+msgid "Brim follows compensated outline"
+msgstr "Vora d'Adherència segueix un esquema compensat"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Quan està activat, vora d'adherència s'alinea amb la geometria del perímetre de la primera capa "
+"després d'aplicar la compensació del peu d'elefant.\n"
+"Aquesta opció està pensada per als casos en què la compensació del peu d'elefant "
+"altera significativament la petjada de la primera capa.\n"
+"\n"
+"Si la vostra configuració actual ja funciona bé, activar-la pot ser innecessari i "
+"pot fer que el vora d'adherència es fusioni amb les capes superiors."
+
msgid "Brim ears"
msgstr "Orelles de la Vora d'Adherència"
diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po
index 9cc4976536..933c3b3504 100644
--- a/localization/i18n/cs/OrcaSlicer_cs.po
+++ b/localization/i18n/cs/OrcaSlicer_cs.po
@@ -11730,6 +11730,26 @@ msgid ""
msgstr ""
"Mezera mezi nejvnitřnějším límcem a předmětem může usnadnit odstranění límce"
+msgid "Brim follows compensated outline"
+msgstr "Límec sleduje kompenzovaný obrys"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Když je povoleno, límec je zarovnán s obvodovou geometrií první vrstvy "
+"po použití kompenzace sloní nohy.\n"
+"Tato možnost je určena pro případy, kdy je kompenzace sloní nohy "
+"výrazně mění stopu první vrstvy.\n"
+"\n"
+"Pokud vaše aktuální nastavení již funguje dobře, jeho povolení může být zbytečné a "
+"může způsobit spojení límec s horními vrstvami."
+
msgid "Brim ears"
msgstr "Uši límce"
diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po
index f0a0be35b4..15b84734a4 100644
--- a/localization/i18n/de/OrcaSlicer_de.po
+++ b/localization/i18n/de/OrcaSlicer_de.po
@@ -12766,6 +12766,26 @@ msgstr ""
"Eine Lücke zwischen der innersten Randlinie und dem Objekt kann das Abnehmen "
"des Randes erleichtern"
+msgid "Brim follows compensated outline"
+msgstr "Umrandung folgt einem kompensierten Umriss"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Wenn diese Option aktiviert ist, wird umrandung an der Umfangsgeometrie der ersten Ebene ausgerichtet "
+"nach Anwendung der Elefantenfußkompensation.\n"
+"Diese Option ist für Fälle gedacht, in denen eine Elefantenfuß-Entschädigung vorliegt "
+"verändert den Footprint der ersten Schicht erheblich.\n"
+"\n"
+"Wenn Ihr aktuelles Setup bereits gut funktioniert, kann es unnötig sein, es zu aktivieren "
+"kann dazu führen, dass der umrandung mit den oberen Schichten verschmilzt."
+
msgid "Brim ears"
msgstr "Brim Ohren"
diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po
index 647f62ee13..02b4dd6c18 100644
--- a/localization/i18n/en/OrcaSlicer_en.po
+++ b/localization/i18n/en/OrcaSlicer_en.po
@@ -11327,6 +11327,26 @@ msgstr ""
"This creates a gap between the innermost brim line and the object and can "
"make the brim easier to remove."
+msgid "Brim follows compensated outline"
+msgstr "Brim follows compensated outline"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+
msgid "Brim ears"
msgstr ""
diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po
index 85079d85fe..19c81d480d 100644
--- a/localization/i18n/es/OrcaSlicer_es.po
+++ b/localization/i18n/es/OrcaSlicer_es.po
@@ -12147,6 +12147,26 @@ msgstr ""
"Un hueco entre la línea más interna del borde de adherencia y el objeto "
"puede hacer que el borde de adherencia se retire más fácilmente"
+msgid "Brim follows compensated outline"
+msgstr "Borde de adherencia sigue el esquema compensado"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Cuando está habilitado, el borde de adherencia está alineado con la geometría del perímetro de la primera capa "
+"después de aplicar la compensación de pata de elefante.\n"
+"Esta opción está destinada a casos en los que la Compensación por pata de elefante "
+"altera significativamente la huella de la primera capa.\n"
+"\n"
+"Si su configuración actual ya funciona bien, habilitarla puede ser innecesario y "
+"puede hacer que el borde de adherencia se fusione con las capas superiores."
+
msgid "Brim ears"
msgstr "Orejas de borde"
diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po
index 1dd903bc10..5a80f34757 100644
--- a/localization/i18n/fr/OrcaSlicer_fr.po
+++ b/localization/i18n/fr/OrcaSlicer_fr.po
@@ -12298,6 +12298,26 @@ msgstr ""
"Un espace entre la ligne de bord la plus interne et l'objet peut faciliter "
"le retrait du bord"
+msgid "Brim follows compensated outline"
+msgstr "Bordure suit le contour compensé"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Lorsqu'il est activé, le bordure est aligné avec la géométrie du périmètre de la première couche "
+"après l'application de la compensation du pied d'éléphant.\n"
+"Cette option est destinée aux cas où la compensation du pied d'éléphant "
+"modifie considérablement l’empreinte de la première couche.\n"
+"\n"
+"Si votre configuration actuelle fonctionne déjà bien, son activation peut être inutile et "
+"peut provoquer la fusion du bordure avec les couches supérieures."
+
msgid "Brim ears"
msgstr "Bordures à oreilles"
diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po
index ddd70907ba..ba898f64ac 100644
--- a/localization/i18n/hu/OrcaSlicer_hu.po
+++ b/localization/i18n/hu/OrcaSlicer_hu.po
@@ -11603,6 +11603,26 @@ msgstr ""
"A legbelső peremvonal és a tárgy közötti rés, ami megkönnyítheti a perem "
"eltávolítását"
+msgid "Brim follows compensated outline"
+msgstr "A Perem a kompenzált körvonalat követi"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Ha engedélyezve van, a perem igazodik az első réteg kerületi geometriájához "
+"az elefánttalp-kompenzáció alkalmazása után.\n"
+"Ez az opció arra az esetre szolgál, amikor az elefánttalp-kompenzáció "
+"jelentősen megváltoztatja az első réteg alapterületét.\n"
+"\n"
+"Ha a jelenlegi beállítás már jól működik, előfordulhat, hogy az engedélyezése felesleges és "
+"a perem összeolvadását okozhatja a felső rétegekkel."
+
msgid "Brim ears"
msgstr "Karimás fülek"
diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po
index 43ee2d09c0..222467d02a 100644
--- a/localization/i18n/it/OrcaSlicer_it.po
+++ b/localization/i18n/it/OrcaSlicer_it.po
@@ -12234,6 +12234,26 @@ msgstr ""
"Crea uno spazio tra la linea più interna della tesa e l'oggetto per rendere "
"più facile la rimozione della tesa."
+msgid "Brim follows compensated outline"
+msgstr "Tesa segue il contorno compensato"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Quando abilitato, tesa è allineato con la geometria perimetrale del primo strato "
+"dopo l'applicazione della compensazione del piede di elefante.\n"
+"Questa opzione è prevista per i casi in cui è prevista la compensazione del piede di elefante "
+"altera significativamente l'impronta del primo strato.\n"
+"\n"
+"Se la tua configurazione attuale funziona già bene, abilitarla potrebbe non essere necessaria e "
+"può causare la fusione del tesa con gli strati superiori."
+
msgid "Brim ears"
msgstr "Tesa ad orecchio"
diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po
index 120ccae558..3258a45800 100644
--- a/localization/i18n/ja/OrcaSlicer_ja.po
+++ b/localization/i18n/ja/OrcaSlicer_ja.po
@@ -11394,6 +11394,26 @@ msgstr ""
"ブリムを取り外しやすくする為、一番内側のブリムラインをモデルと少し距離を設け"
"ます。"
+msgid "Brim follows compensated outline"
+msgstr "ブリム は補正されたアウトラインに従います"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"有効にすると、ブリム は最初の層の周囲ジオメトリと位置合わせされます。 "
+"エレファント・フット・コンペンセーション適用後。\n"
+"このオプションは、象の足の補正が必要な場合を対象としています。 "
+"最初の層のフットプリントを大幅に変更します。\n"
+"\n"
+"現在の設定がすでにうまく機能している場合は、それを有効にする必要はないかもしれません。 "
+"ブリム が上位層と融合する可能性があります。"
+
msgid "Brim ears"
msgstr ""
diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po
index fbc550e415..cf3d9dea71 100644
--- a/localization/i18n/ko/OrcaSlicer_ko.po
+++ b/localization/i18n/ko/OrcaSlicer_ko.po
@@ -11817,6 +11817,26 @@ msgstr ""
"가장 안쪽 브림 라인과 객체 사이에 간격을 주어 쉽게 브림을 제거 할 수 있게 합"
"니다"
+msgid "Brim follows compensated outline"
+msgstr "브림는 보상된 아웃라인을 따릅니다."
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"활성화되면 브림은 첫 번째 레이어 주변 형상과 정렬됩니다 "
+"코끼리 발 보정이 적용된 후.\n"
+"이 옵션은 코끼리 발 보상이 적용되는 경우를 위한 것입니다 "
+"첫 번째 레이어 공간을 크게 변경합니다.\n"
+"\n"
+"현재 설정이 이미 잘 작동하는 경우 활성화할 필요가 없으며 "
+"브림이 상위 레이어와 융합될 수 있습니다."
+
msgid "Brim ears"
msgstr "브림 귀"
diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po
index 052250e63f..ec9f6ce417 100644
--- a/localization/i18n/lt/OrcaSlicer_lt.po
+++ b/localization/i18n/lt/OrcaSlicer_lt.po
@@ -12183,6 +12183,26 @@ msgstr ""
"Sukuriamas tarpas tarp vidinės krašto linijos ir objekto, todėl galima "
"lengviau jį atskirti."
+msgid "Brim follows compensated outline"
+msgstr "Kraštas atitinka kompensuotą kontūrą"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Kai įjungta, kraštas yra sulygiuotas su pirmojo sluoksnio perimetro geometrija "
+"pritaikius dramblio pėdos kompensaciją.\n"
+"Ši parinktis skirta tais atvejais, kai kompensuojama dramblio pėda "
+"žymiai pakeičia pirmojo sluoksnio pėdsaką.\n"
+"\n"
+"Jei dabartinė sąranka jau veikia gerai, jos įjungti gali nebūti ir "
+"gali sukelti kraštas susiliejimą su viršutiniais sluoksniais."
+
msgid "Brim ears"
msgstr "Krašto \"ausys\""
diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po
index 2f1c24f60d..923ea51aec 100644
--- a/localization/i18n/nl/OrcaSlicer_nl.po
+++ b/localization/i18n/nl/OrcaSlicer_nl.po
@@ -11751,6 +11751,26 @@ msgstr ""
"Dit creëert ruimte tussen de binnenste brimlijn en het object en zorgt "
"ervoor dat het object eenvoudiger van het printbed kan worden verwijderd."
+msgid "Brim follows compensated outline"
+msgstr "Rand volgt de gecompenseerde omtrek"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Indien ingeschakeld, wordt de rand uitgelijnd met de omtrekgeometrie van de eerste laag "
+"nadat olifantenvoetcompensatie is toegepast.\n"
+"Deze optie is bedoeld voor gevallen waarin sprake is van olifantenvoetcompensatie "
+"verandert de voetafdruk van de eerste laag aanzienlijk.\n"
+"\n"
+"Als uw huidige configuratie al goed werkt, kan het inschakelen hiervan niet nodig zijn "
+"kan ervoor zorgen dat de rand samensmelt met de bovenste lagen."
+
msgid "Brim ears"
msgstr "Rand oren"
diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po
index 81afc09e9b..5c2896d962 100644
--- a/localization/i18n/pl/OrcaSlicer_pl.po
+++ b/localization/i18n/pl/OrcaSlicer_pl.po
@@ -12130,6 +12130,26 @@ msgstr ""
"Szczelina między najbardziej wewnętrzną linią brimu a obiektem może ułatwić "
"usunięcie brimu"
+msgid "Brim follows compensated outline"
+msgstr "Brim podąża za skompensowanym konturem"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Po włączeniu brim jest wyrównany z geometrią obwodu pierwszej warstwy "
+"po zastosowaniu Kompensacji Stopy Słonia.\n"
+"Ta opcja jest przeznaczona dla przypadków, w których występuje kompensacja stopy słonia "
+"znacząco zmienia ślad pierwszej warstwy.\n"
+"\n"
+"Jeśli Twoja bieżąca konfiguracja już działa dobrze, włączenie jej może być niepotrzebne i "
+"może spowodować stopienie brim z górnymi warstwami."
+
msgid "Brim ears"
msgstr "Uszy brim"
diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
index 73fcdb50ea..cffab32de6 100644
--- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
+++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
@@ -12555,6 +12555,26 @@ msgstr ""
"Um espaço entre a linha mais interna da borda e o objeto pode facilitar a "
"remoção da borda."
+msgid "Brim follows compensated outline"
+msgstr "Borda segue contorno compensado"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Quando ativado, o borda fica alinhado com a geometria do perímetro da primeira camada "
+"após a aplicação da Compensação da Pé de Elefante.\n"
+"Esta opção destina-se aos casos em que a Compensação da Pé de Elefante "
+"altera significativamente a pegada da primeira camada.\n"
+"\n"
+"Se a sua configuração atual já funciona bem, ativá-la pode ser desnecessário e "
+"pode fazer com que o borda se funda com as camadas superiores."
+
msgid "Brim ears"
msgstr "Orelhas da borda"
diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po
index d9ff700c16..4364ce8306 100644
--- a/localization/i18n/ru/OrcaSlicer_ru.po
+++ b/localization/i18n/ru/OrcaSlicer_ru.po
@@ -12291,6 +12291,26 @@ msgid ""
"easily."
msgstr "Смещение каймы от печатаемой модели, может облегчить её удаление."
+msgid "Brim follows compensated outline"
+msgstr "Кайма соответствует компенсированному контуру"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Если этот параметр включен, кайма выравнивается по геометрии периметра первого слоя "
+"после применения компенсации «слоновьей стопы».\n"
+"Эта опция предназначена для случаев, когда «Компенсация слоновой стопы» "
+"существенно изменяет след первого слоя.\n"
+"\n"
+"Если ваша текущая настройка уже работает хорошо, ее включение может быть ненужным и "
+"может привести к слиянию кайма с верхними слоями."
+
msgid "Brim ears"
msgstr "Ушки каймы"
diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po
index 04c2d4d565..ab1944d79e 100644
--- a/localization/i18n/sv/OrcaSlicer_sv.po
+++ b/localization/i18n/sv/OrcaSlicer_sv.po
@@ -11574,6 +11574,26 @@ msgstr ""
"Mellanrum mellan innersta brim linjen och objektet kan underlätta vid "
"borttagande av brim"
+msgid "Brim follows compensated outline"
+msgstr "Brim följer kompenserad disposition"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"När den är aktiverad, är brim justerad med det första lagrets omkretsgeometri "
+"efter att elefantfotskompensation tillämpas.\n"
+"Detta alternativ är avsett för fall där elefantfotskompensation "
+"förändrar det första skiktets fotavtryck avsevärt.\n"
+"\n"
+"Om din nuvarande inställning redan fungerar bra kan det vara onödigt att aktivera det och "
+"kan få brim att smälta samman med de övre lagren."
+
msgid "Brim ears"
msgstr "Brätte öron"
diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po
index a817dd919e..b10eacfc6e 100644
--- a/localization/i18n/tr/OrcaSlicer_tr.po
+++ b/localization/i18n/tr/OrcaSlicer_tr.po
@@ -12097,6 +12097,26 @@ msgstr ""
"En içteki kenar çizgisi ile nesne arasındaki boşluk, kenarlığın daha kolay "
"çıkarılmasını sağlayabilir."
+msgid "Brim follows compensated outline"
+msgstr "Kenar telafi edilen taslağı takip ediyor"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Etkinleştirildiğinde, kenar birinci katmanın çevre geometrisiyle hizalanır "
+"Fil Ayağı Telafisi uygulandıktan sonra.\n"
+"Bu seçenek Fil Ayağı Telafisinin geçerli olmadığı durumlar için tasarlanmıştır "
+"ilk katmanın ayak izini önemli ölçüde değiştirir.\n"
+"\n"
+"Mevcut kurulumunuz zaten iyi çalışıyorsa, bunu etkinleştirmek gereksiz olabilir ve "
+"kenar'in üst katmanlarla kaynaşmasına neden olabilir."
+
msgid "Brim ears"
msgstr "Kenar kulakları"
diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po
index 05482e66d1..296efbe5bd 100644
--- a/localization/i18n/uk/OrcaSlicer_uk.po
+++ b/localization/i18n/uk/OrcaSlicer_uk.po
@@ -12138,6 +12138,26 @@ msgstr ""
"Зазор між першою внутрішньою лінією кайми та об'єктом може сприяти легшому "
"відокремленню кайми"
+msgid "Brim follows compensated outline"
+msgstr "Кайма має компенсований контур"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Якщо ввімкнено, кайма вирівнюється з геометрією периметра першого рівня "
+"після застосування Elephant Foot Compensation.\n"
+"Ця опція призначена для випадків компенсації слонячої стопи "
+"значно змінює поверхню першого шару.\n"
+"\n"
+"Якщо ваші поточні налаштування вже працюють добре, увімкнення їх може бути непотрібним "
+"може призвести до злиття кайма з верхніми шарами."
+
msgid "Brim ears"
msgstr "Вушка кайми"
diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po
index f14576ceed..5017bc246f 100644
--- a/localization/i18n/vi/OrcaSlicer_vi.po
+++ b/localization/i18n/vi/OrcaSlicer_vi.po
@@ -11926,6 +11926,26 @@ msgstr ""
"Khoảng cách giữa đường brim trong cùng và đối tượng có thể làm cho brim dễ "
"dàng tháo hơn."
+msgid "Brim follows compensated outline"
+msgstr "Brim tuân theo phác thảo được bù đắp"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"Khi được bật, brim sẽ được căn chỉnh theo hình học chu vi lớp đầu tiên "
+"sau khi áp dụng Bồi thường bàn chân voi.\n"
+"Tùy chọn này dành cho các trường hợp Bồi thường chân voi "
+"làm thay đổi đáng kể dấu chân lớp đầu tiên.\n"
+"\n"
+"Nếu thiết lập hiện tại của bạn đã hoạt động tốt, việc bật nó có thể không cần thiết và "
+"có thể khiến brim kết hợp với các lớp trên."
+
msgid "Brim ears"
msgstr "Tai brim"
diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
index 952bd49555..8cad4e58a5 100644
--- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
+++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
@@ -2490,7 +2490,7 @@ msgid "Plate"
msgstr "盘"
msgid "Brim"
-msgstr "Brim"
+msgstr "边缘"
msgid "Object/Part Setting"
msgstr "对象/零件设置"
@@ -11493,6 +11493,26 @@ msgid ""
"easily."
msgstr "在brim和模型之间设置间隙,能够让brim更容易剥离"
+msgid "Brim follows compensated outline"
+msgstr "边缘 遵循补偿轮廓"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"启用后,边缘 与第一层周边几何体对齐 "
+"应用象脚补偿后。\n"
+"此选项适用于象脚补偿的情况 "
+"显着改变第一层足迹。\n"
+"\n"
+"如果您当前的设置已经运行良好,则可能没有必要启用它,并且 "
+"可以导致 边缘 与上层融合。"
+
msgid "Brim ears"
msgstr "圆盘"
diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
index 01c3669856..51d89cca21 100644
--- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
+++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
@@ -2493,7 +2493,7 @@ msgid "Plate"
msgstr "列印板"
msgid "Brim"
-msgstr "Brim"
+msgstr "邊緣"
msgid "Object/Part Setting"
msgstr "物件/零件 設定"
@@ -11560,6 +11560,26 @@ msgid ""
"easily."
msgstr "在 Brim 和模型之間設定間隙,能夠讓 Brim 更容易拆除"
+msgid "Brim follows compensated outline"
+msgstr "邊緣 遵循補償輪廓"
+
+msgid ""
+"When enabled, the brim is aligned with the first-layer perimeter geometry "
+"after Elephant Foot Compensation is applied.\n"
+"This option is intended for cases where Elephant Foot Compensation "
+"significantly alters the first-layer footprint.\n"
+"\n"
+"If your current setup already works well, enabling it may be unnecessary and "
+"can cause the brim to fuse with upper layers."
+msgstr ""
+"啟用後,邊緣 與第一層周邊幾何體對齊 "
+"應用像腳補償後。\n"
+"此選項適用於像腳補償的情況 "
+"顯著改變第一層足跡。\n"
+"\n"
+"如果您當前的設置已經運行良好,則可能沒有必要啟用它,並且 "
+"可以導致 邊緣 與上層融合。"
+
msgid "Brim ears"
msgstr "耳狀 Brim"
diff --git a/resources/images/axis_toggle.svg b/resources/images/axis_toggle.svg
deleted file mode 100644
index 679c34e5ca..0000000000
--- a/resources/images/axis_toggle.svg
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
diff --git a/resources/images/axis_toggle_dark.svg b/resources/images/axis_toggle_dark.svg
deleted file mode 100644
index 08c52a8398..0000000000
--- a/resources/images/axis_toggle_dark.svg
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
diff --git a/resources/images/axis_toggle_hover.svg b/resources/images/axis_toggle_hover.svg
deleted file mode 100644
index 1d462ffb1d..0000000000
--- a/resources/images/axis_toggle_hover.svg
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
diff --git a/resources/images/axis_toggle_hover_dark.svg b/resources/images/axis_toggle_hover_dark.svg
deleted file mode 100644
index 14f9bd2767..0000000000
--- a/resources/images/axis_toggle_hover_dark.svg
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
diff --git a/resources/images/canvas_menu.svg b/resources/images/canvas_menu.svg
new file mode 100644
index 0000000000..b94a4952f0
--- /dev/null
+++ b/resources/images/canvas_menu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_menu_dark.svg b/resources/images/canvas_menu_dark.svg
new file mode 100644
index 0000000000..6578d79a9c
--- /dev/null
+++ b/resources/images/canvas_menu_dark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_menu_dark_hover.svg b/resources/images/canvas_menu_dark_hover.svg
new file mode 100644
index 0000000000..e71a5c9787
--- /dev/null
+++ b/resources/images/canvas_menu_dark_hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_menu_hover.svg b/resources/images/canvas_menu_hover.svg
new file mode 100644
index 0000000000..83fbddee17
--- /dev/null
+++ b/resources/images/canvas_menu_hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_zoom.svg b/resources/images/canvas_zoom.svg
new file mode 100644
index 0000000000..5448cd7cee
--- /dev/null
+++ b/resources/images/canvas_zoom.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_zoom_dark.svg b/resources/images/canvas_zoom_dark.svg
new file mode 100644
index 0000000000..9e598f8cba
--- /dev/null
+++ b/resources/images/canvas_zoom_dark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_zoom_dark_hover.svg b/resources/images/canvas_zoom_dark_hover.svg
new file mode 100644
index 0000000000..6d7e4e5fcb
--- /dev/null
+++ b/resources/images/canvas_zoom_dark_hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/images/canvas_zoom_hover.svg b/resources/images/canvas_zoom_hover.svg
new file mode 100644
index 0000000000..53f272d28d
--- /dev/null
+++ b/resources/images/canvas_zoom_hover.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/profiles/BBL/Bambu Lab P2S_cover.png b/resources/profiles/BBL/Bambu Lab P2S_cover.png
index febba125ee..30982b863a 100644
Binary files a/resources/profiles/BBL/Bambu Lab P2S_cover.png and b/resources/profiles/BBL/Bambu Lab P2S_cover.png differ
diff --git a/resources/profiles/BBL/machine/fdm_machine_common.json b/resources/profiles/BBL/machine/fdm_machine_common.json
index 0073ac6a8a..566d3960ed 100644
--- a/resources/profiles/BBL/machine/fdm_machine_common.json
+++ b/resources/profiles/BBL/machine/fdm_machine_common.json
@@ -136,7 +136,7 @@
"60"
],
"scan_first_layer": "0",
- "enable_power_loss_recovery": "1",
+ "enable_power_loss_recovery": "printer_configuration",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"support_air_filtration": "0",
diff --git a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3 Plus.json b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3 Plus.json
index b7c03f3f96..b7605cb457 100644
--- a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3 Plus.json
+++ b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3 Plus.json
@@ -11,6 +11,9 @@
"nozzle_diameter": [
"0.4"
],
+ "nozzle_volume": [
+ "156"
+ ],
"retract_before_wipe": [
"0%"
],
@@ -132,7 +135,7 @@
"0"
],
"parking_pos_retraction": [
- "25"
+ "0"
],
"retract_when_changing_layer": [
"0"
@@ -141,7 +144,10 @@
"0"
],
"high_current_on_filament_swap": [
- "1"
+ "0"
+ ],
+ "enable_filament_ramming": [
+ "0"
],
"z_hop_types": "Spiral Lift"
-}
\ No newline at end of file
+}
diff --git a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3.json b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3.json
index 7dabbd7f08..391b37301d 100644
--- a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3.json
+++ b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle - Ender-3 V3.json
@@ -11,6 +11,9 @@
"nozzle_diameter": [
"0.4"
],
+ "nozzle_volume": [
+ "156"
+ ],
"retract_before_wipe": [
"0%"
],
@@ -132,7 +135,7 @@
"0"
],
"parking_pos_retraction": [
- "25"
+ "0"
],
"retract_when_changing_layer": [
"0"
@@ -141,7 +144,10 @@
"0"
],
"high_current_on_filament_swap": [
- "1"
+ "0"
+ ],
+ "enable_filament_ramming": [
+ "0"
],
"z_hop_types": "Spiral Lift"
-}
\ No newline at end of file
+}
diff --git a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle fast.json b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle fast.json
index 518acb39cd..b33d7e5a5c 100644
--- a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle fast.json
+++ b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle fast.json
@@ -11,6 +11,9 @@
"nozzle_diameter": [
"0.4"
],
+ "nozzle_volume": [
+ "156"
+ ],
"retract_before_wipe": [
"0%"
],
@@ -132,7 +135,7 @@
"0"
],
"parking_pos_retraction": [
- "25"
+ "0"
],
"retract_when_changing_layer": [
"0"
@@ -141,7 +144,10 @@
"0"
],
"high_current_on_filament_swap": [
- "1"
+ "0"
+ ],
+ "enable_filament_ramming": [
+ "0"
],
"z_hop_types": "Spiral Lift"
-}
\ No newline at end of file
+}
diff --git a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle.json b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle.json
index 8a49ec2f87..3ee7b4e79b 100644
--- a/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle.json
+++ b/resources/profiles/Co Print/machine/Co Print ChromaSet 0.4 nozzle.json
@@ -10,6 +10,9 @@
"printer_variant": "0.4",
"nozzle_diameter": [
"0.4"
+ ],
+ "nozzle_volume": [
+ "156"
],
"retract_before_wipe": [
"0%"
@@ -132,7 +135,7 @@
"0"
],
"parking_pos_retraction": [
- "25"
+ "0"
],
"retract_when_changing_layer": [
"0"
@@ -141,7 +144,10 @@
"0"
],
"high_current_on_filament_swap": [
- "1"
+ "0"
+ ],
+ "enable_filament_ramming": [
+ "0"
],
"z_hop_types": "Spiral Lift"
-}
\ No newline at end of file
+}
diff --git a/resources/profiles/Geeetech/Geeetech A10 M_cover.png b/resources/profiles/Geeetech/Geeetech A10 M_cover.png
index 537e84e105..c33288671f 100644
Binary files a/resources/profiles/Geeetech/Geeetech A10 M_cover.png and b/resources/profiles/Geeetech/Geeetech A10 M_cover.png differ
diff --git a/resources/profiles/Ginger Additive/ginger G1_cover.png b/resources/profiles/Ginger Additive/Ginger G1_cover.png
similarity index 100%
rename from resources/profiles/Ginger Additive/ginger G1_cover.png
rename to resources/profiles/Ginger Additive/Ginger G1_cover.png
diff --git a/resources/profiles/M3D/M3D Enabler D8500 MM Model_cover.png b/resources/profiles/M3D/M3D Enabler D8500 MM Model_cover.png
index eb067195cf..50020d51b7 100644
Binary files a/resources/profiles/M3D/M3D Enabler D8500 MM Model_cover.png and b/resources/profiles/M3D/M3D Enabler D8500 MM Model_cover.png differ
diff --git a/resources/profiles/MagicMaker/MM hj sk_cover.png b/resources/profiles/MagicMaker/MM hj SK_cover.png
similarity index 100%
rename from resources/profiles/MagicMaker/MM hj sk_cover.png
rename to resources/profiles/MagicMaker/MM hj SK_cover.png
diff --git a/resources/profiles/OpenEYE/machine/OpenEYE Peacock V2 0.4 nozzle.json b/resources/profiles/OpenEYE/machine/OpenEYE Peacock V2 0.4 nozzle.json
index 4528b72fe1..2912a51b45 100644
--- a/resources/profiles/OpenEYE/machine/OpenEYE Peacock V2 0.4 nozzle.json
+++ b/resources/profiles/OpenEYE/machine/OpenEYE Peacock V2 0.4 nozzle.json
@@ -4,6 +4,9 @@
"from": "system",
"inherits": "fdm_openeye_common",
"instantiation": "true",
+ "adaptive_bed_mesh_margin": "10",
+ "bed_mesh_max": "211,211",
+ "bed_mesh_min": "1.5,7",
"layer_change_gcode": "SET_PRINT_STATS_INFO CURRENT_LAYER={layer_num + 1}\n_MMU_UPDATE_HEIGHT",
"machine_end_gcode": "MMU_END\nEND_PRINT",
"machine_load_filament_time": "30",
@@ -24,8 +27,8 @@
"30"
],
"machine_pause_gcode": "PAUSE",
- "machine_start_gcode": "SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\nMMU_START_SETUP INITIAL_TOOL={initial_tool} TOTAL_TOOLCHANGES=!total_toolchanges! REFERENCED_TOOLS=!referenced_tools! TOOL_COLORS=!colors! TOOL_TEMPS=!temperatures! TOOL_MATERIALS=!materials! FILAMENT_NAMES=!filament_names! PURGE_VOLUMES=!purge_volumes!\nMMU_START_CHECK\nSTART_PRINT BED_TEMP=[bed_temperature_initial_layer] EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TYPE=\"{curr_bed_type}\"\n; Enter YOUR exist start_print macro call here (minus purging logic because tool may not be loaded yet)\nMMU_START_LOAD_INITIAL_TOOL\n; Optionally add YOUR additional start logic (like purging) here to run just prior to start\nSTART_PRINT_SECONDARY\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} ; For pause at layer functionality and better print stats",
- "machine_unload_filament_time": "30",
+ "machine_start_gcode": "SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\nMMU_START_SETUP INITIAL_TOOL={initial_tool} TOTAL_TOOLCHANGES=!total_toolchanges! REFERENCED_TOOLS=!referenced_tools! TOOL_COLORS=!colors! TOOL_TEMPS=!temperatures! TOOL_MATERIALS=!materials! FILAMENT_NAMES=!filament_names! PURGE_VOLUMES=!purge_volumes!\nMMU_START_CHECK\nSTART_PRINT BED_TEMP=[bed_temperature_initial_layer] EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TYPE=\"{curr_bed_type}\" MESH_MIN={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} MESH_MAX={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE_MARGIN={adaptive_bed_mesh_margin}\n; Enter YOUR exist start_print macro call here (minus purging logic because tool may not be loaded yet)\nMMU_START_LOAD_INITIAL_TOOL\n; Optionally add YOUR additional start logic (like purging) here to run just prior to start\nSTART_PRINT_SECONDARY\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} ; For pause at layer functionality and better print stats",
+ "machine_unload_filament_time": "30",
"name": "OpenEYE Peacock V2 0.4 nozzle",
"nozzle_diameter": [
"0.4"
@@ -45,4 +48,4 @@
],
"setting_id": "GM001",
"type": "machine"
-}
\ No newline at end of file
+}
diff --git a/resources/profiles/OpenEYE/machine/fdm_openeye_common.json b/resources/profiles/OpenEYE/machine/fdm_openeye_common.json
index 130e3b189f..a428532958 100644
--- a/resources/profiles/OpenEYE/machine/fdm_openeye_common.json
+++ b/resources/profiles/OpenEYE/machine/fdm_openeye_common.json
@@ -124,8 +124,8 @@
"0"
],
"machine_pause_gcode": "PAUSE",
- "machine_start_gcode": "SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\nMMU_START_SETUP INITIAL_TOOL={initial_tool} TOTAL_TOOLCHANGES=!total_toolchanges! REFERENCED_TOOLS=!referenced_tools! TOOL_COLORS=!colors! TOOL_TEMPS=!temperatures! TOOL_MATERIALS=!materials! FILAMENT_NAMES=!filament_names! PURGE_VOLUMES=!purge_volumes!\nMMU_START_CHECK\nSTART_PRINT BED_TEMP=[bed_temperature_initial_layer] EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TYPE=\"{curr_bed_type}\"\n; Enter YOUR exist start_print macro call here (minus purging logic because tool may not be loaded yet)\nMMU_START_LOAD_INITIAL_TOOL\n; Optionally add YOUR additional start logic (like purging) here to run just prior to start\nSTART_PRINT_SECONDARY\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} ; For pause at layer functionality and better print stats",
- "machine_tool_change_time": "0",
+ "machine_start_gcode": "SET_PRINT_STATS_INFO TOTAL_LAYER=[total_layer_count]\nMMU_START_SETUP INITIAL_TOOL={initial_tool} TOTAL_TOOLCHANGES=!total_toolchanges! REFERENCED_TOOLS=!referenced_tools! TOOL_COLORS=!colors! TOOL_TEMPS=!temperatures! TOOL_MATERIALS=!materials! FILAMENT_NAMES=!filament_names! PURGE_VOLUMES=!purge_volumes!\nMMU_START_CHECK\nSTART_PRINT BED_TEMP=[bed_temperature_initial_layer] EXTRUDER_TEMP=[nozzle_temperature_initial_layer] BED_TYPE=\"{curr_bed_type}\" MESH_MIN={adaptive_bed_mesh_min[0]},{adaptive_bed_mesh_min[1]} MESH_MAX={adaptive_bed_mesh_max[0]},{adaptive_bed_mesh_max[1]} ALGORITHM=[bed_mesh_algo] PROBE_COUNT={bed_mesh_probe_count[0]},{bed_mesh_probe_count[1]} ADAPTIVE_MARGIN={adaptive_bed_mesh_margin}\n; Enter YOUR exist start_print macro call here (minus purging logic because tool may not be loaded yet)\nMMU_START_LOAD_INITIAL_TOOL\n; Optionally add YOUR additional start logic (like purging) here to run just prior to start\nSTART_PRINT_SECONDARY\nSET_PRINT_STATS_INFO TOTAL_LAYER={total_layer_count} ; For pause at layer functionality and better print stats",
+ "machine_tool_change_time": "0",
"machine_unload_filament_time": "0",
"manual_filament_change": "0",
"max_layer_height": [
diff --git a/resources/profiles/WonderMaker/WonderMaker ZR ULtra S_cover.png b/resources/profiles/WonderMaker/WonderMaker ZR Ultra S_cover.png
similarity index 100%
rename from resources/profiles/WonderMaker/WonderMaker ZR ULtra S_cover.png
rename to resources/profiles/WonderMaker/WonderMaker ZR Ultra S_cover.png
diff --git a/resources/profiles/iQ.json b/resources/profiles/iQ.json
index 17d813bac9..c904ad1a1f 100644
--- a/resources/profiles/iQ.json
+++ b/resources/profiles/iQ.json
@@ -80,6 +80,10 @@
{
"name": "0.20mm Standard @iQ TiQ2 P2 - PACF Pro Fiberthree + VXL90 Xioneer (0.4 Nozzle)",
"sub_path": "process/0.20mm Standard @iQ TiQ2 P2 - PACF Pro Fiberthree + VXL90 Xioneer (0.4 Nozzle).json"
+ },
+ {
+ "name": "0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle)",
+ "sub_path": "process/0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle).json"
}
],
"filament_list": [
@@ -106,6 +110,10 @@
{
"name": "VXL90 TiQ2 P2 @iQ TiQ2 0.4 Nozzle",
"sub_path": "filament/VXL90 TiQ2 P2 @iQ TiQ2 0.4 Nozzle.json"
+ },
+ {
+ "name": "Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle",
+ "sub_path": "filament/Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle.json"
}
]
}
diff --git a/resources/profiles/iQ/filament/Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle.json b/resources/profiles/iQ/filament/Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle.json
new file mode 100644
index 0000000000..20146fa309
--- /dev/null
+++ b/resources/profiles/iQ/filament/Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle.json
@@ -0,0 +1,303 @@
+{
+ "type": "filament",
+ "name": "Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle",
+ "inherits": "fdm_filament_common",
+ "from": "system",
+ "setting_id": "IQS1",
+ "filament_id": "IQM1",
+ "instantiation": "true",
+ "compatible_prints": [
+ "0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle)"
+ ],
+ "filament_cost": [
+ "70.58"
+ ],
+ "filament_density": [
+ "1.09"
+ ],
+ "filament_end_gcode": [
+ "; filament end gcode\n{if current_extruder==0}\nG1 Z{layer_z+2} F900 ; safe distance for T0 while tool change\nG1 X-17 Y1 F9000\nG1 X-17 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\n{endif}\n\n{if current_extruder==1}\n{if current_extruder==0}T1{endif}\nG1 X-23 Y3 F9000\nG1 Y45 F9000\nG1 Y3 F9000\nG1 Y45 F9000\n{endif}\n"
+ ],
+ "filament_flow_ratio": [
+ "0.926"
+ ],
+ "filament_settings_id": [
+ "Grauts HPP4GF25 P1 @iQ TiQ2 0.4 Nozzle"
+ ],
+ "filament_shrink": [
+ "98.994%"
+ ],
+ "filament_shrinkage_compensation_z": [
+ "99%"
+ ],
+ "filament_start_gcode": [
+ "; Filament gcode\n{if current_extruder==0}\nG1 X-17 Y1 F9000\nG1 Y45 F9000\nG1 Y1 F9000\nG1 Y45 F9000\n{if layer_z==0}G1 Z{first_layer_height + 2.0}{endif}\n{if layer_z==0}G1 X[first_layer_print_min_0] Y[first_layer_print_min_1]{endif}\n{if layer_z==0}G1 Z{layer_z}{endif}\n{endif}\n\n{if current_extruder==1}\nG1 X-23 Y3 F9000\nG1 Y45 F9000\nG1 Y3 F9000\nG1 Y45 F9000\n{endif}\n"
+ ],
+ "filament_type": [
+ "HPP4GF25"
+ ],
+ "hot_plate_temp": [
+ "110"
+ ],
+ "hot_plate_temp_initial_layer": [
+ "110"
+ ],
+ "idle_temperature": [
+ "180"
+ ],
+ "is_custom_defined": "0",
+ "nozzle_temperature": [
+ "220"
+ ],
+ "nozzle_temperature_initial_layer": [
+ "220"
+ ],
+ "nozzle_temperature_range_high": [
+ "280"
+ ],
+ "nozzle_temperature_range_low": [
+ "220"
+ ],
+ "temperature_vitrification": [
+ "127"
+ ],
+ "version": "2.3.1.10",
+
+
+ "activate_air_filtration": [
+ "0"
+ ],
+ "activate_chamber_temp_control": [
+ "0"
+ ],
+ "adaptive_pressure_advance": [
+ "0"
+ ],
+ "adaptive_pressure_advance_bridges": [
+ "0"
+ ],
+ "adaptive_pressure_advance_model": [
+ "0,0,0\n0,0,0"
+ ],
+ "adaptive_pressure_advance_overhangs": [
+ "0"
+ ],
+ "additional_cooling_fan_speed": [
+ "0"
+ ],
+ "chamber_temperature": [
+ "0"
+ ],
+ "close_fan_the_first_x_layers": [
+ "3"
+ ],
+ "compatible_printers": [
+ "iQ TiQ2 0.4 Nozzle"
+ ],
+ "compatible_printers_condition": "",
+ "compatible_prints_condition": "",
+ "complete_print_exhaust_fan_speed": [
+ "80"
+ ],
+ "cool_plate_temp": [
+ "105"
+ ],
+ "cool_plate_temp_initial_layer": [
+ "105"
+ ],
+ "default_filament_colour": [
+ "#000000"
+ ],
+ "dont_slow_down_outer_wall": [
+ "0"
+ ],
+ "during_print_exhaust_fan_speed": [
+ "60"
+ ],
+ "enable_overhang_bridge_fan": [
+ "1"
+ ],
+ "enable_pressure_advance": [
+ "0"
+ ],
+ "eng_plate_temp": [
+ "105"
+ ],
+ "eng_plate_temp_initial_layer": [
+ "105"
+ ],
+ "fan_cooling_layer_time": [
+ "30"
+ ],
+ "fan_max_speed": [
+ "80"
+ ],
+ "fan_min_speed": [
+ "10"
+ ],
+ "filament_cooling_final_speed": [
+ "3.5"
+ ],
+ "filament_cooling_initial_speed": [
+ "10"
+ ],
+ "filament_cooling_moves": [
+ "2"
+ ],
+ "filament_deretraction_speed": [
+ "nil"
+ ],
+ "filament_diameter": [
+ "1.75"
+ ],
+ "filament_is_support": [
+ "0"
+ ],
+ "filament_loading_speed": [
+ "10"
+ ],
+ "filament_loading_speed_start": [
+ "50"
+ ],
+ "filament_long_retractions_when_cut": [
+ "nil"
+ ],
+ "filament_max_volumetric_speed": [
+ "12"
+ ],
+ "filament_minimal_purge_on_wipe_tower": [
+ "15"
+ ],
+ "filament_multitool_ramming": [
+ "1"
+ ],
+ "filament_multitool_ramming_flow": [
+ "40"
+ ],
+ "filament_multitool_ramming_volume": [
+ "10"
+ ],
+ "filament_notes": [
+ ""
+ ],
+ "filament_ramming_parameters": [
+ "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
+ ],
+ "filament_retract_before_wipe": [
+ "nil"
+ ],
+ "filament_retract_lift_above": [
+ "nil"
+ ],
+ "filament_retract_lift_below": [
+ "nil"
+ ],
+ "filament_retract_lift_enforce": [
+ "nil"
+ ],
+ "filament_retract_restart_extra": [
+ "nil"
+ ],
+ "filament_retract_when_changing_layer": [
+ "nil"
+ ],
+ "filament_retraction_distances_when_cut": [
+ "nil"
+ ],
+ "filament_retraction_length": [
+ "4"
+ ],
+ "filament_retraction_minimum_travel": [
+ "nil"
+ ],
+ "filament_retraction_speed": [
+ "40"
+ ],
+ "filament_soluble": [
+ "0"
+ ],
+ "filament_stamping_distance": [
+ "45"
+ ],
+ "filament_stamping_loading_speed": [
+ "29"
+ ],
+ "filament_toolchange_delay": [
+ "0"
+ ],
+ "filament_unloading_speed": [
+ "100"
+ ],
+ "filament_unloading_speed_start": [
+ "100"
+ ],
+ "filament_vendor": [
+ "iQ Materials"
+ ],
+ "filament_wipe": [
+ "nil"
+ ],
+ "filament_wipe_distance": [
+ "nil"
+ ],
+ "filament_z_hop": [
+ "nil"
+ ],
+ "filament_z_hop_types": [
+ "nil"
+ ],
+ "full_fan_speed_layer": [
+ "0"
+ ],
+ "internal_bridge_fan_speed": [
+ "-1"
+ ],
+ "overhang_fan_speed": [
+ "80"
+ ],
+ "overhang_fan_threshold": [
+ "25%"
+ ],
+ "pellet_flow_coefficient": [
+ "0.4157"
+ ],
+ "pressure_advance": [
+ "0.02"
+ ],
+ "reduce_fan_stop_start_freq": [
+ "1"
+ ],
+ "required_nozzle_HRC": [
+ "0"
+ ],
+ "slow_down_for_layer_cooling": [
+ "1"
+ ],
+ "slow_down_layer_time": [
+ "3"
+ ],
+ "slow_down_min_speed": [
+ "10"
+ ],
+ "supertack_plate_temp": [
+ "35"
+ ],
+ "supertack_plate_temp_initial_layer": [
+ "35"
+ ],
+ "support_material_interface_fan_speed": [
+ "-1"
+ ],
+ "textured_cool_plate_temp": [
+ "40"
+ ],
+ "textured_cool_plate_temp_initial_layer": [
+ "40"
+ ],
+ "textured_plate_temp": [
+ "105"
+ ],
+ "textured_plate_temp_initial_layer": [
+ "105"
+ ]
+}
diff --git a/resources/profiles/iQ/filament/Polymaker PETG Polymax black P1 @iQ TiQ2 0.4 Nozzle.json b/resources/profiles/iQ/filament/Polymaker PETG Polymax black P1 @iQ TiQ2 0.4 Nozzle.json
index 457b37f8cd..054350acfc 100644
--- a/resources/profiles/iQ/filament/Polymaker PETG Polymax black P1 @iQ TiQ2 0.4 Nozzle.json
+++ b/resources/profiles/iQ/filament/Polymaker PETG Polymax black P1 @iQ TiQ2 0.4 Nozzle.json
@@ -30,9 +30,6 @@
"chamber_temperature": [
"0"
],
- "close_fan_the_first_x_layers": [
- "3"
- ],
"compatible_printers": [
"iQ TiQ2 0.4 Nozzle"
],
@@ -89,6 +86,9 @@
"filament_cooling_moves": [
"4"
],
+ "close_fan_the_first_x_layers": [
+ "1000"
+ ],
"filament_cost": [
"29.99"
],
@@ -162,7 +162,7 @@
"nil"
],
"filament_retraction_length": [
- "0.2"
+ "0.4"
],
"filament_retraction_minimum_travel": [
"nil"
@@ -222,7 +222,7 @@
"0"
],
"hot_plate_temp": [
- "80"
+ "70"
],
"hot_plate_temp_initial_layer": [
"80"
@@ -237,7 +237,7 @@
"-1"
],
"nozzle_temperature": [
- "250"
+ "240"
],
"nozzle_temperature_initial_layer": [
"250"
@@ -261,7 +261,7 @@
"0.02"
],
"reduce_fan_stop_start_freq": [
- "1"
+ "0"
],
"required_nozzle_HRC": [
"3"
diff --git a/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle).json b/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle).json
new file mode 100644
index 0000000000..0a542fe938
--- /dev/null
+++ b/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle).json
@@ -0,0 +1,70 @@
+{
+ "type": "process",
+ "inherits": "fdm_process_tiq_common",
+ "from": "system",
+ "instantiation": "true",
+ "default_acceleration": "1500",
+ "enable_extra_bridge_layer": "apply_to_all",
+ "enable_prime_tower": "0",
+ "initial_layer_infill_speed": "100",
+ "inner_wall_acceleration": "1500",
+ "inner_wall_speed": "100",
+ "is_custom_defined": "0",
+ "name": "0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle)",
+ "notes": "Pre-Select: FBA Time Delay: 0 EPC Factor: 0\n\nDeutsch P1 HPP4GF25\n\n1. Überprüfen Sie, dass sich das Grauts HPP4GF25 im linken Extruder befindet. Halten Sie das Filament trocken! Detailierte Trocknungsanleitung, siehe unten.\n\n2. Überprüfen Sie, dass sich eine 0,4 mm Wolfram-Kupfer Düse im linken Extruder befindet.\n\n3. Verwenden Sie Magigoo Kleber für PPGF auf der PET-Folie, um eine bessere Haftung zu gewährleisten, im Singledruck in der Regel auf PET-Folie nicht erforderlich.\n\n4. Reinigen Sie ggf. die Düse mit einer Messing-Drahtbürste.\nNun sind sie bereit, um Ihren Druck zu starten.\n\n\nTipp: Am besten lässt sich das Bauteil bei einer Druckplattentemperatur von 80°C entfernen, da dann der Kleber weich wird.\n\n\nEnglish P1 HPP4GF25\n\n1. Check Left extruder filament: Grauts HPP4GF25 - Keep the filament dry!! Detailed drying instruction below.\n\n2. Check left extruder nozzle: 0.4mm Wolfram\n\n3. Check bed: PET with Magigoo glue for PPGF\n\n4. Check nozzle: Clean it with brush\n\nWELLDONE! YOU ARE READY NOW TO START YOUR PRINT JOB!\n\n\nTip: The component is best removed at a printing plate temperature of 80°C, as this softens the adhesive.",
+ "outer_wall_acceleration": "1500",
+ "outer_wall_speed": "80",
+ "print_settings_id": "0.20mm Standard @iQ TiQ2 P1 - HPP4GF25 Grauts (0.4 Nozzle)",
+ "sparse_infill_speed": "100",
+ "support_angle": "0",
+ "support_base_pattern": "default",
+ "support_interface_bottom_layers": "0",
+ "support_interface_top_layers": "3",
+ "support_object_first_layer_gap": "0.3",
+ "support_object_xy_distance": "0.35",
+ "support_on_build_plate_only": "0",
+ "support_speed": "100",
+ "support_style": "snug",
+ "support_top_z_distance": "0.2",
+ "support_type": "normal(auto)",
+ "top_surface_acceleration": "1500",
+ "top_surface_speed": "80",
+ "travel_acceleration": "1500",
+ "version": "2.3.1.10",
+
+ "bridge_flow": "1.07",
+ "bridge_speed": "25",
+ "brim_type": "no_brim",
+ "enable_support": "1",
+ "exclude_object": "0",
+ "gcode_label_objects": "0",
+ "compatible_printers": [
+ "iQ TiQ2 0.4 Nozzle"
+ ],
+ "internal_bridge_speed": "50%",
+ "internal_solid_infill_speed": "60",
+ "ironing_pattern": "concentric",
+ "prime_tower_width": "80",
+ "layer_height": "0.2",
+ "reduce_crossing_wall": "1",
+ "skirt_height": "1",
+ "skirt_loops": "2",
+ "small_perimeter_speed": "30%",
+ "small_perimeter_threshold": "5",
+ "sparse_infill_density": "30%",
+ "sparse_infill_pattern": "triangles",
+ "support_base_pattern_spacing": "1",
+ "support_bottom_interface_spacing": "0.3",
+ "support_bottom_z_distance": "0.24",
+ "support_expansion": "0.5",
+ "support_filament": "1",
+ "support_interface_filament": "1",
+ "support_interface_pattern": "rectilinear_interlaced",
+ "support_interface_spacing": "0",
+ "top_shell_thickness": "0",
+ "top_solid_infill_flow_ratio": "0.98",
+ "tree_support_branch_diameter_angle": "10",
+ "tree_support_branch_diameter_organic": "3",
+ "tree_support_tip_diameter": "2",
+ "wall_loops": "2"
+}
diff --git a/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - PETG Polymax Polymaker (0.4 Nozzle).json b/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - PETG Polymax Polymaker (0.4 Nozzle).json
index 096eb82e13..1093c7c1c7 100644
--- a/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - PETG Polymax Polymaker (0.4 Nozzle).json
+++ b/resources/profiles/iQ/process/0.20mm Standard @iQ TiQ2 P1 - PETG Polymax Polymaker (0.4 Nozzle).json
@@ -20,6 +20,9 @@
"enable_overhang_speed": "0",
"enable_prime_tower": "0",
"gap_infill_speed": "50",
+ "thick_internal_bridges": "0",
+ "enable_extra_bridge_layer": "apply_to_all",
+ "bottom_shell_thickness": "0.8",
"initial_layer_infill_speed": "25",
"initial_layer_speed": "25",
"initial_layer_travel_speed": "50%",
@@ -63,10 +66,11 @@
"tree_support_wall_count": "2",
"wall_direction": "ccw",
"wall_loops": "3",
- "wall_sequence": "inner-outer-inner wall",
+ "wall_sequence": "inner wall/outer wall",
"support_base_pattern": "rectilinear-grid",
"support_interface_pattern": "rectilinear_interlaced",
"support_interface_spacing": "0",
- "small_perimeter_speed": "30%",
+ "small_perimeter_speed": "50",
+ "support_interface_speed": "50",
"brim_type": "no_brim"
}
\ No newline at end of file
diff --git a/scripts/flatpak/io.github.softfever.OrcaSlicer.metainfo.xml b/scripts/flatpak/io.github.softfever.OrcaSlicer.metainfo.xml
index 96fd4c3ad7..c63f02d96b 100755
--- a/scripts/flatpak/io.github.softfever.OrcaSlicer.metainfo.xml
+++ b/scripts/flatpak/io.github.softfever.OrcaSlicer.metainfo.xml
@@ -11,7 +11,7 @@
Get even more perfect prints!
SoftFever
https://github.com/OrcaSlicer/OrcaSlicer
- https://github.com/OrcaSlicer/OrcaSlicer/wiki
+ https://www.orcaslicer.com/wiki
https://github.com/OrcaSlicer/OrcaSlicer/issues/
https://ko-fi.com/SoftFever
0BSD
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ea7731bf30..8e9a31f705 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,8 +6,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Include dev-utils for encoding check and other utilities
add_subdirectory(dev-utils)
-# Clipper2 math utils
-add_subdirectory(clipper2)
# add_subdirectory(avrdude)
# Note: semver and hints are now included from deps_src/CMakeLists.txt
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 4d91275010..a5fda9f9cb 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -331,10 +331,18 @@ void AppConfig::set_defaults()
set("auto_calculate_flush","all");
}
+ if (get("show_canvas_zoom_button").empty()) {
+ set_bool("show_canvas_zoom_button", true);
+ }
+
if (get("remember_printer_config").empty()) {
set_bool("remember_printer_config", true);
}
+ if (get("group_filament_presets").empty()) {
+ set("group_filament_presets", "1"); // All "0" / None "1" / By Type "2" / By Vendor "3"
+ }
+
if (get("enable_high_low_temp_mixed_printing").empty()){
set_bool("enable_high_low_temp_mixed_printing", false);
}
diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp
index d21ed2e544..35d971a465 100644
--- a/src/libslic3r/Brim.cpp
+++ b/src/libslic3r/Brim.cpp
@@ -1,5 +1,3 @@
-#include "clipper/clipper_z.hpp"
-
#include "ClipperUtils.hpp"
#include "EdgeGrid.hpp"
#include "Layer.hpp"
@@ -10,8 +8,8 @@
#include "MaterialType.hpp"
#include "Model.hpp"
#include
-#include
-#include
+#include
+#include
#include
#include
@@ -54,16 +52,63 @@ static void append_and_translate(Polygons &dst, const Polygons &src, const Print
dst[dst_idx].translate(instance_shift);
}
-static float max_brim_width(const ConstPrintObjectPtrsAdaptor &objects)
+//ORCA: Brim can follow the post-EFC outline when enabled.
+static bool use_brim_efc_outline(const PrintObject &object)
{
- assert(!objects.empty());
- return float(std::accumulate(objects.begin(), objects.end(), 0.,
- [](double partial_result, const PrintObject *object) {
- return std::max(partial_result, object->config().brim_type == btNoBrim ? 0. : object->config().brim_width.value);
- }));
+ return object.config().brim_use_efc_outline.value
+ && object.config().elefant_foot_compensation.value > 0.
+ && object.config().elefant_foot_compensation_layers.value > 0
+ && object.config().raft_layers.value == 0;
}
-// Returns ExPolygons of the bottom layer of the print object after elephant foot compensation.
+//ORCA: Helper for snapping painted ears to the EFC outline.
+static bool closest_point_on_expolygons(const ExPolygons &polygons, const Point &from, Point &closest_out)
+{
+ double min_dist2 = std::numeric_limits::max();
+ bool found = false;
+
+ for (const ExPolygon &poly : polygons) {
+ for (int i = 0; i < poly.num_contours(); ++i) {
+ const Point *candidate = poly.contour_or_hole(i).closest_point(from);
+ if (candidate == nullptr)
+ continue;
+ const int64_t dx = int64_t(candidate->x()) - int64_t(from.x());
+ const int64_t dy = int64_t(candidate->y()) - int64_t(from.y());
+ const double dist2 = double(dx * dx + dy * dy);
+ if (dist2 < min_dist2) {
+ min_dist2 = dist2;
+ closest_out = *candidate;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+//ORCA: Helper for matching painted ears to their original island before EFC snapping.
+static int find_containing_expolygon_index(const ExPolygons &polygons, const Point &from)
+{
+ for (size_t idx = 0; idx < polygons.size(); ++idx) {
+ if (polygons[idx].contains(from))
+ return int(idx);
+ }
+ return -1;
+}
+
+//ORCA: Keep painted ear snapping on the matching island when using EFC outline.
+static bool closest_point_on_matching_island(const ExPolygons &raw_outline, const ExPolygons &efc_outline, const Point &from, Point &closest_out)
+{
+ const int island_idx = find_containing_expolygon_index(raw_outline, from);
+ if (island_idx >= 0) {
+ ExPolygons island_outline = intersection_ex(efc_outline, raw_outline[island_idx]);
+ if (!island_outline.empty())
+ return closest_point_on_expolygons(island_outline, from, closest_out);
+ }
+ return closest_point_on_expolygons(efc_outline, from, closest_out);
+}
+//ORCA: Use post-processed first-layer slices (including EFC) for brim outline.
+// Returns ExPolygons of the bottom layer after all first-layer modifiers
+// (including elephant foot compensation, if enabled) have been applied.
static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &print_object)
{
ExPolygons ex_polygons;
@@ -71,506 +116,6 @@ static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &pr
Slic3r::append(ex_polygons, closing_ex(region->slices.surfaces, float(SCALED_EPSILON)));
return ex_polygons;
}
-
-// Returns ExPolygons of bottom layer for every print object in Print after elephant foot compensation.
-static std::vector get_print_bottom_layers_expolygons(const Print &print)
-{
- std::vector bottom_layers_expolygons;
- bottom_layers_expolygons.reserve(print.objects().size());
- for (const PrintObject *object : print.objects())
- bottom_layers_expolygons.emplace_back(get_print_object_bottom_layer_expolygons(*object));
-
- return bottom_layers_expolygons;
-}
-
-static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, const std::vector &bottom_layers_expolygons)
-{
- assert(print.objects().size() == bottom_layers_expolygons.size());
- Polygons islands;
- ConstPrintObjectPtrs island_to_object;
- for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
- const PrintObject *object = print.objects()[print_object_idx];
- Polygons islands_object;
- islands_object.reserve(bottom_layers_expolygons[print_object_idx].size());
- for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx])
- islands_object.emplace_back(ex_poly.contour);
-
- islands.reserve(islands.size() + object->instances().size() * islands_object.size());
- for (const PrintInstance& instance : object->instances()) {
- Point instance_shift = instance.shift_without_plate_offset();
- for (Polygon& poly : islands_object) {
- islands.emplace_back(poly);
- islands.back().translate(instance_shift);
- island_to_object.emplace_back(object);
- }
- }
- }
- assert(islands.size() == island_to_object.size());
-
- ClipperLib_Z::Paths islands_clip;
- islands_clip.reserve(islands.size());
- for (const Polygon &poly : islands) {
- islands_clip.emplace_back();
- ClipperLib_Z::Path &island_clip = islands_clip.back();
- island_clip.reserve(poly.points.size());
- int island_idx = int(&poly - &islands.front());
- // The Z coordinate carries index of the island used to get the pointer to the object.
- for (const Point &pt : poly.points)
- island_clip.emplace_back(pt.x(), pt.y(), island_idx + 1);
- }
-
- // Init Clipper
- ClipperLib_Z::Clipper clipper;
- // Assign the maximum Z from four points. This values is valid index of the island
- clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
- const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
- pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
- });
- // Add islands
- clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true);
- // Execute union operation to construct polytree
- ClipperLib_Z::PolyTree islands_polytree;
- //FIXME likely pftNonZero or ptfPositive would be better. Why are we using ptfEvenOdd for Unions?
- clipper.Execute(ClipperLib_Z::ctUnion, islands_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
-
- std::unordered_set processed_objects_idx;
- ConstPrintObjectPtrs top_level_objects_with_brim;
- for (int i = 0; i < islands_polytree.ChildCount(); ++i) {
- for (const ClipperLib_Z::IntPoint &point : islands_polytree.Childs[i]->Contour) {
- if (point.z() != 0 && processed_objects_idx.find(island_to_object[point.z() - 1]->id().id) == processed_objects_idx.end()) {
- top_level_objects_with_brim.emplace_back(island_to_object[point.z() - 1]);
- processed_objects_idx.insert(island_to_object[point.z() - 1]->id().id);
- }
- }
- }
- return top_level_objects_with_brim;
-}
-
-static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim, const double scaled_resolution)
-{
- Polygons islands;
- for (const PrintObject *object : top_level_objects_with_brim) {
- if (!object->has_brim())
- continue;
-
- //FIXME how about the brim type?
- auto brim_object_gap = float(scale_(object->config().brim_object_gap.value));
- Polygons islands_object;
- for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) {
- Polygons contour_offset = offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare);
- for (Polygon &poly : contour_offset)
- poly.douglas_peucker(scaled_resolution);
-
- polygons_append(islands_object, std::move(contour_offset));
- }
-
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- Polygons contour_offset = offset(support_contour, brim_object_gap, ClipperLib::jtSquare);
- for (Polygon& poly : contour_offset)
- poly.douglas_peucker(scaled_resolution);
-
- polygons_append(islands_object, std::move(contour_offset));
- }
- }
-
- for (const PrintInstance &instance : object->instances())
- append_and_translate(islands, islands_object, instance);
- }
- return islands;
-}
-
-static ExPolygons top_level_outer_brim_area(const Print &print,
- const ConstPrintObjectPtrs &top_level_objects_with_brim,
- const std::vector &bottom_layers_expolygons,
- const float no_brim_offset,
- // BBS
- double& brim_width_max,
- std::map& brim_width_map)
-{
- const auto scaled_resolution = scaled(print.config().resolution.value);
-
- assert(print.objects().size() == bottom_layers_expolygons.size());
- std::unordered_set top_level_objects_idx;
- top_level_objects_idx.reserve(top_level_objects_with_brim.size());
- for (const PrintObject *object : top_level_objects_with_brim)
- top_level_objects_idx.insert(object->id().id);
-
- ExPolygons brim_area;
- ExPolygons no_brim_area;
- brim_width_max = 0;
- for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
- const PrintObject *object = print.objects()[print_object_idx];
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_object_gap = scale_(object->config().brim_object_gap.value);
- // recording the autoAssigned brimWidth and corresponding objs
- double brimWidthAuto = object->config().brim_width.value;
- double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR;
- brimWidthAuto = floor(brimWidthAuto / flowWidth / 2) * flowWidth * 2;
- brim_width_map.insert(std::make_pair(object->id(), brimWidthAuto));
- brim_width_max = std::max(brim_width_max, brimWidthAuto);
- const float brim_width = scale_(brimWidthAuto);
- const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
-
- ExPolygons brim_area_object;
- ExPolygons no_brim_area_object;
- for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
- if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim)
- append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_object_gap, ClipperLib::jtRound, scaled_resolution), offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare)));
-
- // After 7ff76d07684858fd937ef2f5d863f105a10f798e offset and shrink don't work with CW polygons (holes), so let's make it CCW.
- Polygons ex_poly_holes_reversed = ex_poly.holes;
- polygons_reverse(ex_poly_holes_reversed);
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare));
-
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed));
-
- if (brim_type != BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ExPolygon(ex_poly.contour), brim_object_gap, ClipperLib::jtSquare));
-
- no_brim_area_object.emplace_back(ex_poly.contour);
- }
-
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim)
- append(brim_area_object, diff_ex(offset(support_contour, brim_width + brim_object_gap, ClipperLib::jtRound, scaled_resolution), offset(support_contour, brim_object_gap)));
-
- if (brim_type != BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ExPolygon(support_contour), brim_object_gap));
-
- no_brim_area_object.emplace_back(support_contour);
- }
- }
-
- for (const PrintInstance &instance : object->instances()) {
- append_and_translate(brim_area, brim_area_object, instance);
- append_and_translate(no_brim_area, no_brim_area_object, instance);
- }
- }
-
- return diff_ex(brim_area, no_brim_area);
-}
-
-// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders
-static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
- const float no_brim_offset, double& brim_width_max, std::map& brim_width_map,
- std::map& brimAreaMap,
- std::map& supportBrimAreaMap, std::vector>& objPrintVec)
-{
- std::unordered_set top_level_objects_idx;
- top_level_objects_idx.reserve(top_level_objects_with_brim.size());
- for (const PrintObject* object : top_level_objects_with_brim)
- top_level_objects_idx.insert(object->id().id);
-
- unsigned int support_material_extruder = 1;
- if (print.has_support_material()) {
- assert(top_level_objects_with_brim.front()->config().support_filament >= 0);
- if (top_level_objects_with_brim.front()->config().support_filament > 0)
- support_material_extruder = top_level_objects_with_brim.front()->config().support_filament;
- }
-
- ExPolygons brim_area;
- ExPolygons no_brim_area;
- brim_width_max = 0;
- struct brimWritten {
- bool obj;
- bool sup;
- };
- std::map brimToWrite;
- for (const auto& objectWithExtruder : objPrintVec)
- brimToWrite.insert({ objectWithExtruder.first, {true,true} });
-
- for (unsigned int extruderNo : print.extruders()) {
- ++extruderNo;
- for (const auto &objectWithExtruder : objPrintVec) {
- const PrintObject* object = print.get_object(objectWithExtruder.first);
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_offset = scale_(object->config().brim_object_gap.value);
- // recording the autoAssigned brimWidth and corresponding objs
- double brimWidthAuto = object->config().brim_width.value;
- double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR;
- brimWidthAuto = floor(brimWidthAuto / flowWidth / 2) * flowWidth * 2;
- brim_width_map.insert(std::make_pair(object->id(), brimWidthAuto));
- brim_width_max = std::max(brim_width_max, brimWidthAuto);
- const float brim_width = scale_(brimWidthAuto);
- const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
-
- ExPolygons nullBrim;
- brimAreaMap.insert(std::make_pair(object->id(), nullBrim));
- ExPolygons brim_area_object;
- ExPolygons brim_area_support;
- ExPolygons no_brim_area_object;
- ExPolygons no_brim_area_support;
- if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) {
- for (const ExPolygon& ex_poly : object->layers().front()->lslices) {
- if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim) {
- append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION),
- offset_ex(ex_poly.contour, brim_offset)));
- }
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset));
-
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly.holes));
-
- if (brim_type != BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ExPolygon(ex_poly.contour), brim_offset));
-
- no_brim_area_object.emplace_back(ex_poly.contour);
- }
- brimToWrite.at(object->id()).obj = false;
- for (const PrintInstance& instance : object->instances()) {
- if (!brim_area_object.empty())
- append_and_translate(brim_area, brim_area_object, instance, print, brimAreaMap);
- append_and_translate(no_brim_area, no_brim_area_object, instance);
- }
- if (brimAreaMap.find(object->id()) != brimAreaMap.end())
- expolygons_append(brim_area, brimAreaMap[object->id()]);
- }
- if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) {
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- //BBS: no brim offset for supports
- if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim)
- append(brim_area_support, diff_ex(offset(support_contour, brim_width, jtRound, SCALED_RESOLUTION), offset(support_contour, 0)));
-
- if (brim_type != BrimType::btNoBrim)
- append(no_brim_area_support, offset_ex(support_contour, 0));
-
- no_brim_area_support.emplace_back(support_contour);
- }
- }
-
- brimToWrite.at(object->id()).sup = false;
- for (const PrintInstance& instance : object->instances()) {
- if (!brim_area_support.empty())
- append_and_translate(brim_area, brim_area_support, instance, print, supportBrimAreaMap);
- append_and_translate(no_brim_area, no_brim_area_support, instance);
- }
- if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end())
- expolygons_append(brim_area, supportBrimAreaMap[object->id()]);
- }
- }
- }
- for (const PrintObject* object : print.objects()) {
- if (brimAreaMap.find(object->id()) != brimAreaMap.end())
- brimAreaMap[object->id()] = diff_ex(brimAreaMap[object->id()], no_brim_area);
- if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end())
- supportBrimAreaMap[object->id()] = diff_ex(supportBrimAreaMap[object->id()], no_brim_area);
- }
- return diff_ex(std::move(brim_area), no_brim_area);
-}
-static ExPolygons inner_brim_area(const Print &print,
- const ConstPrintObjectPtrs &top_level_objects_with_brim,
- const std::vector &bottom_layers_expolygons,
- const float no_brim_offset)
-{
- assert(print.objects().size() == bottom_layers_expolygons.size());
- std::unordered_set top_level_objects_idx;
- top_level_objects_idx.reserve(top_level_objects_with_brim.size());
- for (const PrintObject *object : top_level_objects_with_brim)
- top_level_objects_idx.insert(object->id().id);
-
- ExPolygons brim_area;
- ExPolygons no_brim_area;
- Polygons holes;
- for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
- const PrintObject *object = print.objects()[print_object_idx];
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_object_gap = scale_(object->config().brim_object_gap.value);
- double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR;
- const float brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2);
- const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
-
- ExPolygons brim_area_object;
- ExPolygons no_brim_area_object;
- Polygons holes_object;
- for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) {
- if (top_outer_brim)
- no_brim_area_object.emplace_back(ex_poly);
- else
- append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_object_gap, ClipperLib::jtSquare), offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare)));
- }
-
- // After 7ff76d07684858fd937ef2f5d863f105a10f798e offset and shrink don't work with CW polygons (holes), so let's make it CCW.
- Polygons ex_poly_holes_reversed = ex_poly.holes;
- polygons_reverse(ex_poly_holes_reversed);
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim)
- append(brim_area_object, diff_ex(shrink_ex(ex_poly_holes_reversed, brim_object_gap, ClipperLib::jtSquare), shrink_ex(ex_poly_holes_reversed, brim_width + brim_object_gap, ClipperLib::jtSquare)));
-
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed));
-
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, diff_ex(ExPolygon(ex_poly.contour), shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare)));
-
- append(holes_object, ex_poly_holes_reversed);
- }
- append(no_brim_area_object, offset_ex(bottom_layers_expolygons[print_object_idx], brim_object_gap, ClipperLib::jtSquare));
-
- for (const PrintInstance &instance : object->instances()) {
- append_and_translate(brim_area, brim_area_object, instance);
- append_and_translate(no_brim_area, no_brim_area_object, instance);
- append_and_translate(holes, holes_object, instance);
- }
- }
-
- return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area);
-}
-
-// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders
-static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
- const float no_brim_offset, std::map& brimAreaMap,
- std::map& supportBrimAreaMap,
- std::vector>& objPrintVec)
-{
- std::unordered_set top_level_objects_idx;
- top_level_objects_idx.reserve(top_level_objects_with_brim.size());
- for (const PrintObject* object : top_level_objects_with_brim)
- top_level_objects_idx.insert(object->id().id);
-
- unsigned int support_material_extruder = 1;
- if (print.has_support_material()) {
- assert(top_level_objects_with_brim.front()->config().support_filament >= 0);
- if (top_level_objects_with_brim.front()->config().support_filament > 0)
- support_material_extruder = top_level_objects_with_brim.front()->config().support_filament;
- }
-
- ExPolygons brim_area;
- ExPolygons no_brim_area;
- Polygons holes;
- Polygon bedShape(get_bed_shape(print.config()));
- holes.emplace_back(get_bed_shape(print.config()));
- std::map innerBrimAreaMap;
- std::map innerSupportBrimAreaMap;
-
- struct brimWritten {
- bool obj;
- bool sup;
- };
- std::map brimToWrite;
- for (const auto& objectWithExtruder : objPrintVec)
- brimToWrite.insert({ objectWithExtruder.first, {true,true} });
-
-
- for (unsigned int extruderNo : print.extruders()) {
- ++extruderNo;
- for (const auto& objectWithExtruder : objPrintVec) {
- const PrintObject* object = print.get_object(objectWithExtruder.first);
- const BrimType brim_type = object->config().brim_type.value;
- const float brim_offset = scale_(object->config().brim_object_gap.value);
- double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR;
- const float brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2);
- const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
-
- ExPolygons brim_area_object;
- ExPolygons no_brim_area_object;
- ExPolygons brim_area_support;
- ExPolygons no_brim_area_support;
- Polygons holes_object;
- Polygons holes_support;
- if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) {
- for (const ExPolygon& ex_poly : object->layers().front()->lslices) {
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) {
- if (top_outer_brim)
- no_brim_area_object.emplace_back(ex_poly);
- else
- append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION), offset_ex(ex_poly.contour, brim_offset)));
- }
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner)
- append(brim_area_object, diff_ex(offset_ex(ex_poly.holes, -brim_offset), offset_ex(ex_poly.holes, -brim_width - brim_offset)));
- if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly.holes));
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim)
- append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset));
- append(holes_object, ex_poly.holes);
- }
- append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset));
- brimToWrite.at(object->id()).obj = false;
- for (const PrintInstance& instance : object->instances()) {
- if (!brim_area_object.empty())
- append_and_translate(brim_area, brim_area_object, instance, print, innerBrimAreaMap);
- append_and_translate(no_brim_area, no_brim_area_object, instance);
- append_and_translate(holes, holes_object, instance);
- }
- if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end())
- expolygons_append(brim_area, innerBrimAreaMap[object->id()]);
- }
- if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) {
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) {
- if (!top_outer_brim)
- append(brim_area_support, diff_ex(offset_ex(support_contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION), offset_ex(support_contour, brim_offset)));
- }
- if (brim_type != BrimType::btNoBrim)
- append(no_brim_area_support, offset_ex(support_contour, 0));
- no_brim_area_support.emplace_back(support_contour);
- }
- }
- }
- brimToWrite.at(object->id()).sup = false;
- for (const PrintInstance& instance : object->instances()) {
- if (!brim_area_support.empty())
- append_and_translate(brim_area, brim_area_support, instance, print, innerSupportBrimAreaMap);
- append_and_translate(no_brim_area, no_brim_area_support, instance);
- append_and_translate(holes, holes_support, instance);
- }
- if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end())
- expolygons_append(brim_area, innerSupportBrimAreaMap[object->id()]);
- }
- }
- for (const PrintObject* object : print.objects()) {
- if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end()) {
- innerBrimAreaMap[object->id()] = intersection_ex(to_polygons(innerBrimAreaMap[object->id()]), holes);
- append(brimAreaMap[object->id()], innerBrimAreaMap[object->id()]);
- }
- if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) {
- innerSupportBrimAreaMap[object->id()] = intersection_ex(to_polygons(innerSupportBrimAreaMap[object->id()]), holes);
- append(supportBrimAreaMap[object->id()], innerSupportBrimAreaMap[object->id()]);
- }
- }
- for (const PrintObject* object : print.objects()) {
- if (brimAreaMap.find(object->id()) != brimAreaMap.end())
- brimAreaMap[object->id()] = diff_ex(brimAreaMap[object->id()], no_brim_area);
- if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end())
- supportBrimAreaMap[object->id()] = diff_ex(supportBrimAreaMap[object->id()], no_brim_area);
- }
- brim_area = intersection_ex(to_polygons(brim_area), holes);
- append(no_brim_area, brim_area);
- return no_brim_area;
-}
-
-//BBS maximum temperature difference from print object class
-double getTemperatureFromExtruder(const PrintObject* printObject) {
- auto print = printObject->print();
- std::vector extrudersFirstLayer;
- auto firstLayerRegions = printObject->layers().front()->regions();
- if (!firstLayerRegions.empty()) {
- for (const LayerRegion* regionPtr : firstLayerRegions) {
- if (regionPtr->has_extrusions())
- extrudersFirstLayer.push_back(regionPtr->region().extruder(frExternalPerimeter));
- }
- }
-
- const PrintConfig& config = print->config();
- int curr_bed_type = config.option("curr_bed_type")->getInt();
- const ConfigOptionInts* bed_temp_1st_layer_opt = config.option(get_bed_temp_1st_layer_key((BedType)curr_bed_type));
-
- double maxDeltaTemp = 0;
- for (auto extruderID : extrudersFirstLayer) {
- int bedTemp = bed_temp_1st_layer_opt->get_at(extruderID - 1);
- if (bedTemp > maxDeltaTemp)
- maxDeltaTemp = bedTemp;
- }
-
- return maxDeltaTemp;
-}
//BBS adhesion coefficients from print object class
double getadhesionCoeff(const PrintObject* printObject)
{
@@ -711,50 +256,6 @@ bool compSecondMoment(const ExPolygons& expolys, double& smExpolysX, double& smE
return true;
}
-
-
-
-//BBS: config brimwidth by volumes
-double configBrimWidthByVolumes(double deltaT, double adhesion, double maxSpeed, const ModelVolume* modelVolumePtr, const ExPolygons& expolys)
-{
- // height of a volume
- double height = 0;
- if (modelVolumePtr->is_model_part()) {
- auto rawBoundingbox = modelVolumePtr->mesh().transformed_bounding_box(modelVolumePtr->get_matrix());
- auto bbox = modelVolumePtr->get_object()->instances.front()->transform_bounding_box(rawBoundingbox);
- auto bbox_size = bbox.size();
- height = bbox_size(2);
- }
-
- // sencond moment of the expolygons of the first layer of the volume
- double Ixx = -1.e30, Iyy = -1.e30;
- if (!expolys.empty()) {
- if (!compSecondMoment(expolys, Ixx, Iyy))
- Ixx = Iyy = -1.e30;
- }
- Ixx = Ixx * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR;
- Iyy = Iyy * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR;
-
- // bounding box of the expolygons of the first layer of the volume
- BoundingBox bbox2;
- for (const auto& expoly : expolys)
- bbox2.merge(get_extents(expoly.contour));
- const double& bboxX = bbox2.size()(0);
- const double& bboxY = bbox2.size()(1);
- double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR;
- double thermalLengthRef = Model::getThermalLength(modelVolumePtr);
-
- double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR));
- double brim_width = adhesion * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength);
- // small brims are omitted
- if (brim_width < 5 && brim_width < 1.5 * thermalLength)
- brim_width = 0;
- // large brims are omitted
- if (brim_width > 18) brim_width = 18.;
-
- return brim_width;
-}
-
//BBS: config brimwidth by group of volumes
double configBrimWidthByVolumeGroups(double adhesion, double maxSpeed, const std::vector modelVolumePtrs, const ExPolygons& expolys, double &groupHeight)
{
@@ -857,6 +358,14 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi
if (brim_ear_points.size() <= 0) {
return mouse_ears_ex;
}
+ //ORCA: Painted ears can snap to the EFC-adjusted outline when enabled.
+ const bool use_efc_outline = use_brim_efc_outline(*object);
+ const ExPolygons &raw_outline = object->layers().front()->lslices;
+ //ORCA: Lazily computed EFC-adjusted bottom outline.
+ //Stored separately so we can avoid recomputation unless EFC snapping is used.
+ ExPolygons efc_outline_storage;
+ const ExPolygons* efc_outline = nullptr;
+
const Geometry::Transformation& trsf = object->model_object()->instances[0]->get_transformation();
Transform3d model_trsf = trsf.get_matrix_no_offset();
const Point ¢er_offset = object->center_offset();
@@ -880,6 +389,29 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi
Vec3f pos = pt.transform(model_trsf);
int32_t pt_x = scale_(pos.x());
int32_t pt_y = scale_(pos.y());
+
+ //ORCA: Snap painted ears to the EFC-adjusted outline when enabled.
+ if (use_efc_outline) {
+ if (efc_outline == nullptr) {
+ //ORCA: Compute EFC-adjusted outline lazily for painted ear snapping.
+ efc_outline_storage = get_print_object_bottom_layer_expolygons(*object);
+ efc_outline = &efc_outline_storage;
+ }
+
+ if (!efc_outline->empty()) {
+ Point closest_point;
+ //ORCA: Snap within the matching island to avoid drifting to another island.
+ if (closest_point_on_matching_island(
+ raw_outline,
+ *efc_outline,
+ Point(pt_x, pt_y),
+ closest_point)) {
+ pt_x = closest_point.x();
+ pt_y = closest_point.y();
+ }
+ }
+ }
+
mouse_ears_ex.back().contour.translate(Point(pt_x, pt_y));
}
return mouse_ears_ex;
@@ -926,6 +458,14 @@ static ExPolygons outer_inner_brim_area(const Print& print,
const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || use_auto_brim_ears || use_brim_ears;
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;
+ //ORCA: Select brim base slices from EFC-compensated outline when enabled.
+ const bool use_efc_outline = use_brim_efc_outline(*object);
+ ExPolygons brim_slices_storage;
+ const ExPolygons* brim_slices = nullptr;
+ //ORCA: Select EFC-adjusted bottom outline when enabled.
+ if (use_efc_outline)
+ brim_slices_storage = get_print_object_bottom_layer_expolygons(*object);
+ brim_slices = use_efc_outline ? &brim_slices_storage : &object->layers().front()->lslices;
ExPolygons brim_area_object;
ExPolygons no_brim_area_object;
@@ -961,64 +501,72 @@ static ExPolygons outer_inner_brim_area(const Print& print,
double brimWidthRaw = configBrimWidthByVolumeGroups(adhesion, maxSpeed, groupVolumePtrs, volumeGroup.slices, groupHeight);
brim_width = scale_(floor(brimWidthRaw / flowWidth / 2) * flowWidth * 2);
}
- for (const ExPolygon& ex_poly : volumeGroup.slices) {
- // BBS: additional brim width will be added if part's adhesion area is too small and brim is not generated
- float brim_width_mod;
- if (brim_width < scale_(5.) && has_brim_auto && groupHeight > 10.) {
- brim_width_mod = ex_poly.area() / ex_poly.contour.length() < scaled_half_min_adh_length
- && brim_width < scaled_flow_width ? brim_width + scaled_additional_brim_width : brim_width;
- }
- else {
- brim_width_mod = brim_width;
- }
- //BBS: brim width should be limited to the 1.5*boundingboxSize of a single polygon.
- if (has_brim_auto) {
- BoundingBox bbox2 = ex_poly.contour.bounding_box();
- brim_width_mod = std::min(brim_width_mod, float(std::max(bbox2.size()(0), bbox2.size()(1))));
- }
- brim_width_mod = floor(brim_width_mod / scaled_flow_width / 2) * scaled_flow_width * 2;
-
- Polygons ex_poly_holes_reversed = ex_poly.holes;
- polygons_reverse(ex_poly_holes_reversed);
-
- if (has_outer_brim) {
- // BBS: inner and outer boundary are offset from the same polygon incase of round off error.
- auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION);
- ExPolygons outerExpoly;
- if (use_brim_ears) {
- outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true);
- //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION);
- } else if (use_auto_brim_ears) {
- coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing());
- outerExpoly = make_brim_ears_auto(innerExpoly, size_ear, ear_detection_length, brim_ears_max_angle, true);
- }else {
- outerExpoly = offset_ex(innerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION);
- }
- append(brim_area_object, diff_ex(outerExpoly, innerExpoly));
- }
- if (has_inner_brim) {
- ExPolygons outerExpoly;
- auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset);
- if (use_brim_ears) {
- outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false);
- } else if (use_auto_brim_ears) {
- coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing());
- outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false);
- }else {
- outerExpoly = offset_ex(ex_poly_holes_reversed, -brim_offset);
- }
- append(brim_area_object, intersection_ex(diff_ex(outerExpoly, innerExpoly), ex_poly_holes_reversed));
- }
- if (!has_inner_brim) {
- // BBS: brim should be apart from holes
- append(no_brim_area_object, diff_ex(ex_poly_holes_reversed, offset_ex(ex_poly_holes_reversed, -no_brim_offset)));
- }
- if (!has_outer_brim)
- append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly_holes_reversed));
- append(holes_object, ex_poly_holes_reversed);
+ ExPolygons volume_group_slices_efc;
+ const ExPolygons* volume_group_slices = &volumeGroup.slices;
+ if (use_efc_outline) {
+ //ORCA: When using EFC outline, restrict per-volume-group slices to the
+ // EFC-adjusted bottom footprint to keep brim width heuristics consistent.
+ volume_group_slices_efc = intersection_ex(*brim_slices, volumeGroup.slices);
+ volume_group_slices = &volume_group_slices_efc;
}
- }
- auto objectIsland = offset_ex(object->layers().front()->lslices, brim_offset, jtRound, SCALED_RESOLUTION);
+ for (const ExPolygon& ex_poly : *volume_group_slices) {
+ // BBS: additional brim width will be added if part's adhesion area is too small and brim is not generated
+ float brim_width_mod;
+ if (brim_width < scale_(5.) && has_brim_auto && groupHeight > 10.) {
+ brim_width_mod = ex_poly.area() / ex_poly.contour.length() < scaled_half_min_adh_length
+ && brim_width < scaled_flow_width ? brim_width + scaled_additional_brim_width : brim_width;
+ }
+ else {
+ brim_width_mod = brim_width;
+ }
+ //BBS: brim width should be limited to the 1.5*boundingboxSize of a single polygon.
+ if (has_brim_auto) {
+ BoundingBox bbox2 = ex_poly.contour.bounding_box();
+ brim_width_mod = std::min(brim_width_mod, float(std::max(bbox2.size()(0), bbox2.size()(1))));
+ }
+ brim_width_mod = floor(brim_width_mod / scaled_flow_width / 2) * scaled_flow_width * 2;
+
+ Polygons ex_poly_holes_reversed = ex_poly.holes;
+ polygons_reverse(ex_poly_holes_reversed);
+
+ if (has_outer_brim) {
+ // BBS: inner and outer boundary are offset from the same polygon incase of round off error.
+ auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION);
+ ExPolygons outerExpoly;
+ if (use_brim_ears) {
+ outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true);
+ //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION);
+ } else if (use_auto_brim_ears) {
+ coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing());
+ outerExpoly = make_brim_ears_auto(innerExpoly, size_ear, ear_detection_length, brim_ears_max_angle, true);
+ }else {
+ outerExpoly = offset_ex(innerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION);
+ }
+ append(brim_area_object, diff_ex(outerExpoly, innerExpoly));
+ }
+ if (has_inner_brim) {
+ ExPolygons outerExpoly;
+ auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset);
+ if (use_brim_ears) {
+ outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false);
+ } else if (use_auto_brim_ears) {
+ coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing());
+ outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false);
+ }else {
+ outerExpoly = offset_ex(ex_poly_holes_reversed, -brim_offset);
+ }
+ append(brim_area_object, intersection_ex(diff_ex(outerExpoly, innerExpoly), ex_poly_holes_reversed));
+ }
+ if (!has_inner_brim) {
+ // BBS: brim should be apart from holes
+ append(no_brim_area_object, diff_ex(ex_poly_holes_reversed, offset_ex(ex_poly_holes_reversed, -no_brim_offset)));
+ }
+ if (!has_outer_brim)
+ append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly_holes_reversed));
+ append(holes_object, ex_poly_holes_reversed);
+ }
+ }
+ auto objectIsland = offset_ex(*brim_slices, brim_offset, jtRound, SCALED_RESOLUTION);
append(no_brim_area_object, objectIsland);
brimToWrite.at(object->id()).obj = false;
@@ -1261,393 +809,8 @@ static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_
return std::move(polylines);
}
-
-// BBS: this function is used to generate brim for inner island inside holes
-// Collect island + brim area to be minused when generating inner brim for holes
-static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
- ExtrusionEntityCollection &brim, ExPolygons &islands_area_ex)
-{
- const auto scaled_resolution = scaled(print.config().resolution.value);
-
- auto save_polygon_if_is_inner_island = [scaled_resolution](const Polygons& holes_area, Polygon& contour, std::map& hole_island_pair) {
- for (size_t i = 0; i < holes_area.size(); i++) {
- Polygons contour_polys;
- contour_polys.push_back(contour);
- if (diff_ex(contour_polys, { holes_area[i] }).empty()) {
- // BBS: this is an inner island inside holes_area[i], save
- contour.douglas_peucker(scaled_resolution);
- hole_island_pair[i].push_back(contour);
- break;
- }
- }
- };
-
- Flow flow = print.brim_flow();
- for (const PrintObject* object : top_level_objects_with_brim) {
- const BrimType brim_type = object->config().brim_type.value;
- // BBS: don't need to handle this object if hasn't enabled outer_brim
- if (brim_type == BrimType::btNoBrim)
- continue;
-
- //BBS: 1 collect holes area which is used to limit the brim of inner island
- Polygons holes_area;
- for (const ExPolygon& ex_poly : object->layers().front()->lslices)
- polygons_append(holes_area, ex_poly.holes);
-
-
- //BBS: 2 get the island polygons inside holes, saved as map
- std::map hole_island_pair;
- for (const ExPolygon& ex_poly : object->layers().front()->lslices) {
- Polygon counter = ex_poly.contour;
- save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair);
- }
-
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- Polygon counter = support_contour;
- save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair);
- }
- }
-
- //BBS: 3 generate loops, only save part of loop which inside hole
- const float brim_offset = scale_(object->config().brim_object_gap.value);
- const float brim_width = scale_(object->config().brim_width.value);
- if (brim_type == BrimType::btInnerOnly) {
- // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island.
- // Only update islands_area_ex and return
- for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) {
- ExPolygons islands_area_ex_object = intersection_ex(offset(it->second, brim_offset), offset(holes_area[it->first], -brim_offset));
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_object, instance);
- }
- }
- else {
- size_t num_loops = size_t(floor(brim_width / float(flow.scaled_spacing())));
- for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) {
- Polygons loops;
- Polygons inner_islands = offset(it->second, brim_offset);
- Polygons brimable_area = offset(holes_area[it->first], -brim_offset); //offset to keep away from hole
- Polygons contour = inner_islands;
- for (size_t i = 0; i < num_loops; ++i) {
- contour = offset(contour, float(flow.scaled_spacing()), jtSquare);
- for (Polygon& poly : contour)
- poly.douglas_peucker(scaled_resolution);
- polygons_append(loops, offset(contour, -0.5f * float(flow.scaled_spacing())));
- }
- // BBS: to be checked.
- //loops = union_pt_chained_outside_in(loops, false);
- loops = union_pt_chained_outside_in(loops);
-
- std::vector loops_pl_by_levels;
- {
- Polylines loops_pl = to_polylines(loops);
- loops_pl_by_levels.assign(loops_pl.size(), Polylines());
- tbb::parallel_for(tbb::blocked_range(0, loops_pl.size()),
- [&loops_pl_by_levels, &loops_pl, &brimable_area](const tbb::blocked_range& range) {
- for (size_t i = range.begin(); i < range.end(); ++i) {
- loops_pl_by_levels[i] = chain_polylines(intersection_pl({ std::move(loops_pl[i]) }, brimable_area));
- }
- });
- }
-
- // BBS: Reduce down to the ordered list of polylines.
- Polylines all_loops_object;
- for (Polylines& polylines : loops_pl_by_levels)
- append(all_loops_object, std::move(polylines));
- loops_pl_by_levels.clear();
-
- optimize_polylines_by_reversing(&all_loops_object);
- all_loops_object = connect_brim_lines(std::move(all_loops_object), offset(inner_islands, float(SCALED_EPSILON)), float(flow.scaled_spacing()) * 2.f);
-
- Polylines final_loops;
- for (const PrintInstance& instance : object->instances()) {
- size_t dst_idx = final_loops.size();
- final_loops.insert(final_loops.end(), all_loops_object.begin(), all_loops_object.end());
- Point instance_shift = instance.shift_without_plate_offset();
- for (; dst_idx < final_loops.size(); ++dst_idx)
- final_loops[dst_idx].translate(instance_shift);
-
- }
- extrusion_entities_append_loops_and_paths(brim.entities, std::move(final_loops),
- erBrim, float(flow.mm3_per_mm()), float(flow.width()),
- float(print.skirt_first_layer_height()));
-
- //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes
- //Inner brim of holes must not occupy this area
- ExPolygons islands_area_ex_object = intersection_ex(contour, brimable_area);
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_object, instance);
- }
- }
- }
-}
-
-//BBS: the brim are generated one by one, and sorted by objs/supports and extruders
-static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
- std::map& innerbrimAreaMap,
- std::map& innerSupportBrimAreaMap,
- ExPolygons& islands_area_ex, ExPolygons& NobrimArea,
- std::vector>& objPrintVec)
-{
- auto save_polygon_if_is_inner_island = [](const Polygons& holes_area, Polygon& counter, std::map& hole_island_pair) {
- for (size_t i = 0; i < holes_area.size(); i++) {
- if (diff_ex(Polygons{ counter }, { holes_area[i] }).empty()) {
- // BBS: this is an inner island inside holes_area[i], save
- counter.douglas_peucker(SCALED_RESOLUTION);
- hole_island_pair[i].push_back(counter);
- break;
- }
- }
- };
-
- unsigned int support_material_extruder = 1;
- if (print.has_support_material()) {
- assert(top_level_objects_with_brim.front()->config().support_filament >= 0);
- if (top_level_objects_with_brim.front()->config().support_filament > 0)
- support_material_extruder = top_level_objects_with_brim.front()->config().support_filament;
- }
-
- std::unordered_set top_level_objects_idx;
- top_level_objects_idx.reserve(top_level_objects_with_brim.size());
- for (const PrintObject* object : top_level_objects_with_brim)
- top_level_objects_idx.insert(object->id().id);
-
- struct brimWritten {
- bool obj;
- bool sup;
- };
- std::map brimToWrite;
- for (const auto& objectWithExtruder : objPrintVec)
- if (top_level_objects_idx.find(objectWithExtruder.first.id) != top_level_objects_idx.end())
- brimToWrite.insert({ objectWithExtruder.first, {true,true} });
-
- Flow flow = print.brim_flow();
- for (unsigned int extruderNo : print.extruders()) {
- ++extruderNo;
- for (const auto& objectWithExtruder : objPrintVec) {
- if (top_level_objects_idx.find(objectWithExtruder.first.id) != top_level_objects_idx.end()) {
- const PrintObject* object = print.get_object(objectWithExtruder.first);
- const BrimType brim_type = object->config().brim_type.value;
- // BBS: don't need to handle this object if hasn't enabled outer_brim
- if (brim_type == BrimType::btNoBrim)
- continue;
-
- //BBS: 1 collect holes area which is used to limit the brim of inner island
- Polygons holes_area;
- for (const ExPolygon& ex_poly : object->layers().front()->lslices)
- polygons_append(holes_area, ex_poly.holes);
-
-
- //BBS: 2 get the island polygons inside holes, saved as map
- std::map hole_island_pair;
- for (const ExPolygon& ex_poly : object->layers().front()->lslices) {
- Polygon counter = ex_poly.contour;
- save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair);
- }
- std::map hole_island_pair_supports;
- if (!object->support_layers().empty()) {
- for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) {
- Polygon counter = support_contour;
- save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair_supports);
- }
- }
-
- //BBS: 3 generate loops, only save part of loop which inside hole
- const float brim_offset = scale_(object->config().brim_object_gap.value);
- const float brim_width = floor(scale_(object->config().brim_width.value) / 2 / flow.scaled_spacing()) * 2 * flow.scaled_spacing();
- if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) {
- if (brim_type == BrimType::btInnerOnly) {
- // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island.
- // Only update islands_area_ex and return
- for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) {
- ExPolygons islands_area_ex_object = intersection_ex(offset(it->second, brim_offset), offset(holes_area[it->first], -brim_offset));
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_object, instance);
- }
- brimToWrite.at(object->id()).obj = false;
- }
- else {
- for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) {
- Polygons loops;
- Polygons inner_islands = offset(it->second, brim_offset);
- Polygons brimable_area = offset(holes_area[it->first], -brim_offset); //offset to keep away from hole
- Polygons contour = offset(inner_islands, brim_offset + brim_width, jtRound, SCALED_RESOLUTION);
- for (Polygon& poly : contour)
- poly.douglas_peucker(SCALED_RESOLUTION);
-
-
- //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes
- //Inner brim of holes must not occupy this area
- ExPolygons islands_area_ex_object = intersection_ex(contour, brimable_area);
- ExPolygons inner_islands_exp = offset_ex(inner_islands, 0.);
- islands_area_ex_object = diff_ex(islands_area_ex_object, inner_islands_exp);
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_object, instance, print, innerbrimAreaMap);
- }
- brimToWrite.at(object->id()).obj = false;
- }
- if (innerbrimAreaMap.find(object->id()) != innerbrimAreaMap.end())
- expolygons_append(islands_area_ex, innerbrimAreaMap[object->id()]);
- }
-
-
- if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) {
- if (brim_type == BrimType::btInnerOnly) {
- // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island.
- // Only update islands_area_ex and return
- for (auto it = hole_island_pair_supports.begin(); it != hole_island_pair_supports.end(); it++) {
- ExPolygons islands_area_ex_support = intersection_ex(offset(it->second, 0), offset(holes_area[it->first], 0));
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_support, instance);
- }
- brimToWrite.at(object->id()).sup = false;
- }
- else {
- for (auto it = hole_island_pair_supports.begin(); it != hole_island_pair_supports.end(); it++) {
- Polygons loops;
- Polygons inner_islands = offset(it->second, 0);
- Polygons brimable_area = offset(holes_area[it->first], -float(flow.scaled_spacing())); //offset to keep away from hole
- Polygons contour = offset(inner_islands, brim_width, jtRound, SCALED_RESOLUTION);
- for (Polygon& poly : contour)
- poly.douglas_peucker(SCALED_RESOLUTION);
-
-
- //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes
- //Inner brim of holes must not occupy this area
- ExPolygons islands_area_ex_support = intersection_ex(contour, brimable_area);
- ExPolygons inner_islands_exp = offset_ex(inner_islands, 0.);
- islands_area_ex_support = diff_ex(islands_area_ex_support, inner_islands_exp);
- for (const PrintInstance& instance : object->instances())
- append_and_translate(islands_area_ex, islands_area_ex_support, instance, print, innerSupportBrimAreaMap);
-
- }
- brimToWrite.at(object->id()).sup = false;
- }
- if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end())
- expolygons_append(islands_area_ex, innerSupportBrimAreaMap[object->id()]);
- }
- }
- }
- }
- islands_area_ex = diff_ex(islands_area_ex, NobrimArea);
- for (const PrintObject* object : print.objects()) {
- if (innerbrimAreaMap.find(object->id()) != innerbrimAreaMap.end())
- innerbrimAreaMap[object->id()] = diff_ex(innerbrimAreaMap[object->id()], NobrimArea);
- if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end())
- innerSupportBrimAreaMap[object->id()] = diff_ex(innerSupportBrimAreaMap[object->id()], NobrimArea);
- }
-}
-static void make_inner_brim(const Print &print,
- const ConstPrintObjectPtrs &top_level_objects_with_brim,
- const std::vector &bottom_layers_expolygons,
- ExtrusionEntityCollection &brim)
-{
- assert(print.objects().size() == bottom_layers_expolygons.size());
- const auto scaled_resolution = scaled(print.config().resolution.value);
-
- //BBS: generate brim for inner island first
- ExPolygons inner_islands_ex;
- make_inner_island_brim(print, top_level_objects_with_brim, brim, inner_islands_ex);
-
-#ifdef INNER_ISLAND_BRIM_DEBUG_TO_SVG
- static int irun = 0;
- BoundingBox bbox_svg;
- bbox_svg.merge(get_extents(inner_islands_ex));
- {
- std::stringstream stri;
- stri << "inner_island_and_brim_area_" << irun << ".svg";
- SVG svg(stri.str(), bbox_svg);
- svg.draw(to_polylines(inner_islands_ex), "blue");
- svg.Close();
- }
- ++ irun;
-#endif
-
- Flow flow = print.brim_flow();
- ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
- //BBS: brim of hole must not overlap with inner island and inner island brim
- if (!inner_islands_ex.empty()) {
- islands_ex = diff_ex(islands_ex, inner_islands_ex);
- }
-
- Polygons loops;
- islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()));// jtSquare seems not working when expandign the holes
- for (size_t i = 0; !islands_ex.empty(); ++i) {
- for (ExPolygon &poly_ex : islands_ex)
- poly_ex.douglas_peucker(scaled_resolution);
- polygons_append(loops, to_polygons(islands_ex));// jtSquare seems not working when expandign the holes
- islands_ex = offset_ex(islands_ex, -1.3f * float(flow.scaled_spacing()));
- islands_ex = offset_ex(islands_ex, .3f * float(flow.scaled_spacing()));
- }
-
- loops = union_pt_chained_outside_in(loops);
- std::reverse(loops.begin(), loops.end());
- extrusion_entities_append_loops(brim.entities, std::move(loops), erBrim, float(flow.mm3_per_mm()),
- float(flow.width()), float(print.skirt_first_layer_height()));
-}
-
-// BBS: generate inner brim by objs
-static void make_inner_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim,
- std::map& brimAreaMap, std::map& supportBrimAreaMap,
- std::vector>& objPrintVec)
-{
- //BBS: generate brim for inner island first
-
-
-#ifdef INNER_ISLAND_BRIM_DEBUG_TO_SVG
- static int irun = 0;
- BoundingBox bbox_svg;
- bbox_svg.merge(get_extents(inner_islands_ex));
- {
- std::stringstream stri;
- stri << "inner_island_and_brim_area_" << irun << ".svg";
- SVG svg(stri.str(), bbox_svg);
- svg.draw(to_polylines(inner_islands_ex), "blue");
- svg.Close();
- }
- ++irun;
-#endif
-
- Flow flow = print.brim_flow();
- ExPolygons NoBrim = inner_brim_area(print, top_level_objects_with_brim,
- float(flow.scaled_spacing()), brimAreaMap, supportBrimAreaMap, objPrintVec);
-
- ExPolygons inner_islands_ex;
- std::map innerBrimAreaMap;
- std::map innerSupportBrimAreaMap;
- /*make_inner_island_brim(print, top_level_objects_with_brim, innerBrimAreaMap, innerSupportBrimAreaMap,
- inner_islands_ex, NoBrim, objPrintVec);*/
-
- //BBS: brim of hole must not overlap with inner island and inner island brim
- if (!inner_islands_ex.empty()) {
- if (brimAreaMap.size() > 0) {
- for (auto iter = brimAreaMap.begin(); iter != brimAreaMap.end(); ++iter) {
- if (!iter->second.empty()) {
- iter->second = diff_ex(iter->second, inner_islands_ex);
- };
- }
- }
- if (supportBrimAreaMap.size() > 0) {
- for (auto iter = supportBrimAreaMap.begin(); iter != supportBrimAreaMap.end(); ++iter) {
- if (!iter->second.empty()) {
- iter->second = diff_ex(iter->second, inner_islands_ex);
- };
- }
- }
- for (const PrintObject* object : print.objects()) {
- if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end()) {
- append(brimAreaMap[object->id()], innerBrimAreaMap[object->id()]);
- }
- if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) {
- append(supportBrimAreaMap[object->id()], innerSupportBrimAreaMap[object->id()]);
- }
- }
- }
-}
-
-
//BBS: generate out brim by offseting ExPolygons 'islands_area_ex'
-Polygons tryExPolygonOffset(const ExPolygons islandAreaEx, const Print& print)
+Polygons tryExPolygonOffset(const ExPolygons& islandAreaEx, const Print& print)
{
const auto scaled_resolution = scaled(print.config().resolution.value);
Polygons loops;
@@ -1718,8 +881,6 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
std::vector> &objPrintVec,
std::vector& printExtruders)
{
-
- double brim_width_max = 0;
std::map brim_width_map;
std::map brimAreaMap;
std::map supportBrimAreaMap;
@@ -1732,7 +893,10 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
for (const ObjectID printObjID : print.print_object_ids()) {
BoundingBox bbx;
PrintObject* object = const_cast(print.get_object(printObjID));
- for (const ExPolygon& ex_poly : object->layers().front()->lslices)
+ //ORCA: Use EFC-compensated outline for brim bounding box when enabled.
+ const ExPolygons brim_slices = use_brim_efc_outline(*object) ?
+ get_print_object_bottom_layer_expolygons(*object) : object->layers().front()->lslices;
+ for (const ExPolygon& ex_poly : brim_slices)
for (const PrintInstance& instance : object->instances()) {
auto ex_poly_translated = ex_poly;
ex_poly_translated.translate(instance.shift_without_plate_offset());
@@ -1774,9 +938,6 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
supportBrimMap.insert(std::make_pair(iter->first, makeBrimInfill(iter->second, print, islands_area)));
};
}
-
- size_t num_loops = size_t(floor(brim_width_max / flow.spacing()));
- BOOST_LOG_TRIVIAL(debug) << "brim_width_max, num_loops: " << brim_width_max << ", " << num_loops;
}
} // namespace Slic3r
diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp
index 2e6f7efd9d..a9b5099383 100644
--- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp
+++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp
@@ -162,8 +162,8 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
}
if (ext_lines.back().p == ext_lines.front().p) { // Connect endpoints.
- out.front().p = out.back().p;
- out.front().w = out.back().w;
+ out.back().p = out.front().p;
+ out.back().w = out.front().w;
}
if (out.size() >= 3)
diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp
index c585329079..eff83efe3e 100644
--- a/src/libslic3r/Fill/FillBase.cpp
+++ b/src/libslic3r/Fill/FillBase.cpp
@@ -1707,6 +1707,12 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vectorcontour_idx];
+
+ // Orca: If multiline infill is requested, skip connections that are too short.
+ if (params.multiline > 1 && arc.arc_length < scale_(spacing) * params.multiline) {
+ continue;
+ }
+
const std::vector &contour_params = graph.boundary_params[cp1->contour_idx];
if (polyline_idx1 != polyline_idx2) {
Polyline &polyline1 = infill_ordered[polyline_idx1];
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 707dadd9f9..0e07e3fdb8 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -3084,10 +3084,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_sorted_layer_filaments.emplace_back(lt.extruders);
}
- // Orca: finish tracking power lost recovery
+ // Orca: disable power loss recovery if it was enabled earlier
{
- if (m_second_layer_things_done && print.config().enable_power_loss_recovery.value == true) {
- file.write(m_writer.enable_power_loss_recovery(false));
+ const auto plr_mode = print.config().enable_power_loss_recovery.value;
+ if (m_second_layer_things_done && plr_mode == PowerLossRecoveryMode::Enable) {
+ file.write(m_writer.enable_power_loss_recovery(PowerLossRecoveryMode::Disable));
}
}
++ finished_objects;
@@ -3165,9 +3166,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_sorted_layer_filaments.emplace_back(lt.extruders);
}
- // Orca: finish tracking power lost recovery
- if (m_second_layer_things_done && print.config().enable_power_loss_recovery.value == true) {
- file.write(m_writer.enable_power_loss_recovery(false));
+ // Orca: disable power loss recovery
+ if (m_second_layer_things_done && print.config().enable_power_loss_recovery.value == PowerLossRecoveryMode::Enable) {
+ file.write(m_writer.enable_power_loss_recovery(PowerLossRecoveryMode::Disable));
}
if (m_wipe_tower)
// Purge the extruder, pull out the active filament.
@@ -4381,10 +4382,9 @@ LayerResult GCode::process_layer(
}
if (!first_layer && !m_second_layer_things_done) {
- // Orca: start tracking power lost recovery
- if (print.config().enable_power_loss_recovery.value == true) {
- gcode += m_writer.enable_power_loss_recovery(true);
- }
+ // Orca: set power loss recovery
+ const auto plr_mode = print.config().enable_power_loss_recovery.value;
+ gcode += m_writer.enable_power_loss_recovery(plr_mode);
if (print.is_BBL_printer()) {
// BBS: open first layer inspection at second layer
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index 9f7687d2c6..bd413d3782 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -1846,7 +1846,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
// sanity check
if(m_preheat_steps < 1)
m_preheat_steps = 1;
- m_result.backtrace_enabled = m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && filament_count > 1));
+ m_result.backtrace_enabled = config.ooze_prevention && m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && filament_count > 1));
assert(config.nozzle_volume.size() == config.nozzle_diameter.size());
m_nozzle_volume.resize(config.nozzle_volume.size());
diff --git a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
index e472b20794..20377cfe8d 100644
--- a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
+++ b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
@@ -15,7 +15,6 @@
#include "../PrintConfig.hpp"
#include "SmallAreaInfillFlowCompensator.hpp"
-#include "spline/spline.h"
#include
namespace Slic3r {
@@ -47,37 +46,43 @@ SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCo
}
} catch (...) {
std::stringstream ss;
- ss << "Error parsing data point in small area infill compensation model:" << line << std::endl;
+ ss << "Small Area Flow Compensation: Error parsing data point in small area infill compensation model:" << line << std::endl;
throw Slic3r::InvalidArgument(ss.str());
}
}
}
- for (int i = 0; i < eLengths.size(); i++) {
+ for (size_t i = 0; i < eLengths.size(); i++) {
if (i == 0) {
if (!nearly_equal(eLengths[i], 0.0)) {
- throw Slic3r::InvalidArgument("First extrusion length for small area infill compensation model must be 0");
+ throw Slic3r::InvalidArgument("Small Area Flow Compensation: First extrusion length for small area infill compensation model must be 0");
}
} else {
if (nearly_equal(eLengths[i], 0.0)) {
- throw Slic3r::InvalidArgument("Only the first extrusion length for small area infill compensation model can be 0");
+ throw Slic3r::InvalidArgument("Small Area Flow Compensation: Only the first extrusion length for small area infill compensation model can be 0");
}
if (eLengths[i] <= eLengths[i - 1]) {
- throw Slic3r::InvalidArgument("Extrusion lengths for subsequent points must be increasing");
+ throw Slic3r::InvalidArgument("Small Area Flow Compensation: Extrusion lengths for subsequent points must be increasing");
}
}
}
- if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) {
- throw Slic3r::InvalidArgument("Final compensation factor for small area infill flow compensation model must be 1.0");
+ for (size_t i = 1; i < flowComps.size(); ++i) {
+ if (flowComps[i] <= flowComps[i - 1]) {
+ throw Slic3r::InvalidArgument("Small Area Flow Compensation: Flow compensation factors must strictly increase with extrusion length");
+ }
}
- flowModel = std::make_unique();
- flowModel->set_points(eLengths, flowComps);
+ if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) {
+ throw Slic3r::InvalidArgument("Small Area Flow Compensation: Final compensation factor for small area infill flow compensation model must be 1.0");
+ }
+
+ flowModel = std::make_unique(eLengths, flowComps);
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Error parsing small area infill compensation model: " << e.what();
+ throw;
}
}
@@ -92,7 +97,7 @@ double SmallAreaInfillFlowCompensator::flow_comp_model(const double line_length)
return 1.0;
}
- return (*flowModel)(line_length);
+ return flowModel->interpolate(line_length);
}
double SmallAreaInfillFlowCompensator::modify_flow(const double line_length, const double dE, const ExtrusionRole role)
diff --git a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
index 1bfa5149f7..de1df98170 100644
--- a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
+++ b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
@@ -4,12 +4,9 @@
#include "../libslic3r.h"
#include "../PrintConfig.hpp"
#include "../ExtrusionEntity.hpp"
+#include "PchipInterpolatorHelper.hpp"
#include
-namespace tk {
-class spline;
-} // namespace tk
-
namespace Slic3r {
class SmallAreaInfillFlowCompensator
@@ -26,8 +23,7 @@ private:
std::vector eLengths;
std::vector flowComps;
- // TODO: Cubic Spline
- std::unique_ptr flowModel;
+ std::unique_ptr flowModel;
double flow_comp_model(const double line_length);
diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp
index cf5a68b436..6bec4168f4 100644
--- a/src/libslic3r/GCode/WipeTower2.cpp
+++ b/src/libslic3r/GCode/WipeTower2.cpp
@@ -1215,6 +1215,10 @@ WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
result.extrusions = std::move(writer.extrusions());
result.wipe_path = std::move(writer.wipe_path());
result.is_finish_first = is_finish;
+ // ORCA: Always initialize the tool_change_start_pos with a valid position
+ // to avoid undefined variable travel on X in Gcode.cpp function std::string WipeTowerIntegration::post_process_wipe_tower_moves
+ result.tool_change_start_pos = result.start_pos; // always valid fallback
+
return result;
}
diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp
index 3dbc066634..6242b634a8 100644
--- a/src/libslic3r/GCode/WipeTower2.hpp
+++ b/src/libslic3r/GCode/WipeTower2.hpp
@@ -58,10 +58,18 @@ public:
std::vector> get_z_and_depth_pairs() const;
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
float get_wipe_tower_height() const { return m_wipe_tower_height; }
-
-
-
-
+ // ORCA: Match WipeTower API used by Print skirt/brim planning.
+ // Returned bounding box is in WIPE-TOWER-LOCAL coordinates (before placement on the bed).
+ // Include brim and y-shift to match what WT gcode actually prints.
+ BoundingBoxf get_bbx() const{
+ const float brim = m_wipe_tower_brim_width_real;
+ const Vec2d min(-brim, -brim + double(m_y_shift));
+ const Vec2d max(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim + double(m_y_shift));
+ return BoundingBoxf(min, max);
+ }
+ // WT2 doesn't currently compute a rib-origin compensation like WipeTower (m_rib_offset),
+ // so expose a zero offset for consistency purposes (to maintain API parity).
+ Vec2f get_rib_offset() const { return Vec2f::Zero(); }
// Switch to a next layer.
void set_layer(
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index f3d218750b..1008e5eab1 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -444,23 +444,28 @@ std::string GCodeWriter::reset_e(bool force)
}
}
-std::string GCodeWriter::enable_power_loss_recovery(bool enable)
+std::string GCodeWriter::enable_power_loss_recovery(PowerLossRecoveryMode mode)
{
std::ostringstream gcode;
-
+
+ if (mode == PowerLossRecoveryMode::PrinterConfiguration)
+ return std::string();
+
+ const bool enable = mode == PowerLossRecoveryMode::Enable;
+
if (m_is_bbl_printers) {
- gcode << "; start tracking Power Loss Recovery https://wiki.bambulab.com/en/knowledge-sharing/power-loss-recovery\n";
- gcode << "M1003 S" << (enable ? "1" : "0") << "\n";
+ gcode << "M1003 S" << (enable ? "1" : "0");
}
else if (FLAVOR_IS(gcfMarlinFirmware)) {
- gcode << "; start tracking Power-loss Recovery https://marlinfw.org/docs/gcode/M413.html\n";
- gcode << "M413 S" << (enable ? "1" : "0") << "\n";
+ gcode << "M413 S" << (enable ? "1" : "0");
+ } else {
+ return std::string();
}
-
+ if (GCodeWriter::full_gcode_comment) gcode << " ; set Power-loss Recovery";
+ gcode << "\n";
return gcode.str();
}
-
std::string GCodeWriter::update_progress(unsigned int num, unsigned int tot, bool allow_100) const
{
if (FLAVOR_IS_NOT(gcfMakerWare) && FLAVOR_IS_NOT(gcfSailfish))
diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp
index 32e737164d..dbc64694e2 100644
--- a/src/libslic3r/GCodeWriter.hpp
+++ b/src/libslic3r/GCodeWriter.hpp
@@ -61,7 +61,7 @@ public:
std::string set_input_shaping(char axis, float damp, float freq, std::string type) const;
std::string reset_e(bool force = false);
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
- std::string enable_power_loss_recovery(bool enable);
+ std::string enable_power_loss_recovery(PowerLossRecoveryMode mode);
// return false if this extruder was already selected
bool need_toolchange(unsigned int filament_id) const;
std::string set_extruder(unsigned int filament_id);
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index 3ca75d28f3..4e78b31b46 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -904,7 +904,7 @@ static std::vector s_Preset_print_options {
"top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed",
"bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed",
"outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield",
- "brim_width", "brim_object_gap", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
+ "brim_width", "brim_object_gap", "brim_use_efc_outline", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers",
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
"support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style",
// BBS
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 330b489141..7a0a6dd867 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -3333,6 +3333,8 @@ void Print::_make_wipe_tower()
m_wipe_tower_data.z_and_depth_pairs = wipe_tower.get_z_and_depth_pairs();
m_wipe_tower_data.brim_width = wipe_tower.get_brim_width();
m_wipe_tower_data.height = wipe_tower.get_wipe_tower_height();
+ m_wipe_tower_data.bbx = wipe_tower.get_bbx();
+ m_wipe_tower_data.rib_offset = wipe_tower.get_rib_offset();
// Unload the current filament over the purge tower.
coordf_t layer_height = m_objects.front()->config().layer_height.value;
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 37fc895411..7549eb821d 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -161,6 +161,14 @@ static t_config_enum_values s_keys_map_BedTempFormula {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BedTempFormula)
+// Orca
+static t_config_enum_values s_keys_map_PowerLossRecoveryMode {
+ { "printer_configuration", int(PowerLossRecoveryMode::PrinterConfiguration) },
+ { "enable", int(PowerLossRecoveryMode::Enable) },
+ { "disable", int(PowerLossRecoveryMode::Disable) }
+};
+CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PowerLossRecoveryMode)
+
static t_config_enum_values s_keys_map_FuzzySkinType {
{ "none", int(FuzzySkinType::None) },
{ "external", int(FuzzySkinType::External) },
@@ -1562,6 +1570,16 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.));
+ def = this->add("brim_use_efc_outline", coBool);
+ def->label = L("Brim follows compensated outline");
+ def->category = L("Support");
+ def->tooltip = L("When enabled, the brim is aligned with the first-layer perimeter geometry after Elephant Foot Compensation is applied.\n"
+ "This option is intended for cases where Elephant Foot Compensation significantly alters the first-layer footprint.\n"
+ "\n"
+ "If your current setup already works well, enabling it may be unnecessary and can cause the brim to fuse with upper layers." );
+ def->mode = comAdvanced;
+ def->set_default_value(new ConfigOptionBool(false));
+
def = this->add("brim_ears", coBool);
def->label = L("Brim ears");
def->category = L("Support");
@@ -3366,11 +3384,18 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionBool(false));
// Orca
- def = this->add("enable_power_loss_recovery", coBool);
- def->label = L("Turn on Power Loss Recovery");
- def->tooltip = L("Enable this to insert power loss recovery commands in generated G-code.(Only for Bambu Lab printers and Marlin firmware based printers)");
+ def = this->add("enable_power_loss_recovery", coEnum);
+ def->label = L("Power Loss Recovery");
+ def->tooltip = L("Choose how to control power loss recovery. When set to Printer configuration, the slicer will not emit power loss recovery G-code and will leave the printer's configuration unchanged. Applicable to Bambu Lab or Marlin 2 firmware based printers.");
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionBool(false));
+ def->enum_keys_map = &ConfigOptionEnum::get_enum_values();
+ def->enum_values.push_back("printer_configuration");
+ def->enum_values.push_back("enable");
+ def->enum_values.push_back("disable");
+ def->enum_labels.push_back(L("Printer configuration"));
+ def->enum_labels.push_back(L("Enable"));
+ def->enum_labels.push_back(L("Disable"));
+ def->set_default_value(new ConfigOptionEnum(PowerLossRecoveryMode::PrinterConfiguration));
//BBS
// def = this->add("spaghetti_detector", coBool);
@@ -7432,6 +7457,13 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
else if (opt_key == "extruder_type") {
ReplaceString(value, "DirectDrive", "Direct Drive");
}
+ else if (opt_key == "enable_power_loss_recovery") {
+ if (value == "1" || boost::iequals(value, "true")) {
+ value = "enable";
+ } else if (value == "0" || boost::iequals(value, "false")) {
+ value = "disable";
+ }
+ }
else if(opt_key == "ensure_vertical_shell_thickness") {
if(value == "1") {
value = "ensure_all";
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 3e34a8362b..998764f292 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -102,6 +102,13 @@ enum class BedTempFormula {
count,
};
+// Orca
+enum class PowerLossRecoveryMode {
+ PrinterConfiguration,
+ Enable,
+ Disable,
+};
+
// BBS
enum class WallSequence {
InnerOuter,
@@ -507,6 +514,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrintHostType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AuthorizationType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(WipeTowerWallType)
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType)
+CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PowerLossRecoveryMode)
#undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS
@@ -874,6 +882,7 @@ PRINT_CONFIG_CLASS_DEFINE(
PrintObjectConfig,
((ConfigOptionFloat, brim_object_gap))
+ ((ConfigOptionBool, brim_use_efc_outline))
((ConfigOptionEnum, brim_type))
((ConfigOptionFloat, brim_width))
((ConfigOptionFloat, brim_ears_detection_length))
@@ -1271,7 +1280,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionIntsNullable, filament_flush_temp))
// BBS
((ConfigOptionBool, scan_first_layer))
- ((ConfigOptionBool, enable_power_loss_recovery))
+ ((ConfigOptionEnum, enable_power_loss_recovery))
((ConfigOptionBool, enable_wrapping_detection))
((ConfigOptionInt, wrapping_detection_layers))
((ConfigOptionPoints, wrapping_exclude_area))
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 7cc98209cf..4b4237dca1 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1006,6 +1006,7 @@ bool PrintObject::invalidate_state_by_config_options(
for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "brim_width"
|| opt_key == "brim_object_gap"
+ || opt_key == "brim_use_efc_outline"
|| opt_key == "brim_type"
|| opt_key == "brim_ears_max_angle"
|| opt_key == "brim_ears_detection_length"
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 5529cd04c5..e6f28b68fe 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -494,6 +494,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Widgets/ErrorMsgStaticText.hpp
GUI/Widgets/FanControl.cpp
GUI/Widgets/FanControl.hpp
+ GUI/Widgets/HyperLink.cpp
+ GUI/Widgets/HyperLink.hpp
GUI/Widgets/ImageSwitchButton.cpp
GUI/Widgets/ImageSwitchButton.hpp
GUI/Widgets/Label.cpp
diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp
index a649f6b833..19a32c2d21 100644
--- a/src/slic3r/GUI/AMSMaterialsSetting.cpp
+++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp
@@ -298,11 +298,7 @@ void AMSMaterialsSetting::create_panel_kn(wxWindow* parent)
if (language.find("zh") == 0)
region = "zh";
wxString link_url = wxString::Format("https://wiki.bambulab.com/%s/software/bambu-studio/calibration_pa", region);
- m_wiki_ctrl = new wxHyperlinkCtrl(parent, wxID_ANY, "Wiki", link_url);
- m_wiki_ctrl->SetNormalColour(*wxBLUE);
- m_wiki_ctrl->SetHoverColour(wxColour(0, 0, 200));
- m_wiki_ctrl->SetVisitedColour(*wxBLUE);
- m_wiki_ctrl->SetFont(Label::Head_14);
+ m_wiki_ctrl = new HyperLink(parent, "Wiki Guide", link_url);
cali_title_sizer->Add(m_ratio_text, 0, wxALIGN_CENTER_VERTICAL);
cali_title_sizer->Add(m_wiki_ctrl, 0, wxALIGN_CENTER_VERTICAL);
diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp
index c678ec0717..84688896e6 100644
--- a/src/slic3r/GUI/AMSMaterialsSetting.hpp
+++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp
@@ -14,8 +14,8 @@
#include "Widgets/CheckBox.hpp"
#include "Widgets/ComboBox.hpp"
#include "Widgets/TextInput.hpp"
+#include "Widgets/HyperLink.hpp"
#include "slic3r/Utils/CalibUtils.hpp"
-#include
#define AMS_MATERIALS_SETTING_DEF_COLOUR wxColour(255, 255, 255)
#define AMS_MATERIALS_SETTING_GREY900 wxColour(38, 46, 48)
@@ -174,7 +174,7 @@ protected:
wxPanel * m_panel_kn;
wxStaticText* m_ratio_text;
- wxHyperlinkCtrl * m_wiki_ctrl;
+ HyperLink * m_wiki_ctrl;
wxStaticText* m_k_param;
TextInput* m_input_k_val;
wxStaticText* m_n_param;
diff --git a/src/slic3r/GUI/BindDialog.cpp b/src/slic3r/GUI/BindDialog.cpp
index 7610fbe820..3847f8f2f1 100644
--- a/src/slic3r/GUI/BindDialog.cpp
+++ b/src/slic3r/GUI/BindDialog.cpp
@@ -98,18 +98,8 @@ PingCodeBindDialog::PingCodeBindDialog(Plater* plater /*= nullptr*/)
m_status_text->Wrap(FromDIP(440));
m_status_text->SetForegroundColour(wxColour(38, 46, 48));
- m_link_show_ping_code_wiki = new wxStaticText(request_bind_panel, wxID_ANY, _L("Can't find Pin Code?"));
- m_link_show_ping_code_wiki->SetFont(Label::Body_14);
- m_link_show_ping_code_wiki->SetBackgroundColour(*wxWHITE);
- m_link_show_ping_code_wiki->SetForegroundColour(wxColour(31, 142, 234));
-
- m_link_show_ping_code_wiki->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
- m_link_show_ping_code_wiki->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
-
- m_link_show_ping_code_wiki->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
- m_ping_code_wiki = "https://wiki.bambulab.com/en/bambu-studio/manual/pin-code";
- wxLaunchDefaultBrowser(m_ping_code_wiki);
- });
+ // ORCA standardized HyperLink
+ m_link_show_ping_code_wiki = new HyperLink(request_bind_panel, _L("Can't find Pin Code?"), "https://wiki.bambulab.com/en/bambu-studio/manual/pin-code");
m_text_input_title = new wxStaticText(request_bind_panel, wxID_ANY, _L("Pin Code"));
m_text_input_title->SetFont(Label::Body_14);
@@ -453,11 +443,11 @@ PingCodeBindDialog::~PingCodeBindDialog() {
m_st_privacy_title->SetFont(Label::Body_13);
m_st_privacy_title->SetForegroundColour(wxColour(38, 46, 48));
- auto m_link_Terms_title = new Label(m_panel_agreement, _L("Terms and Conditions"));
+ // ORCA standardized HyperLink
+ auto m_link_Terms_title = new HyperLink(m_panel_agreement, _L("Terms and Conditions"));
m_link_Terms_title->SetFont(Label::Head_13);
m_link_Terms_title->SetMaxSize(wxSize(FromDIP(450), -1));
m_link_Terms_title->Wrap(FromDIP(450));
- m_link_Terms_title->SetForegroundColour(wxColour("#009688"));
m_link_Terms_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
wxString txt = _L("Thank you for purchasing a Bambu Lab device. Before using your Bambu Lab device, please read the terms and conditions. "
"By clicking to agree to use your Bambu Lab device, you agree to abide by the Privacy Policy and Terms of Use (collectively, the \"Terms\"). "
@@ -467,18 +457,16 @@ PingCodeBindDialog::~PingCodeBindDialog() {
confirm_dlg.CenterOnParent();
confirm_dlg.on_show();
});
- m_link_Terms_title->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
- m_link_Terms_title->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
auto m_st_and_title = new Label(m_panel_agreement, _L("and"));
m_st_and_title->SetFont(Label::Body_13);
m_st_and_title->SetForegroundColour(wxColour(38, 46, 48));
- auto m_link_privacy_title = new Label(m_panel_agreement, _L("Privacy Policy"));
+ // ORCA standardized HyperLink
+ auto m_link_privacy_title = new HyperLink(m_panel_agreement, _L("Privacy Policy"));
m_link_privacy_title->SetFont(Label::Head_13);
m_link_privacy_title->SetMaxSize(wxSize(FromDIP(450), -1));
m_link_privacy_title->Wrap(FromDIP(450));
- m_link_privacy_title->SetForegroundColour(wxColour("#009688"));
m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
std::string url;
std::string country_code = Slic3r::GUI::wxGetApp().app_config->get_country_code();
@@ -491,8 +479,6 @@ PingCodeBindDialog::~PingCodeBindDialog() {
}
wxLaunchDefaultBrowser(url);
});
- m_link_privacy_title->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND);});
- m_link_privacy_title->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW);});
sizere_notice_agreement->Add(0, 0, 0, wxTOP, FromDIP(4));
sizer_privacy_agreement->Add(m_st_privacy_title, 0, wxALIGN_CENTER, 0);
@@ -514,13 +500,11 @@ PingCodeBindDialog::~PingCodeBindDialog() {
m_st_notice_title->SetFont(Label::Body_13);
m_st_notice_title->SetForegroundColour(wxColour(38, 46, 48));
- auto m_link_notice_title = new Label(m_panel_agreement, notice_link_title);
+ // ORCA standardized HyperLink
+ auto m_link_notice_title = new HyperLink(m_panel_agreement, notice_link_title);
m_link_notice_title->SetFont(Label::Head_13);
m_link_notice_title->SetMaxSize(wxSize(FromDIP(450), -1));
m_link_notice_title->Wrap(FromDIP(450));
- m_link_notice_title->SetForegroundColour(wxColour("#009688"));
- m_link_notice_title->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
- m_link_notice_title->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
m_link_notice_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
wxString txt = _L("In the 3D Printing community, we learn from each other's successes and failures to adjust "
"our own slicing parameters and settings. %s follows the same principle and uses machine "
@@ -580,13 +564,8 @@ PingCodeBindDialog::~PingCodeBindDialog() {
wxBoxSizer* m_sizer_bind_failed_info = new wxBoxSizer(wxVERTICAL);
m_sw_bind_failed_info->SetSizer( m_sizer_bind_failed_info );
- m_link_network_state = new wxHyperlinkCtrl(m_sw_bind_failed_info, wxID_ANY,_L("Check the status of current system services"),"");
- m_link_network_state->SetFont(::Label::Body_12);
- m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
- m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); });
- m_link_network_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_ARROW); });
-
-
+ // ORCA standardized HyperLink
+ m_link_network_state = new HyperLink(m_sw_bind_failed_info, _L("Check the status of current system services"), wxGetApp().link_to_network_check());
wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL);
diff --git a/src/slic3r/GUI/BindDialog.hpp b/src/slic3r/GUI/BindDialog.hpp
index a4ffd8fbff..b809bc523b 100644
--- a/src/slic3r/GUI/BindDialog.hpp
+++ b/src/slic3r/GUI/BindDialog.hpp
@@ -17,13 +17,13 @@
#include
#include
#include
-#include
#include "wxExtensions.hpp"
#include "Widgets/StepCtrl.hpp"
#include "Widgets/ProgressDialog.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/ProgressBar.hpp"
#include "Widgets/RoundedRectangle.hpp"
+#include "Widgets/HyperLink.hpp"
#include "Jobs/BindJob.hpp"
#include "BBLStatusBar.hpp"
#include "BBLStatusBarBind.hpp"
@@ -56,7 +56,7 @@ private:
Label* m_status_text;
wxStaticText* m_text_input_title;
- wxStaticText* m_link_show_ping_code_wiki;
+ HyperLink* m_link_show_ping_code_wiki; // ORCA
TextInput* m_text_input_single_code[PING_CODE_LENGTH];
Button* m_button_bind;
Button* m_button_cancel;
@@ -70,7 +70,7 @@ private:
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
- wxHyperlinkCtrl* m_link_network_state{ nullptr };
+ HyperLink* m_link_network_state{ nullptr };
wxString m_result_info;
wxString m_result_extra;
wxString m_ping_code_wiki;
@@ -114,7 +114,7 @@ private:
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
- wxHyperlinkCtrl* m_link_network_state{ nullptr };
+ HyperLink* m_link_network_state{ nullptr };
wxString m_result_info;
wxString m_result_extra;
bool m_show_error_info_state = true;
diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp
index 055cbe905d..12162615aa 100644
--- a/src/slic3r/GUI/CalibrationPanel.cpp
+++ b/src/slic3r/GUI/CalibrationPanel.cpp
@@ -269,7 +269,7 @@ void SelectMObjectPopup::Popup(wxWindow* WXUNUSED(focus))
}
}
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxTimerEvent(*m_refresh_timer));
PopupWindow::Popup();
}
@@ -505,7 +505,7 @@ void CalibrationPanel::init_timer()
m_refresh_timer = new wxTimer();
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(REFRESH_INTERVAL);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxCommandEvent(wxEVT_TIMER));
}
void CalibrationPanel::on_timer(wxTimerEvent& event) {
@@ -634,7 +634,7 @@ bool CalibrationPanel::Show(bool show) {
m_refresh_timer->Stop();
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(REFRESH_INTERVAL);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxCommandEvent(wxEVT_TIMER));
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (dev) {
diff --git a/src/slic3r/GUI/CalibrationWizardPage.cpp b/src/slic3r/GUI/CalibrationWizardPage.cpp
index 3da543e79d..13e7023190 100644
--- a/src/slic3r/GUI/CalibrationWizardPage.cpp
+++ b/src/slic3r/GUI/CalibrationWizardPage.cpp
@@ -466,21 +466,12 @@ void CaliPageCaption::init_bitmaps() {
void CaliPageCaption::create_wiki(wxWindow* parent)
{
- m_wiki_text = new Label(parent, _L("Wiki"));
- m_wiki_text->SetFont(Label::Head_14);
- m_wiki_text->SetForegroundColour({ 0, 88, 220 });
- m_wiki_text->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& e) {
- e.Skip();
- SetCursor(wxCURSOR_HAND);
- });
- m_wiki_text->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) {
- e.Skip();
- SetCursor(wxCURSOR_ARROW);
- });
+ // ORCA standardized HyperLink
+ m_wiki_text = new HyperLink(parent, _L("Wiki Guide"));
m_wiki_text->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) {
if (!m_wiki_url.empty())
wxLaunchDefaultBrowser(m_wiki_url);
- });
+ });
}
void CaliPageCaption::show_prev_btn(bool show)
diff --git a/src/slic3r/GUI/CalibrationWizardPage.hpp b/src/slic3r/GUI/CalibrationWizardPage.hpp
index d03979cd55..524b1a6029 100644
--- a/src/slic3r/GUI/CalibrationWizardPage.hpp
+++ b/src/slic3r/GUI/CalibrationWizardPage.hpp
@@ -7,6 +7,7 @@
#include "Widgets/TextInput.hpp"
#include "Widgets/AMSControl.hpp"
#include "Widgets/ProgressBar.hpp"
+#include "Widgets/HyperLink.hpp"
#include "wxExtensions.hpp"
#include "PresetComboBoxes.hpp"
@@ -140,7 +141,7 @@ private:
void init_bitmaps();
void create_wiki(wxWindow* parent);
- Label* m_wiki_text;
+ HyperLink* m_wiki_text; // ORCA
wxString m_wiki_url;
ScalableBitmap m_prev_bmp_normal;
ScalableBitmap m_prev_bmp_hover;
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index 6c5fa69534..90944e673e 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -705,6 +705,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
bool have_brim = (config->opt_enum("brim_type") != btNoBrim);
toggle_field("brim_object_gap", have_brim);
+ toggle_field("brim_use_efc_outline", have_brim);
bool have_brim_width = (config->opt_enum("brim_type") != btNoBrim) && config->opt_enum("brim_type") != btAutoBrim &&
config->opt_enum("brim_type") != btPainted;
toggle_field("brim_width", have_brim_width);
diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp
index 7eb3beda82..269cd6ed12 100644
--- a/src/slic3r/GUI/CreatePresetsDialog.cpp
+++ b/src/slic3r/GUI/CreatePresetsDialog.cpp
@@ -17,6 +17,7 @@
#include "Tab.hpp"
#include "MainFrame.hpp"
#include "libslic3r_version.h"
+#include "Widgets/HyperLink.hpp" // ORCA
#define NAME_OPTION_COMBOBOX_SIZE wxSize(FromDIP(200), FromDIP(24))
#define FILAMENT_PRESET_COMBOBOX_SIZE wxSize(FromDIP(300), FromDIP(24))
@@ -5027,8 +5028,8 @@ wxPanel *PresetTree::get_child_item(wxPanel *parent, std::shared_ptr pre
bool base_id_error = false;
if (preset->inherits() == "" && preset->base_id != "") base_id_error = true;
if (base_id_error) {
- std::string wiki_url = "https://wiki.bambulab.com/en/software/bambu-studio/custom-filament-issue";
- wxHyperlinkCtrl *m_download_hyperlink = new wxHyperlinkCtrl(panel, wxID_ANY, _L("[Delete Required]"), wiki_url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
+ // ORCA standardized HyperLink
+ HyperLink *m_download_hyperlink = new HyperLink(panel, _L("[Delete Required]"), "https://wiki.bambulab.com/en/software/bambu-studio/custom-filament-issue");
m_download_hyperlink->SetFont(Label::Body_10);
sizer->Add(m_download_hyperlink, 0, wxEXPAND | wxALL, 5);
}
diff --git a/src/slic3r/GUI/DownloadProgressDialog.cpp b/src/slic3r/GUI/DownloadProgressDialog.cpp
index 76ef7afa92..7ded82037e 100644
--- a/src/slic3r/GUI/DownloadProgressDialog.cpp
+++ b/src/slic3r/GUI/DownloadProgressDialog.cpp
@@ -24,6 +24,8 @@
#include "Jobs/BoostThreadWorker.hpp"
#include "Jobs/PlaterWorker.hpp"
+#include "Widgets/HyperLink.hpp" // ORCA
+
#define DESIGN_INPUT_SIZE wxSize(FromDIP(100), -1)
namespace Slic3r {
@@ -73,7 +75,8 @@ DownloadProgressDialog::DownloadProgressDialog(wxString title)
sizer_download_failed->Add(m_statictext_download_failed, 0, wxALIGN_CENTER | wxALL, 5);
- auto m_download_hyperlink = new wxHyperlinkCtrl(m_panel_download_failed, wxID_ANY, _L("click here to see more info"), download_failed_url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
+ // ORCA standardized HyperLink
+ auto m_download_hyperlink = new HyperLink(m_panel_download_failed, _L("click here to see more info"), download_failed_url);
sizer_download_failed->Add(m_download_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
@@ -94,7 +97,8 @@ DownloadProgressDialog::DownloadProgressDialog(wxString title)
sizer_install_failed->Add(m_statictext_install_failed, 0, wxALIGN_CENTER | wxALL, 5);
- auto m_install_hyperlink = new wxHyperlinkCtrl(m_panel_install_failed, wxID_ANY, _L("click here to see more info"), install_failed_url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
+ // ORCA standardized HyperLink
+ auto m_install_hyperlink = new HyperLink(m_panel_install_failed, _L("click here to see more info"), install_failed_url);
sizer_install_failed->Add(m_install_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
diff --git a/src/slic3r/GUI/FilamentGroupPopup.cpp b/src/slic3r/GUI/FilamentGroupPopup.cpp
index 89c9dbd8de..df78e69a80 100644
--- a/src/slic3r/GUI/FilamentGroupPopup.cpp
+++ b/src/slic3r/GUI/FilamentGroupPopup.cpp
@@ -147,15 +147,10 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w
{
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
- const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html";
+ const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html"; // NEEDFIX this link is broken
auto* wiki_sizer = new wxBoxSizer(wxHORIZONTAL);
- wiki_link = new wxStaticText(this, wxID_ANY, _L("Learn more"));
- wiki_link->SetBackgroundColour(BackGroundColor);
- wiki_link->SetForegroundColour(GreenColor);
- wiki_link->SetFont(Label::Body_12.Underlined());
- wiki_link->SetCursor(wxCursor(wxCURSOR_HAND));
- wiki_link->Bind(wxEVT_LEFT_DOWN, [wiki_path](wxMouseEvent &) { wxLaunchDefaultBrowser(wxString(wiki_path.c_str())); });
+ wiki_link = new HyperLink(this, _L("Wiki Guide"), wxString(wiki_path.c_str())); // ORCA
wiki_sizer->Add(wiki_link, 0, wxALIGN_CENTER | wxALL, FromDIP(3));
button_sizer->Add(wiki_sizer, 0, wxLEFT, horizontal_margin);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 00d15ddadd..ce859e1a7b 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -6044,6 +6044,7 @@ static const float cameraProjection[16] = {1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.
void GLCanvas3D::_render_3d_navigator()
{
if (!wxGetApp().show_3d_navigator()) {
+ m_canvas_toolbar_pos[0] = 0;
return;
}
@@ -6090,7 +6091,7 @@ void GLCanvas3D::_render_3d_navigator()
}
const float size = 128 * sc;
- m_axis_button_pos[0] = size - 10;
+ m_canvas_toolbar_pos[0] = size;
const auto result = ImGuizmo::ViewManipulate(cameraView, cameraProjection, ImGuizmo::OPERATION::ROTATE, ImGuizmo::MODE::WORLD, nullptr,
camDistance, ImVec2(viewManipulateLeft, viewManipulateTop - size), ImVec2(size, size),
0x00101010);
@@ -6126,7 +6127,6 @@ void GLCanvas3D::_render_3d_navigator()
request_extra_frame();
}
- _render_camera_toolbar();
}
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT 0
@@ -7989,6 +7989,8 @@ void GLCanvas3D::_render_overlays()
m_labels.render(sorted_instances);
_render_3d_navigator();
+
+ _render_canvas_toolbar();
}
void GLCanvas3D::_render_style_editor()
@@ -8627,47 +8629,169 @@ void GLCanvas3D::_render_return_toolbar() const
imgui.end();
}
-void GLCanvas3D::_render_camera_toolbar()
+void GLCanvas3D::_render_canvas_toolbar()
{
- float font_size = ImGui::GetFontSize();
- float sc = get_scale();
- ImVec2 button_icon_size = ImVec2(font_size * 2.5, font_size * 2.5);
+ ImGuiWrapper &imgui = *wxGetApp().imgui();
+ float sc = get_scale();
- ImGuiWrapper &imgui = *wxGetApp().imgui();
- float window_width = button_icon_size.x + imgui.scaled(2.0f);
- float window_height = button_icon_size.y + imgui.scaled(2.0f);
+ #ifdef WIN32
+ const int dpi = get_dpi_for_window(wxGetApp().GetTopWindow());
+ sc *= (float) dpi / (float) DPI_DEFAULT;
+ #endif // WIN32
- Size cnv_size = get_canvas_size();
- m_axis_button_pos[1] = cnv_size.get_height() - button_icon_size[1] - 20 * sc;
- imgui.set_next_window_pos(m_axis_button_pos[0], m_axis_button_pos[1], ImGuiCond_Always, 0, 0);
-#ifdef __WINDOWS__
- imgui.set_next_window_size(window_width, window_height, ImGuiCond_Always);
-#endif
+ ImVec2 btn_size = ImVec2(36.f, 36.f) * sc;
+ ImVec2 margin = ImVec2(m_canvas_toolbar_pos[0] > 0 ? 0.f : (10.f * sc), 10.f * sc);
+ ImVec2 spacing = ImVec2(6.f, 6.f) * sc;
+ ImVec2 padding = ImVec2(2.f, 2.f) * sc;
+ Vec2i32 pos = {
+ m_canvas_toolbar_pos[0] + margin.x,
+ get_canvas_size().get_height() - margin.y
+ };
+ bool zoom_btn = wxGetApp().show_canvas_zoom_button();
- imgui.begin(_L("Toggle Axis"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove |
+ imgui.set_next_window_pos(pos[0], pos[1], ImGuiCond_Always, 0, 1); // pivot bottom-left
+
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0 );
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , {0,0});
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing , {0,0});
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding , padding); // without padding images clipping
+
+ imgui.begin(_L("Canvas Toolbar"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse);//
- ImTextureID normal_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_AXIS_TOGGLE_DARK : GLGizmosManager::MENU_ICON_NAME::IC_AXIS_TOGGLE);
- ImTextureID hover_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_AXIS_TOGGLE_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_AXIS_TOGGLE_HOVER);
+ ImTextureID m_normal_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_DARK : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU);
+ ImTextureID m_hover_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_HOVER);
- ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0});
-
- if (ImGui::ImageButton3(normal_id, hover_id, button_icon_size, ImVec2(0, 0), ImVec2(1, 1), -1,
- ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1), ImVec2(10, 0))) {
- //select_view("plate");
-
- if (m_canvas_type == ECanvasType::CanvasView3D || m_canvas_type == ECanvasType::CanvasPreview) {
- toggle_world_axes_visibility(false);
+ if (ImGui::ImageButton3(m_normal_id, m_hover_id, btn_size)) {
+ if(!ImGui::IsPopupOpen("CanvasToolbarMenu")){
+ ImGui::SetNextWindowPos(ImVec2(pos[0] + padding.x, pos[1] - padding.y - (zoom_btn ? (btn_size.y + spacing.y) : 0.f)), ImGuiCond_Always, ImVec2(0, 1)); // pivot bottom-left
+ ImGui::OpenPopup("CanvasToolbarMenu");
}
+ }
+ if(zoom_btn){
+ ImGui::Dummy({ 0, spacing.y});
+
+ ImTextureID z_normal_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_ZOOM_DARK : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_ZOOM);
+ ImTextureID z_hover_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_ZOOM_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_ZOOM_HOVER);
+
+ if (ImGui::ImageButton3(z_normal_id, z_hover_id, btn_size)) {
+ select_view("plate");
+ if (m_selection.is_empty()) {
+ if (m_canvas_type == ECanvasType::CanvasAssembleView)
+ zoom_to_volumes();
+ else
+ zoom_to_bed();
+ } else {
+ zoom_to_selection();
+ }
+ } else if (ImGui::IsItemHovered()) {
+ auto tooltip = _L("Fit camera to scene or selected object.");
+ auto width = ImGui::CalcTextSize(tooltip.c_str()).x + imgui.scaled(2.0f);
+ imgui.tooltip(tooltip, width);
+ }
}
- if (ImGui::IsItemHovered()) {
- auto temp_tooltip = _L("Toggle Axis");
- auto width = ImGui::CalcTextSize(temp_tooltip.c_str()).x + imgui.scaled(2.0f);
- imgui.tooltip(temp_tooltip, width);
+
+ ImGui::PopStyleVar(4); // Window
+
+ ImGui::PushStyleColor(ImGuiCol_PopupBg , m_is_dark ? ImGuiWrapper::COL_TOOLBAR_BG_DARK : ImGuiWrapper::COL_TOOLBAR_BG);
+ ImGui::PushStyleColor(ImGuiCol_Separator , m_is_dark ? ImVec4(1, 1, 1, .20f) : ImVec4(0, 0, 0, .2f));
+ ImGui::PushStyleColor(ImGuiCol_Text , m_is_dark ? ImVec4(1, 1, 1, .88f) : ImVec4(50 / 255.f, 58 / 255.f, 61 / 255.f, 1.f));
+ ImGui::PushStyleColor(ImGuiCol_TextDisabled , m_is_dark ? ImVec4(1, 1, 1, .44f) : ImVec4(50 / 255.f, 58 / 255.f, 61 / 255.f, .5f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered , ImVec4(0, 0, 0, 0.f)); // bg color for menu item
+ ImGui::PushStyleColor(ImGuiCol_BorderActive , ImGuiWrapper::COL_ORCA);
+ ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.f );
+ ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding , 8.f * sc);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f * sc);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 2.f * sc);
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding , ImVec2(4.f, 10.f) * sc);
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing , ImVec2(0.f, 8.f ) * sc);
+
+ if (ImGui::BeginPopup("CanvasToolbarMenu")) {
+ ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
+
+ Plater* p = wxGetApp().plater();
+ AppConfig* cfg = wxGetApp().app_config;
+
+ auto create_menu_item = [this, sc](
+ const std::string& name,
+ bool enable,
+ bool condition,
+ const std::function& action
+ ) {
+ ImGui::Dummy({2.f * sc,0});
+ ImGui::SameLine();
+ if (ImGui::BBLMenuItem((" " + _u8L(name)).c_str(), nullptr, false, enable, ImGui::CalcTextSize(_u8L(name).c_str()).y))
+ action();
+ ImGui::SameLine(12.f * sc);
+ ImGui::TextColored(enable ? ImVec4(1,1,1,1) : ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "%s", into_u8(condition ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str());
+ };
+
+ create_menu_item( "3D Navigator",
+ m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
+ wxGetApp().show_3d_navigator(),
+ [this]{
+ wxGetApp().toggle_show_3d_navigator();
+ ImGui::CloseCurrentPopup(); // Close popup to show changes on UI
+ }
+ );
+
+ create_menu_item( "Zoom button",
+ true, // work on all
+ wxGetApp().show_canvas_zoom_button(),
+ [this]{
+ wxGetApp().toggle_canvas_zoom_button();
+ ImGui::CloseCurrentPopup(); // Close popup to show changes on UI
+ }
+ );
+
+ ImGui::Separator();
+
+ create_menu_item( "Overhangs",
+ m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
+ p->is_view3D_overhang_shown(),
+ [this, p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());}
+ );
+
+ create_menu_item( "Outline",
+ m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
+ wxGetApp().show_outline(),
+ [this]{wxGetApp().toggle_show_outline();}
+ );
+
+ ImGui::Separator();
+
+ create_menu_item( "Perspective",
+ true, // work on all
+ cfg->get_bool("use_perspective_camera"),
+ [this, &cfg]{
+ cfg->set_bool("use_perspective_camera", !(cfg->get_bool("use_perspective_camera")));
+ wxGetApp().update_ui_from_settings();
+ }
+ );
+
+ ImGui::Separator();
+
+ create_menu_item( "Axes",
+ m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
+ m_show_world_axes,
+ [this]{toggle_world_axes_visibility(false);}
+ );
+
+ // will add an option for gridlines in here
+
+ create_menu_item( "Labels",
+ m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
+ p->are_view3D_labels_shown(),
+ [this, p]{p->show_view3D_labels(!p->are_view3D_labels_shown());}
+ );
+
+ ImGui::PopItemFlag();
+ ImGui::EndPopup();
}
- ImGui::PopStyleVar(2);
+
+ ImGui::PopStyleColor(6);
+ ImGui::PopStyleVar(6);
imgui.end();
}
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index aab67615d9..6931b305d6 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -543,7 +543,7 @@ private:
mutable IMToolbar m_sel_plate_toolbar;
mutable GLToolbar m_assemble_view_toolbar;
mutable IMReturnToolbar m_return_toolbar;
- mutable Vec2i32 m_axis_button_pos = {128, 5};
+ mutable Vec2i32 m_canvas_toolbar_pos = {140, 5};
mutable float m_sc{1};
mutable float m_paint_toolbar_width;
@@ -1246,7 +1246,7 @@ private:
void _render_imgui_select_plate_toolbar();
void _render_assemble_view_toolbar() const;
void _render_return_toolbar() const;
- void _render_camera_toolbar();
+ void _render_canvas_toolbar();
void _render_separator_toolbar_right() const;
void _render_separator_toolbar_left() const;
void _render_collapse_toolbar() const;
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 8223c913e1..fef82357ae 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -2312,7 +2312,13 @@ void GUI_App::init_app_config()
}
// Change current dirtory of application
- [[maybe_unused]] auto unused_result = chdir(encode_path((Slic3r::data_dir() + "/log").c_str()).c_str());
+
+#ifdef _WIN32
+ [[maybe_unused]] auto unused_result = _chdir(encode_path((Slic3r::data_dir() + "/log").c_str()).c_str());
+#else
+ [[maybe_unused]] auto unused_result = chdir(encode_path((Slic3r::data_dir() + "/log").c_str()).c_str());
+#endif
+
} else {
m_datadir_redefined = true;
}
@@ -3727,7 +3733,7 @@ void GUI_App::set_side_menu_popup_status(bool status)
m_side_popup_status = status;
}
-void GUI_App::link_to_network_check()
+std::string GUI_App::link_to_network_check()
{
std::string url;
std::string country_code = app_config->get_country_code();
@@ -3742,10 +3748,11 @@ void GUI_App::link_to_network_check()
else {
url = "https://status.bambulab.com";
}
- wxLaunchDefaultBrowser(url);
+ //wxLaunchDefaultBrowser(url);
+ return url; // ORCA
}
-void GUI_App::link_to_lan_only_wiki()
+std::string GUI_App::link_to_lan_only_wiki()
{
std::string url;
std::string country_code = app_config->get_country_code();
@@ -3759,7 +3766,8 @@ void GUI_App::link_to_lan_only_wiki()
else {
url = "https://wiki.bambulab.com/en/knowledge-sharing/enable-lan-mode";
}
- wxLaunchDefaultBrowser(url);
+ //wxLaunchDefaultBrowser(url);
+ return url; // ORCA
}
bool GUI_App::tabs_as_menu() const
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 9827e64fae..7e78003497 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -356,6 +356,9 @@ public:
bool show_3d_navigator() const { return app_config->get_bool("show_3d_navigator"); }
void toggle_show_3d_navigator() const { app_config->set_bool("show_3d_navigator", !show_3d_navigator()); }
+ bool show_canvas_zoom_button() const { return app_config->get_bool("show_canvas_zoom_button"); }
+ void toggle_canvas_zoom_button() const { app_config->set_bool("show_canvas_zoom_button", !show_canvas_zoom_button()); }
+
bool show_outline() const { return app_config->get_bool("show_outline"); }
void toggle_show_outline() const { app_config->set_bool("show_outline", !show_outline()); }
@@ -404,8 +407,8 @@ public:
//update side popup status
bool get_side_menu_popup_status();
void set_side_menu_popup_status(bool status);
- void link_to_network_check();
- void link_to_lan_only_wiki();
+ std::string link_to_network_check(); // ORCA
+ std::string link_to_lan_only_wiki(); // ORCA
const wxColour& get_label_clr_modified() { return m_color_label_modified; }
const wxColour& get_label_clr_sys() { return m_color_label_sys; }
diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp
index e7520b5b51..44dd7b8f6e 100644
--- a/src/slic3r/GUI/GUI_Factories.cpp
+++ b/src/slic3r/GUI/GUI_Factories.cpp
@@ -87,14 +87,14 @@ std::map> SettingsFactory::OBJECT_C
{"precise_z_height", "",10}
}},
- { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},
- {"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6}, {"support_threshold_overlap", "",6}, {"support_on_build_plate_only", "",7},
- {"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25},
- {"tree_support_brim_width", "",26}, {"tree_support_branch_angle", "",10},{"tree_support_branch_angle_organic","",10}, {"tree_support_wall_count", "",11},{"tree_support_branch_diameter_angle", "",11},//tree support
- {"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15},
- {"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19},
- {"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27},
- {"support_object_first_layer_gap","",28}
+ { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_use_efc_outline", "",4},
+ {"enable_support", "",5},{"support_type", "",6},{"support_threshold_angle", "",7}, {"support_threshold_overlap", "",8}, {"support_on_build_plate_only", "",9},
+ {"support_filament", "",10},{"support_interface_filament", "",11},{"support_expansion", "",12},{"support_style", "",13},
+ {"tree_support_brim_width", "",14}, {"tree_support_branch_angle", "",15},{"tree_support_branch_angle_organic","",16}, {"tree_support_wall_count", "",17},{"tree_support_branch_diameter_angle", "",18},//tree support
+ {"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22},
+ {"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26},
+ {"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31},
+ {"support_object_first_layer_gap","",32}
}},
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
}}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 04e65fc88a..0ca62d849a 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -281,23 +281,43 @@ bool GLGizmosManager::init_icon_textures()
else
return false;
- if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle.svg", 64, 64, texture_id))
- icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE, texture_id));
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_menu.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_MENU, texture_id));
else
return false;
- if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_hover.svg", 64, 64, texture_id))
- icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_HOVER, texture_id));
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_menu_hover.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_MENU_HOVER, texture_id));
else
return false;
- if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_dark.svg", 64, 64, texture_id))
- icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_DARK, texture_id));
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_menu_dark.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_MENU_DARK, texture_id));
else
return false;
- if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_hover_dark.svg", 64, 64, texture_id))
- icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_DARK_HOVER, texture_id));
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_menu_dark_hover.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_MENU_DARK_HOVER, texture_id));
+ else
+ return false;
+
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_zoom.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_ZOOM, texture_id));
+ else
+ return false;
+
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_zoom_hover.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_ZOOM_HOVER, texture_id));
+ else
+ return false;
+
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_zoom_dark.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_ZOOM_DARK, texture_id));
+ else
+ return false;
+
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/canvas_zoom_dark_hover.svg", 72, 72, texture_id))
+ icon_list.insert(std::make_pair((int) IC_CANVAS_ZOOM_DARK_HOVER, texture_id));
else
return false;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index ba7d5afdb9..5897c2a512 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -170,10 +170,14 @@ public:
IC_TOOLBAR_TOOLTIP,
IC_TOOLBAR_TOOLTIP_HOVER,
IC_NAME_COUNT,
- IC_AXIS_TOGGLE,
- IC_AXIS_TOGGLE_HOVER,
- IC_AXIS_TOGGLE_DARK,
- IC_AXIS_TOGGLE_DARK_HOVER,
+ IC_CANVAS_MENU,
+ IC_CANVAS_MENU_HOVER,
+ IC_CANVAS_MENU_DARK,
+ IC_CANVAS_MENU_DARK_HOVER,
+ IC_CANVAS_ZOOM,
+ IC_CANVAS_ZOOM_HOVER,
+ IC_CANVAS_ZOOM_DARK,
+ IC_CANVAS_ZOOM_DARK_HOVER,
};
explicit GLGizmosManager(GLCanvas3D& parent);
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 6d0023a0ba..b6d1a7b7d8 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -3113,7 +3113,7 @@ void MainFrame::init_menubar_as_editor()
// help
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Tutorial"), _L("Calibration help"),
[this](wxCommandEvent&) {
- std::string url = "https://github.com/OrcaSlicer/OrcaSlicer/wiki/Calibration";
+ std::string url = "https://www.orcaslicer.com/wiki/Calibration";
if (const std::string country_code = wxGetApp().app_config->get_country_code(); country_code == "CN") {
// Use gitee mirror for China users
url = "https://gitee.com/n0isyfox/orca-slicer-docs/wikis/%E6%A0%A1%E5%87%86/%E6%89%93%E5%8D%B0%E5%8F%82%E6%95%B0%E6%A0%A1%E5%87%86";
@@ -3229,7 +3229,7 @@ void MainFrame::init_menubar_as_editor()
[this]() {return m_plater->is_view3D_shown();; }, this);
// help
append_menu_item(calib_menu, wxID_ANY, _L("Tutorial"), _L("Calibration help"),
- [this](wxCommandEvent&) { wxLaunchDefaultBrowser("https://github.com/OrcaSlicer/OrcaSlicer/wiki/Calibration", wxBROWSER_NEW_WINDOW); }, "", nullptr,
+ [this](wxCommandEvent&) { wxLaunchDefaultBrowser("https://www.orcaslicer.com/wiki/Calibration", wxBROWSER_NEW_WINDOW); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
m_menubar->Append(calib_menu,wxString::Format("&%s", _L("Calibration")));
diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp
index 7869662d7c..c412b5585a 100644
--- a/src/slic3r/GUI/MediaPlayCtrl.cpp
+++ b/src/slic3r/GUI/MediaPlayCtrl.cpp
@@ -769,7 +769,7 @@ bool MediaPlayCtrl::start_stream_service(bool *need_install)
auto file_dll = tools_dir + dll;
auto file_dll2 = plugins_dir + dll;
if (!boost::filesystem::exists(file_dll) || boost::filesystem::last_write_time(file_dll) != boost::filesystem::last_write_time(file_dll2))
- boost::filesystem::copy_file(file_dll2, file_dll, boost::filesystem::copy_option::overwrite_if_exists);
+ boost::filesystem::copy_file(file_dll2, file_dll, boost::filesystem::copy_options::overwrite_existing);
}
boost::process::child process_source(file_source, file_url2.ToStdWstring(), boost::process::start_dir(tools_dir),
boost::process::windows::create_no_window,
diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp
index 0e6e1a324d..049a6b00f2 100644
--- a/src/slic3r/GUI/MsgDialog.cpp
+++ b/src/slic3r/GUI/MsgDialog.cpp
@@ -586,7 +586,8 @@ wxBoxSizer *Newer3mfVersionDialog::get_msg_sizer()
if (file_version_newer) {
text1 = new wxStaticText(this, wxID_ANY, _L("The 3MF file version is in Beta and it is newer than the current OrcaSlicer version."));
wxStaticText * text2 = new wxStaticText(this, wxID_ANY, _L("If you would like to try Orca Slicer Beta, you may click to"));
- wxHyperlinkCtrl *github_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Download Beta Version"), "https://github.com/bambulab/BambuStudio/releases");
+ // ORCA standardized HyperLink
+ HyperLink * github_link = new HyperLink(this, _L("Download Beta Version"), "https://github.com/SoftFever/OrcaSlicer/releases");
horizontal_sizer->Add(text2, 0, wxEXPAND, 0);
horizontal_sizer->Add(github_link, 0, wxEXPAND | wxLEFT, 5);
@@ -672,11 +673,9 @@ NetworkErrorDialog::NetworkErrorDialog(wxWindow* parent)
wxBoxSizer* sizer_link = new wxBoxSizer(wxVERTICAL);
- m_link_server_state = new wxHyperlinkCtrl(this, wxID_ANY, _L("Check the status of current system services"), "");
+ // ORCA standardized HyperLink
+ m_link_server_state = new HyperLink(this, _L("Check the status of current system services"), wxGetApp().link_to_network_check());
m_link_server_state->SetFont(::Label::Body_13);
- m_link_server_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
- m_link_server_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
- m_link_server_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
sizer_link->Add(m_link_server_state, 0, wxALL, 0);
@@ -690,11 +689,9 @@ NetworkErrorDialog::NetworkErrorDialog(wxWindow* parent)
m_text_proposal->SetFont(::Label::Body_14);
m_text_proposal->SetForegroundColour(0x323A3C);
- m_text_wiki = new wxHyperlinkCtrl(this, wxID_ANY, _L("How to use LAN only mode"), "");
+ // ORCA standardized HyperLink
+ m_text_wiki = new HyperLink(this, _L("How to use LAN only mode"), wxGetApp().link_to_lan_only_wiki());
m_text_wiki->SetFont(::Label::Body_13);
- m_text_wiki->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_lan_only_wiki(); });
- m_text_wiki->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); });
- m_text_wiki->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); });
sizer_help->Add(m_text_proposal, 0, wxEXPAND, 0);
sizer_help->Add(m_text_wiki, 0, wxALL, 0);
diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp
index 7b4eb71612..bb3abde75c 100644
--- a/src/slic3r/GUI/MsgDialog.hpp
+++ b/src/slic3r/GUI/MsgDialog.hpp
@@ -14,6 +14,7 @@
#include "Widgets/Button.hpp"
#include "Widgets/CheckBox.hpp"
#include "Widgets/TextInput.hpp"
+#include "Widgets/HyperLink.hpp"
#include "BBLStatusBar.hpp"
#include "BBLStatusBarSend.hpp"
#include "libslic3r/Semver.hpp"
@@ -424,9 +425,9 @@ public:
private:
Label* m_text_basic;
- wxHyperlinkCtrl* m_link_server_state;
+ HyperLink* m_link_server_state; // ORCA
Label* m_text_proposal;
- wxHyperlinkCtrl* m_text_wiki;
+ HyperLink* m_text_wiki; // ORCA
Button * m_button_confirm;
public:
diff --git a/src/slic3r/GUI/MultiMachineManagerPage.cpp b/src/slic3r/GUI/MultiMachineManagerPage.cpp
index 3956f89072..5b0ca791b7 100644
--- a/src/slic3r/GUI/MultiMachineManagerPage.cpp
+++ b/src/slic3r/GUI/MultiMachineManagerPage.cpp
@@ -653,7 +653,7 @@ void MultiMachineManagerPage::start_timer()
m_flipping_timer->SetOwner(this);
m_flipping_timer->Start(1000);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxTimerEvent(*m_flipping_timer));
}
void MultiMachineManagerPage::update_page_number()
diff --git a/src/slic3r/GUI/MultiMachinePage.cpp b/src/slic3r/GUI/MultiMachinePage.cpp
index f7cb05a80e..b9b71ad670 100644
--- a/src/slic3r/GUI/MultiMachinePage.cpp
+++ b/src/slic3r/GUI/MultiMachinePage.cpp
@@ -61,7 +61,7 @@ bool MultiMachinePage::Show(bool show)
m_refresh_timer->Stop();
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(2000);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxTimerEvent(*m_refresh_timer));
}
else {
m_refresh_timer->Stop();
@@ -96,7 +96,7 @@ void MultiMachinePage::init_timer()
m_refresh_timer = new wxTimer();
//m_refresh_timer->SetOwner(this);
//m_refresh_timer->Start(8000);
- //wxPostEvent(this, wxTimerEvent());
+ //wxPostEvent(this, wxTimerEvent(*m_refresh_timer));
}
void MultiMachinePage::on_timer(wxTimerEvent& event)
@@ -482,7 +482,7 @@ bool MultiMachinePickPage::Show(bool show)
//m_refresh_timer->Stop();
//m_refresh_timer->SetOwner(this);
//m_refresh_timer->Start(4000);
- //wxPostEvent(this, wxTimerEvent());
+ //wxPostEvent(this, wxTimerEvent(*m_refresh_timer));
}
else {
//m_refresh_timer->Stop();
diff --git a/src/slic3r/GUI/MultiTaskManagerPage.cpp b/src/slic3r/GUI/MultiTaskManagerPage.cpp
index 37321063f8..0b0b422eb4 100644
--- a/src/slic3r/GUI/MultiTaskManagerPage.cpp
+++ b/src/slic3r/GUI/MultiTaskManagerPage.cpp
@@ -1402,7 +1402,7 @@ void CloudTaskManagerPage::start_timer()
m_flipping_timer->SetOwner(this);
m_flipping_timer->Start(1000);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxTimerEvent(*m_flipping_timer));
}
void CloudTaskManagerPage::on_timer(wxTimerEvent& event)
diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp
index 9abf49323a..c9bb132f68 100644
--- a/src/slic3r/GUI/NotificationManager.hpp
+++ b/src/slic3r/GUI/NotificationManager.hpp
@@ -980,7 +980,7 @@ private:
NotificationData{NotificationType::BBLUserPresetExceedLimit, NotificationLevel::WarningNotificationLevel, BBL_NOTICE_MAX_INTERVAL,
_u8L("The number of user presets cached in the cloud has exceeded the upper limit, newly created user presets can only be used locally."),
- _u8L("Wiki"),
+ _u8L("Wiki Guide"),
[](wxEvtHandler* evnthndlr) {
wxLaunchDefaultBrowser("https://wiki.bambulab.com/en/software/bambu-studio/3rd-party-printer-profile#cloud-user-presets-limit");
return false;
diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp
index 6d3b277c03..7575777507 100644
--- a/src/slic3r/GUI/ObjColorDialog.cpp
+++ b/src/slic3r/GUI/ObjColorDialog.cpp
@@ -47,14 +47,7 @@ wxBoxSizer* ObjColorDialog::create_btn_sizer(long flags,bool exist_error)
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
if (!exist_error) {
btn_sizer->AddSpacer(FromDIP(25));
- wxStaticText *tips = new wxStaticText(this, wxID_ANY, _L("Open Wiki for more information >"));
- /* wxFont font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false);
- font.SetUnderlined(true);
- tips->SetFont(font);*/
- auto font = tips->GetFont();
- font.SetUnderlined(true);
- tips->SetFont(font);
- tips->SetForegroundColour(wxColour("#009687"));
+ auto *tips = new HyperLink(this, _L("Wiki Guide")); // ORCA
tips->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
bool is_zh = wxGetApp().app_config->get("language") == "zh_CN";
if (is_zh) {
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 3d0318f663..5b4f9d3504 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -1312,7 +1312,7 @@ wxString OptionsGroup::get_url(const std::string& path_end)
str = str.Left(pos) + anchor;
}
// Orca: point to sf wiki for seam parameters
- return wxString::Format(L"https://github.com/OrcaSlicer/OrcaSlicer/wiki/%s", from_u8(path_end));
+ return wxString::Format(L"https://www.orcaslicer.com/wiki/%s", from_u8(path_end));
}
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index cc67ee11fd..059955a7cc 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -4670,7 +4670,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"extruder_clearance_radius",
"extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"nozzle_height", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle",
- "brim_width", "brim_object_gap", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
+ "brim_width", "brim_object_gap", "brim_use_efc_outline", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
"enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_tower_enable_framework",
"prime_tower_infill_gap", "prime_volume",
"extruder_colour", "filament_colour", "filament_type", "material_colour", "printable_height", "extruder_printable_height", "printer_model", "printer_technology",
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index 7dc2329f21..0dedacb9d0 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -80,7 +80,7 @@ std::tuple PreferencesDialog::create_item_combobox_base(
return {m_sizer_combox, combobox};
}
-wxBoxSizer* PreferencesDialog::create_item_combobox(wxString title, wxString tooltip, std::string param, std::vector vlist)
+wxBoxSizer* PreferencesDialog::create_item_combobox(wxString title, wxString tooltip, std::string param, std::vector vlist, std::function onchange)
{
unsigned int current_index = 0;
@@ -92,8 +92,10 @@ wxBoxSizer* PreferencesDialog::create_item_combobox(wxString title, wxString too
auto [sizer, combobox] = create_item_combobox_base(title, tooltip, param, vlist, current_index);
//// save config
- combobox->GetDropDown().Bind(wxEVT_COMBOBOX, [this, param](wxCommandEvent& e) {
+ combobox->GetDropDown().Bind(wxEVT_COMBOBOX, [this, param, onchange](wxCommandEvent& e) {
app_config->set(param, std::to_string(e.GetSelection()));
+ if (onchange)
+ onchange(std::to_string(e.GetSelection()));
e.Skip();
});
@@ -1285,6 +1287,10 @@ void PreferencesDialog::create_items()
auto item_remember_printer = create_item_checkbox(_L("Remember printer configuration"), _L("If enabled, Orca will remember and switch filament/process configuration for each printer automatically."), "remember_printer_config");
g_sizer->Add(item_remember_printer);
+ auto item_filament_preset_grouping = create_item_combobox(_L("Group user filament presets"), _L("Group user filament presets based on selection"),
+ "group_filament_presets", {_L("All"), _L("None"), _L("By type"), _L("By vendor")}, [](wxString value) {wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);});
+ g_sizer->Add(item_filament_preset_grouping);
+
//// GENERAL > Features
g_sizer->Add(create_item_title(_L("Features")), 1, wxEXPAND);
diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp
index 5f98174bf2..892c1ec35c 100644
--- a/src/slic3r/GUI/Preferences.hpp
+++ b/src/slic3r/GUI/Preferences.hpp
@@ -80,7 +80,7 @@ public:
std::vector f_sizers;
wxBoxSizer *create_item_title(wxString title);
- wxBoxSizer *create_item_combobox(wxString title, wxString tooltip, std::string param, std::vector vlist);
+ wxBoxSizer *create_item_combobox(wxString title, wxString tooltip, std::string param, std::vector vlist, std::function onchange = {});
wxBoxSizer *create_item_combobox(wxString title, wxString tooltip, std::string param, std::vector vlist, std::vector config_name_index);
wxBoxSizer *create_item_region_combobox(wxString title, wxString tooltip);
wxBoxSizer *create_item_language_combobox(wxString title, wxString tooltip);
diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp
index 5006c5eab0..2e5f83c211 100644
--- a/src/slic3r/GUI/PresetComboBoxes.cpp
+++ b/src/slic3r/GUI/PresetComboBoxes.cpp
@@ -1132,6 +1132,7 @@ void PlaterPresetComboBox::update()
std::map preset_descriptions;
std::map preset_filament_vendors;
std::map preset_filament_types;
+ std::map preset_filament_names; // ORCA
//BBS: move system to the end
wxString selected_system_preset;
wxString selected_user_preset;
@@ -1174,7 +1175,8 @@ void PlaterPresetComboBox::update()
bitmap_key += single_bar ? filament_rgb : filament_rgb + extruder_rgb;
#endif
- if (preset.is_system) {
+ // ORCA allow caching vendor and type values for all presets instead just system ones
+ // if (preset.is_system) {
if (!preset.is_compatible && preset_filament_vendors.count(name) > 0)
continue;
else if (preset.is_compatible && preset_filament_vendors.count(name) > 0)
@@ -1183,7 +1185,8 @@ void PlaterPresetComboBox::update()
if (preset_filament_vendors[name] == "Bambu Lab")
preset_filament_vendors[name] = "Bambu";
preset_filament_types[name] = preset.config.option("filament_type")->values.at(0);
- }
+ preset_filament_names[name] = name.ToStdString(); // ORCA
+ //}
}
wxBitmap* bmp = get_bmp(preset);
assert(bmp);
@@ -1251,7 +1254,7 @@ void PlaterPresetComboBox::update()
"Bambu PLA Galaxy", "Bambu PLA Metal", "Bambu PLA Marble", "Bambu PETG-CF", "Bambu PETG Translucent", "Bambu ABS-GF"};
std::vector first_vendors = {"", "Bambu", "Generic"}; // Empty vendor for non-system presets
std::vector first_types = {"PLA", "PETG", "ABS", "TPU"};
- auto add_presets = [this, &preset_descriptions, &filament_orders, &preset_filament_vendors, &first_vendors, &preset_filament_types, &first_types, &selected_in_ams]
+ auto add_presets = [this, &preset_descriptions, &filament_orders, &preset_filament_vendors, &first_vendors, &preset_filament_types, &preset_filament_names, &first_types, &selected_in_ams]
(std::map const &presets, wxString const &selected, std::string const &group, wxString const &groupName) {
if (!presets.empty()) {
set_label_marker(Append(_L(group), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
@@ -1285,9 +1288,31 @@ void PlaterPresetComboBox::update()
}
return l->first < r->first;
});
+ // ORCA add sorting support for vendor / type for user presets. also non grouped items
+ if (groupName == "by_vendor" || groupName == "by_type" || groupName == ""){
+ auto by = groupName == "by_vendor" ? preset_filament_vendors
+ : groupName == "by_type" ? preset_filament_types
+ : preset_filament_names;
+ std::sort(list.begin(), list.end(), [&by](auto *l, auto *r) {
+ auto get_key = [&](auto* item) -> std::pair {
+ std::string str = by.count(item->first) ? by.at(item->first) : "";
+ std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c);});
+ return {!str.empty(), str}; // is_valid, lower_case
+ };
+ auto [l_valid, l_lower] = get_key(l);
+ auto [r_valid, r_lower] = get_key(r);
+ return (l_valid != r_valid) ? l_valid > r_valid
+ : (l_lower != r_lower) ? l_lower < r_lower
+ : l->first < r->first;
+ });
+ }
bool unsupported = group == "Unsupported presets";
for (auto it : list) {
- auto groupName2 = groupByGroup ? groupName : preset_filament_vendors[it->first];
+ // ORCA add sorting support for vendor / type for user presets
+ auto groupName2 = groupName == "by_type" ? (preset_filament_types[it->first].empty() ? _L("Unspecified") : preset_filament_types[it->first])
+ : groupName == "by_vendor" ? (preset_filament_vendors[it->first].empty() ? _L("Unspecified") : preset_filament_vendors[it->first])
+ : groupByGroup ? groupName
+ : preset_filament_vendors[it->first];
int index = Append(it->first, *it->second, groupName2, nullptr, unsupported ? DD_ITEM_STYLE_DISABLED : 0);
if (unsupported)
set_label_marker(index, LABEL_ITEM_DISABLED);
@@ -1311,7 +1336,13 @@ void PlaterPresetComboBox::update()
//BBS: add project embedded preset logic
add_presets(project_embedded_presets, selected_user_preset, L("Project-inside presets"), _L("Project") + " ");
- add_presets(nonsys_presets, selected_user_preset, L("User presets"), _L("Custom") + " ");
+ // ORCA add sorting support for vendor / type for user presets
+ auto group_filament_presets = wxGetApp().app_config->get("group_filament_presets");
+ auto group_filament_presets_by = group_filament_presets == "0" ? (_L("Custom") + " ") // Append all to "Custom" sub menu
+ : group_filament_presets == "2" ? "by_type" // Create sub menus with filament type
+ : group_filament_presets == "3" ? "by_vendor" // Create sub menus with filament vendor
+ : ""; // Use without sub menu
+ add_presets(nonsys_presets, selected_user_preset, L("User presets"), group_filament_presets_by);
// BBS: move system to the end
add_presets(system_presets, selected_system_preset, L("System presets"), _L("System"));
add_presets(uncompatible_presets, {}, L("Unsupported presets"), _L("Unsupported") + " ");
diff --git a/src/slic3r/GUI/PrintOptionsDialog.cpp b/src/slic3r/GUI/PrintOptionsDialog.cpp
index 02329a36b7..56cc764356 100644
--- a/src/slic3r/GUI/PrintOptionsDialog.cpp
+++ b/src/slic3r/GUI/PrintOptionsDialog.cpp
@@ -1153,11 +1153,8 @@ PrinterPartsDialog::PrinterPartsDialog(wxWindow* parent)
change_nozzle_tips->SetFont(Label::Body_13);
change_nozzle_tips->SetForegroundColour(STATIC_TEXT_CAPTION_COL);
- m_wiki_link = new Label(single_panel, _L("View wiki"));
+ m_wiki_link = new HyperLink(single_panel, _L("Wiki Guide")); // ORCA
m_wiki_link->SetFont(Label::Body_13);
- m_wiki_link->SetForegroundColour(wxColour("#009688"));
- m_wiki_link->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_HAND); });
- m_wiki_link->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_ARROW); });
m_wiki_link->Bind(wxEVT_LEFT_DOWN, &PrinterPartsDialog::OnWikiClicked, this);
h_tips_sizer->Add(change_nozzle_tips, 0, wxLEFT);
@@ -1267,11 +1264,8 @@ PrinterPartsDialog::PrinterPartsDialog(wxWindow* parent)
multiple_change_nozzle_tips->SetFont(Label::Body_13);
multiple_change_nozzle_tips->SetForegroundColour(STATIC_TEXT_CAPTION_COL);
- multiple_wiki_link = new Label(multiple_panel, _L("View wiki"));
+ multiple_wiki_link = new HyperLink(multiple_panel, _L("Wiki Guide")); // ORCA
multiple_wiki_link->SetFont(Label::Body_13);
- multiple_wiki_link->SetForegroundColour(wxColour("#009688"));
- multiple_wiki_link->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_HAND); });
- multiple_wiki_link->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) { SetCursor(wxCURSOR_ARROW); });
multiple_wiki_link->Bind(wxEVT_LEFT_DOWN, &PrinterPartsDialog::OnWikiClicked, this);
wxSizer* multiple_change_tips_sizer = new wxBoxSizer(wxHORIZONTAL);
diff --git a/src/slic3r/GUI/PrintOptionsDialog.hpp b/src/slic3r/GUI/PrintOptionsDialog.hpp
index d555c8237b..9918cfb80e 100644
--- a/src/slic3r/GUI/PrintOptionsDialog.hpp
+++ b/src/slic3r/GUI/PrintOptionsDialog.hpp
@@ -16,6 +16,7 @@
#include "Widgets/CheckBox.hpp"
#include "Widgets/StaticLine.hpp"
#include "Widgets/ComboBox.hpp"
+#include "Widgets/HyperLink.hpp"
// Previous definitions
class SwitchBoard;
@@ -33,7 +34,7 @@ protected:
Label* nozzle_flow_type_label;
ComboBox* nozzle_flow_type_checkbox;
Label *change_nozzle_tips;
- Label* m_wiki_link;
+ HyperLink* m_wiki_link;
Button* m_single_update_nozzle_button;
Button* m_multiple_update_nozzle_button;
@@ -46,7 +47,7 @@ protected:
ComboBox *multiple_right_nozzle_flow_checkbox;
Label *multiple_change_nozzle_tips;
- Label* multiple_wiki_link;
+ HyperLink* multiple_wiki_link;
wxPanel *single_panel;
wxPanel *multiple_panel;
diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp
index 2dd0a7baf2..9b156c5228 100644
--- a/src/slic3r/GUI/ReleaseNote.cpp
+++ b/src/slic3r/GUI/ReleaseNote.cpp
@@ -1510,7 +1510,8 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow *parent)
m_tip4->SetMinSize(wxSize(FromDIP(355), -1));
m_tip4->SetMaxSize(wxSize(FromDIP(355), -1));
- m_trouble_shoot = new wxHyperlinkCtrl(this, wxID_ANY, "How to trouble shooting", "");
+ // ORCA standardized HyperLink
+ m_trouble_shoot = new HyperLink(this, "How to trouble shooting");
m_img_help = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("input_access_code_x1_en", this, 198), wxDefaultPosition, wxSize(FromDIP(355), -1), 0);
diff --git a/src/slic3r/GUI/ReleaseNote.hpp b/src/slic3r/GUI/ReleaseNote.hpp
index 838df0efd5..37b7c58935 100644
--- a/src/slic3r/GUI/ReleaseNote.hpp
+++ b/src/slic3r/GUI/ReleaseNote.hpp
@@ -326,7 +326,7 @@ public:
wxStaticBitmap* m_img_step1{ nullptr };
wxStaticBitmap* m_img_step2{ nullptr };
wxStaticBitmap* m_img_step3{ nullptr };
- wxHyperlinkCtrl* m_trouble_shoot{ nullptr };
+ HyperLink* m_trouble_shoot{ nullptr }; // ORCA
wxTimer* closeTimer{ nullptr };
int closeCount{3};
bool m_show_access_code{ false };
diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp
index 56ecd56ce2..eeb472e98a 100644
--- a/src/slic3r/GUI/SelectMachine.cpp
+++ b/src/slic3r/GUI/SelectMachine.cpp
@@ -688,12 +688,9 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0);
sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0);
-
- m_link_network_state = new wxHyperlinkCtrl(m_sw_print_failed_info, wxID_ANY,_L("Check the status of current system services"),"");
+ // ORCA standardized HyperLink
+ m_link_network_state = new HyperLink(m_sw_print_failed_info, _L("Check the status of current system services"), wxGetApp().link_to_network_check());
m_link_network_state->SetFont(::Label::Body_12);
- m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check();});
- m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND);});
- m_link_network_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_ARROW);});
sizer_print_failed_info->Add(m_link_network_state, 0, wxLEFT, 5);
sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5);
diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp
index 42bf251b7c..302b37b553 100644
--- a/src/slic3r/GUI/SelectMachine.hpp
+++ b/src/slic3r/GUI/SelectMachine.hpp
@@ -42,6 +42,7 @@
#include "Widgets/ComboBox.hpp"
#include "Widgets/ScrolledWindow.hpp"
#include "Widgets/PopupWindow.hpp"
+#include "Widgets/HyperLink.hpp" // ORCA
#include
#include
@@ -371,7 +372,7 @@ protected:
Label* m_st_txt_error_desc{nullptr};
Label* m_st_txt_extra_info{nullptr};
Label* m_ams_backup_tip{nullptr};
- wxHyperlinkCtrl* m_link_network_state{ nullptr };
+ HyperLink* m_link_network_state{ nullptr }; // ORCA
wxSimplebook* m_rename_switch_panel{nullptr};
wxSimplebook* m_simplebook{nullptr};
wxStaticText* m_rename_text{nullptr};
diff --git a/src/slic3r/GUI/SelectMachinePop.cpp b/src/slic3r/GUI/SelectMachinePop.cpp
index aef994d067..ddca6df8a7 100644
--- a/src/slic3r/GUI/SelectMachinePop.cpp
+++ b/src/slic3r/GUI/SelectMachinePop.cpp
@@ -596,8 +596,9 @@ void SelectMachinePopup::update_other_devices()
m_placeholder_panel = new wxWindow(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxSize(-1,FromDIP(26)));
wxBoxSizer* placeholder_sizer = new wxBoxSizer(wxVERTICAL);
- m_hyperlink = new wxHyperlinkCtrl(m_placeholder_panel, wxID_ANY, _L("Can't find my devices?"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
- m_hyperlink->SetNormalColour(StateColor::darkModeColorFor("#009789"));
+ // ORCA standardized HyperLink
+ m_hyperlink = new HyperLink(m_placeholder_panel, _L("Can't find my devices?"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"));
+ m_hyperlink->SetFont(::Label::Body_12);
placeholder_sizer->Add(m_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
diff --git a/src/slic3r/GUI/SelectMachinePop.hpp b/src/slic3r/GUI/SelectMachinePop.hpp
index d1a34f9b3a..757cb08ed5 100644
--- a/src/slic3r/GUI/SelectMachinePop.hpp
+++ b/src/slic3r/GUI/SelectMachinePop.hpp
@@ -180,7 +180,7 @@ private:
PinCodePanel* m_panel_ping_code{nullptr};
PinCodePanel* m_panel_direct_connection{nullptr};
wxWindow* m_placeholder_panel{nullptr};
- wxHyperlinkCtrl* m_hyperlink{nullptr};
+ HyperLink* m_hyperlink{nullptr}; // ORCA
Label* m_ping_code_text{nullptr};
wxStaticBitmap* m_img_ping_code{nullptr};
wxBoxSizer * m_sizer_body{nullptr};
diff --git a/src/slic3r/GUI/SendMultiMachinePage.cpp b/src/slic3r/GUI/SendMultiMachinePage.cpp
index 1060dc253c..3578e4047c 100644
--- a/src/slic3r/GUI/SendMultiMachinePage.cpp
+++ b/src/slic3r/GUI/SendMultiMachinePage.cpp
@@ -801,7 +801,7 @@ bool SendMultiMachinePage::Show(bool show)
m_refresh_timer->Stop();
m_refresh_timer->SetOwner(this);
m_refresh_timer->Start(4000);
- wxPostEvent(this, wxTimerEvent());
+ wxPostEvent(this, wxTimerEvent(*m_refresh_timer));
}
else {
m_refresh_timer->Stop();
diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp
index 5f5cf9925e..670a8bcad4 100644
--- a/src/slic3r/GUI/SendToPrinter.cpp
+++ b/src/slic3r/GUI/SendToPrinter.cpp
@@ -446,11 +446,9 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater)
sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0);
sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0);
- m_link_network_state = new wxHyperlinkCtrl(m_sw_print_failed_info, wxID_ANY,_L("Check the status of current system services"),"");
+ // ORCA standardized HyperLink
+ m_link_network_state = new HyperLink(m_sw_print_failed_info, _L("Check the status of current system services"), wxGetApp().link_to_network_check());
m_link_network_state->SetFont(::Label::Body_12);
- m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
- m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); });
- m_link_network_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_ARROW); });
sizer_print_failed_info->Add(m_link_network_state, 0, wxLEFT, 5);
sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5);
diff --git a/src/slic3r/GUI/SendToPrinter.hpp b/src/slic3r/GUI/SendToPrinter.hpp
index de284e31d6..14493a1f20 100644
--- a/src/slic3r/GUI/SendToPrinter.hpp
+++ b/src/slic3r/GUI/SendToPrinter.hpp
@@ -110,7 +110,7 @@ private:
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
- wxHyperlinkCtrl* m_link_network_state{ nullptr };
+ HyperLink* m_link_network_state{ nullptr };
StateColor btn_bg_enable;
wxBoxSizer* rename_sizer_v{ nullptr };
wxBoxSizer* rename_sizer_h{ nullptr };
diff --git a/src/slic3r/GUI/StepMeshDialog.cpp b/src/slic3r/GUI/StepMeshDialog.cpp
index db281a8ebf..196c0ff8e0 100644
--- a/src/slic3r/GUI/StepMeshDialog.cpp
+++ b/src/slic3r/GUI/StepMeshDialog.cpp
@@ -117,14 +117,11 @@ StepMeshDialog::StepMeshDialog(wxWindow* parent, Slic3r::Step& file, double line
wxBoxSizer* tips_sizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* info = new wxStaticText(this, wxID_ANY, _L("Smaller linear and angular deflections result in higher-quality transformations but increase the processing time."));
info->SetForegroundColour(StateColor::darkModeColorFor(FONT_COLOR));
- wxStaticText *tips = new wxStaticText(this, wxID_ANY, _L("View Wiki for more information"));
- wxFont font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false);
- font.SetUnderlined(true);
- tips->SetForegroundColour(StateColor::darkModeColorFor(wxColour(0, 151, 137)));
- tips->SetFont(font);
- tips->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) {
- wxLaunchDefaultBrowser("https://github.com/OrcaSlicer/OrcaSlicer/wiki/stl-transformation");
- });
+
+ // ORCA standardized HyperLink
+ HyperLink *tips = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/stl-transformation");
+ tips->SetFont(::Label::Body_12);
+
info->Wrap(FromDIP(400));
tips_sizer->Add(info, 0, wxALIGN_LEFT);
tips_sizer->Add(tips, 0, wxALIGN_LEFT);
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index fd8ede92d2..d4d31a3573 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -2663,6 +2663,7 @@ void TabPrint::build()
optgroup->append_single_option_line("brim_type", "others_settings_brim#type");
optgroup->append_single_option_line("brim_width", "others_settings_brim#width");
optgroup->append_single_option_line("brim_object_gap", "others_settings_brim#brim-object-gap");
+ optgroup->append_single_option_line("brim_use_efc_outline", "others_settings_brim#brim-use-efc-outline");
optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle");
optgroup->append_single_option_line("brim_ears_detection_length", "others_settings_brim#ear-detection-radius");
diff --git a/src/slic3r/GUI/WebUserLoginDialog.cpp b/src/slic3r/GUI/WebUserLoginDialog.cpp
index fba6547f65..2522efbf4f 100644
--- a/src/slic3r/GUI/WebUserLoginDialog.cpp
+++ b/src/slic3r/GUI/WebUserLoginDialog.cpp
@@ -25,6 +25,7 @@
#include
#include
+#include // ORCA
using namespace std;
using namespace nlohmann;
@@ -57,11 +58,12 @@ ZUserLogin::ZUserLogin() : wxDialog((wxWindow *) (wxGetApp().mainframe), wxID_AN
m_message->SetForegroundColour(*wxBLACK);
m_message->Wrap(FromDIP(360));
- auto m_download_hyperlink = new wxHyperlinkCtrl(this, wxID_ANY, _L("Click here to download it."), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
- m_download_hyperlink->Bind(wxEVT_HYPERLINK, [this](wxCommandEvent& event) {
+ // ORCA standardized HyperLink
+ auto m_download_hyperlink = new HyperLink(this, _L("Click here to download it."));
+ m_download_hyperlink->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
this->Close();
wxGetApp().ShowDownNetPluginDlg();
- });
+ });
m_sizer_main->Add(m_message, 0, wxALIGN_CENTER | wxALL, FromDIP(15));
m_sizer_main->Add(m_download_hyperlink, 0, wxALIGN_CENTER | wxALL, FromDIP(10));
m_sizer_main->Add(0, 0, 1, wxBOTTOM, 10);
diff --git a/src/slic3r/GUI/Widgets/HyperLink.cpp b/src/slic3r/GUI/Widgets/HyperLink.cpp
new file mode 100644
index 0000000000..7fdb236199
--- /dev/null
+++ b/src/slic3r/GUI/Widgets/HyperLink.cpp
@@ -0,0 +1,49 @@
+#include "HyperLink.hpp"
+#include "Label.hpp"
+
+namespace Slic3r { namespace GUI {
+
+HyperLink::HyperLink(wxWindow* parent, const wxString& label, const wxString& url, long style)
+ : wxStaticText(parent, wxID_ANY, label)
+ , m_url(url)
+ , m_normalColor(wxColour("#009687")) // used slightly different color otherwise automatically uses ColorForDark that not visible enough
+ , m_hoverColor(wxColour("#26A69A"))
+{
+ SetForegroundColour(m_normalColor);
+ HyperLink::SetFont(Label::Head_14);
+ SetCursor(wxCursor(wxCURSOR_HAND));
+
+ if (!m_url.IsEmpty())
+ SetToolTip(m_url);
+
+ Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent& e) {
+ if (!m_url.IsEmpty())
+ wxLaunchDefaultBrowser(m_url);
+ }));
+
+ Bind(wxEVT_ENTER_WINDOW, ([this](wxMouseEvent& e) {
+ SetForegroundColour(m_hoverColor);
+ Refresh();
+ }));
+ Bind(wxEVT_LEAVE_WINDOW, ([this](wxMouseEvent& e) {
+ SetForegroundColour(m_normalColor);
+ Refresh();
+ }));
+}
+
+bool HyperLink::SetFont(const wxFont& font)
+{ // ensure it stays underlined
+ wxFont f = font;
+ f.SetUnderlined(true);
+ return wxStaticText::SetFont(f);
+}
+
+void HyperLink::SetURL(const wxString& url)
+{
+ m_url = url;
+ SetToolTip(m_url);
+}
+
+wxString HyperLink::GetURL() const { return m_url; }
+
+}} // namespace Slic3r::GUI
diff --git a/src/slic3r/GUI/Widgets/HyperLink.hpp b/src/slic3r/GUI/Widgets/HyperLink.hpp
new file mode 100644
index 0000000000..48e2245e3b
--- /dev/null
+++ b/src/slic3r/GUI/Widgets/HyperLink.hpp
@@ -0,0 +1,26 @@
+#ifndef slic3r_GUI_HyperLink_hpp_
+#define slic3r_GUI_HyperLink_hpp_
+
+#include
+#include
+
+namespace Slic3r { namespace GUI {
+
+class HyperLink : public wxStaticText
+{
+public:
+ HyperLink(wxWindow* parent, const wxString& label = wxEmptyString, const wxString& url = wxEmptyString, const long style = 0);
+
+ void SetURL(const wxString& url);
+ wxString GetURL() const;
+
+ bool SetFont(const wxFont& font);
+
+private:
+ wxString m_url;
+ wxColour m_normalColor;
+ wxColour m_hoverColor;
+};
+
+}} // namespace Slic3r::GUI
+#endif // !slic3r_GUI_HyperLink_hpp_
diff --git a/src/slic3r/GUI/Widgets/LabeledStaticBox.cpp b/src/slic3r/GUI/Widgets/LabeledStaticBox.cpp
index 93e4596aa5..c8e054593f 100644
--- a/src/slic3r/GUI/Widgets/LabeledStaticBox.cpp
+++ b/src/slic3r/GUI/Widgets/LabeledStaticBox.cpp
@@ -160,7 +160,7 @@ void LabeledStaticBox::DrawBorderAndLabel(wxDC& dc)
wxSize wSz = GetSize();
dc.SetBrush(*wxTRANSPARENT_BRUSH);
- dc.SetPen(wxPen(border_color.colorForStates(state_handler.states()), m_border_width, wxSOLID));
+ dc.SetPen(wxPen(border_color.colorForStates(state_handler.states()), m_border_width, wxPENSTYLE_SOLID));
dc.DrawRoundedRectangle( // Border
std::max(0, m_pos.x),
std::max(0, m_pos.y) + m_label_height * .5,
diff --git a/src/slic3r/GUI/Widgets/SideTools.cpp b/src/slic3r/GUI/Widgets/SideTools.cpp
index 4288647e53..377253e707 100644
--- a/src/slic3r/GUI/Widgets/SideTools.cpp
+++ b/src/slic3r/GUI/Widgets/SideTools.cpp
@@ -274,8 +274,8 @@ SideTools::SideTools(wxWindow *parent, wxWindowID id, const wxPoint &pos, const
wxBoxSizer* connection_sizer_V = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* connection_sizer_H = new wxBoxSizer(wxHORIZONTAL);
- m_hyperlink = new wxHyperlinkCtrl(m_connection_info, wxID_ANY, _L("Failed to connect to the server"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
- m_hyperlink->SetBackgroundColour(wxColour(255, 111, 0));
+ // ORCA standardized HyperLink
+ m_hyperlink = new HyperLink(m_connection_info, _L("Failed to connect to the server"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"));
m_more_err_open = ScalableBitmap(this, "monitir_err_open", 16);
m_more_err_close = ScalableBitmap(this, "monitir_err_close", 16);
@@ -328,13 +328,10 @@ SideTools::SideTools(wxWindow *parent, wxWindowID id, const wxPoint &pos, const
wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL);
- m_link_network_state = new wxHyperlinkCtrl(m_side_error_panel, wxID_ANY,_L("Check the status of current system services"),"",wxDefaultPosition,wxDefaultSize, wxHL_ALIGN_CENTRE |wxST_ELLIPSIZE_END);
- m_link_network_state->SetMinSize(wxSize(FromDIP(220), -1));
+ // ORCA standardized HyperLink
+ m_link_network_state = new HyperLink(m_side_error_panel, _L("Check the status of current system services"), wxGetApp().link_to_network_check(), wxST_ELLIPSIZE_END);
m_link_network_state->SetMaxSize(wxSize(FromDIP(220), -1));
m_link_network_state->SetFont(::Label::Body_12);
- m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
- m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); });
- m_link_network_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_ARROW); });
auto st_title_error_code = new wxStaticText(m_side_error_panel, wxID_ANY, _L("code"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
auto st_title_error_code_doc = new wxStaticText(m_side_error_panel, wxID_ANY, ": ");
diff --git a/src/slic3r/GUI/Widgets/SideTools.hpp b/src/slic3r/GUI/Widgets/SideTools.hpp
index 4f1cf7c667..24cbae4fd2 100644
--- a/src/slic3r/GUI/Widgets/SideTools.hpp
+++ b/src/slic3r/GUI/Widgets/SideTools.hpp
@@ -4,9 +4,9 @@
#include
#include
#include
-#include
#include "Button.hpp"
#include "Label.hpp"
+#include "HyperLink.hpp" // ORCA
#include "../GUI/Tabbook.hpp"
#include "../DeviceManager.hpp"
#include "../wxExtensions.hpp"
@@ -99,13 +99,13 @@ public:
private:
SideToolsPanel* m_side_tools{ nullptr };
Tabbook* m_tabpanel{ nullptr };
- wxHyperlinkCtrl* m_link_network_state{ nullptr };
+ HyperLink* m_link_network_state{ nullptr }; // ORCA
Label* m_st_txt_error_code{ nullptr };
Label* m_st_txt_error_desc{ nullptr };
Label* m_st_txt_extra_info{ nullptr };
wxWindow* m_side_error_panel{ nullptr };
Button* m_connection_info{ nullptr };
- wxHyperlinkCtrl* m_hyperlink{ nullptr };
+ HyperLink* m_hyperlink{ nullptr }; // ORCA
ScalableButton* m_more_button{ nullptr };
ScalableBitmap m_more_err_open;
ScalableBitmap m_more_err_close;
diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp
index 24eb46b4a5..79735f6901 100644
--- a/src/slic3r/GUI/calib_dlg.cpp
+++ b/src/slic3r/GUI/calib_dlg.cpp
@@ -5,6 +5,7 @@
#include
#include "MainFrame.hpp"
#include "Widgets/DialogButtons.hpp"
+#include "Widgets/HyperLink.hpp"
#include
#include
#include "libslic3r/PrintConfig.hpp"
@@ -173,22 +174,14 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- // Help links
- auto help_sizer = new wxBoxSizer(wxVERTICAL);
- auto help_link_pa = new wxHyperlinkCtrl(this, wxID_ANY, _L("Pressure Advance Guide"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/pressure-advance-calib");
- help_link_pa->SetForegroundColour(wxColour("#1890FF"));
- help_sizer->Add(help_link_pa, 0, wxALL, FromDIP(5));
-
- auto help_link_apa = new wxHyperlinkCtrl(this, wxID_ANY, _L("Adaptive Pressure Advance Guide"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/adaptive-pressure-advance-calib");
- help_link_apa->SetForegroundColour(wxColour("#1890FF"));
- help_sizer->Add(help_link_apa, 0, wxALL, FromDIP(5));
-
- v_sizer->Add(help_sizer, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/pressure-advance-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &PA_Calibration_Dlg::on_start, this);
@@ -399,13 +392,14 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Temperature Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/temp-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/temp-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &Temp_Calibration_Dlg::on_start, this);
@@ -578,13 +572,14 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Volumetric Speed Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/volumetric-speed-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/volumetric-speed-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &MaxVolumetricSpeed_Test_Dlg::on_start, this);
@@ -684,13 +679,14 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: VFA"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/vfa-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/vfa-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &VFA_Test_Dlg::on_start, this);
@@ -791,13 +787,14 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Retraction Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/retraction-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/retraction-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &Retraction_Test_Dlg::on_start, this);
@@ -968,13 +965,14 @@ Input_Shaping_Freq_Test_Dlg::Input_Shaping_Freq_Test_Dlg(wxWindow* parent, wxWin
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Input Shaping Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/input-shaping-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/input-shaping-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &Input_Shaping_Freq_Test_Dlg::on_start, this);
@@ -1165,13 +1163,14 @@ Input_Shaping_Damp_Test_Dlg::Input_Shaping_Damp_Test_Dlg(wxWindow* parent, wxWin
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Input Shaping Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/input-shaping-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/input-shaping-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &Input_Shaping_Damp_Test_Dlg::on_start, this);
@@ -1356,13 +1355,14 @@ Cornering_Test_Dlg::Cornering_Test_Dlg(wxWindow* parent, wxWindowID id, Plater*
v_sizer->Add(settings_sizer, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10));
v_sizer->AddSpacer(FromDIP(5));
- auto help_link = new wxHyperlinkCtrl(this, wxID_ANY, _L("Wiki Guide: Cornering Calibration"),
- "https://github.com/OrcaSlicer/OrcaSlicer/wiki/cornering-calib");
- help_link->SetForegroundColour(wxColour("#1890FF"));
- v_sizer->Add(help_link, 0, wxALL, FromDIP(10));
-
auto dlg_btns = new DialogButtons(this, {"OK"});
- v_sizer->Add(dlg_btns , 0, wxEXPAND);
+
+ auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
+ auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/cornering-calib");
+ bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20));
+ bottom_sizer->AddStretchSpacer();
+ bottom_sizer->Add(dlg_btns, 0, wxEXPAND);
+ v_sizer->Add(bottom_sizer, 0, wxEXPAND);
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &Cornering_Test_Dlg::on_start, this);