Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05eb2efb49 |
@@ -1,47 +0,0 @@
|
|||||||
# clang-tidy configuration. Only missing includes are reported for now: a file
|
|
||||||
# should include the header for every symbol it uses, not rely on the
|
|
||||||
# precompiled header or another header's includes. Run with --fix to add them.
|
|
||||||
Checks: '-*,misc-include-cleaner'
|
|
||||||
CheckOptions:
|
|
||||||
# Missing includes only. Builds without the precompiled header break on these.
|
|
||||||
misc-include-cleaner.UnusedIncludes: false
|
|
||||||
# Headers that declare a symbol but are not the one to include: per-platform
|
|
||||||
# implementations of wxWidgets and Boost.Thread (a Linux run would suggest the
|
|
||||||
# GTK or pthread one), library internals and forward declarations, CPython's
|
|
||||||
# headers behind Python.h, curl's behind curl.h, oneTBB's behind tbb/, and
|
|
||||||
# admesh's stl.h, which the include path also exposes without its directory.
|
|
||||||
# FFmpeg's C headers are left alone because they are only included inside
|
|
||||||
# extern "C", which an inserted include would miss. OS-specific headers (GLib,
|
|
||||||
# GTK, D-Bus, POSIX, the Windows SDK) are only used inside platform #if blocks,
|
|
||||||
# and an include added at the top of the file would break the other platforms'
|
|
||||||
# builds. A symbol these provide is not reported missing.
|
|
||||||
# Write every / as [/\\] so the patterns also match Windows paths.
|
|
||||||
# No comments inside the block below, because a # there silently becomes part of a pattern.
|
|
||||||
misc-include-cleaner.IgnoreHeaders: >-
|
|
||||||
wx[/\\](gtk|gtk1|msw|osx|unix|x11|motif|univ|qt|dfb|generic|private)[/\\].*;
|
|
||||||
.*[/\\]detail[/\\].*;
|
|
||||||
.*[/\\]impl[/\\].*;
|
|
||||||
.*_fwd\.hpp;
|
|
||||||
python3\.[0-9]+[/\\].*;
|
|
||||||
bits[/\\].*;
|
|
||||||
imconfig\.h;
|
|
||||||
expat_external\.h;
|
|
||||||
admesh[/\\]stl\.h;
|
|
||||||
boost[/\\]thread[/\\](pthread|win32)[/\\].*;
|
|
||||||
boost[/\\]regex[/\\]v[0-9]+[/\\].*;
|
|
||||||
curl[/\\](easy|multi|system|urlapi|header|options|websockets|mprintf)\.h;
|
|
||||||
oneapi[/\\]tbb[/\\].*;
|
|
||||||
opencv2[/\\]core[/\\]hal[/\\].*;
|
|
||||||
openssl[/\\]ossl_typ\.h;
|
|
||||||
libav[a-z]+[/\\].*;
|
|
||||||
libsw[a-z]+[/\\].*;
|
|
||||||
glib-2\.0[/\\].*;
|
|
||||||
gtk-3\.0[/\\].*;
|
|
||||||
dbus-1\.0[/\\].*;
|
|
||||||
sys[/\\].*;
|
|
||||||
unistd\.h;
|
|
||||||
strings\.h;
|
|
||||||
fcntl\.h;
|
|
||||||
termios\.h;
|
|
||||||
[/\\](um|shared)[/\\].*;
|
|
||||||
sal\.h
|
|
||||||
@@ -206,8 +206,7 @@ known class with a pitfall entry and a fixing commit.
|
|||||||
- **macOS:** capture-lost is never sent (a leaked capture freezes all clicks); transient popups hover-
|
- **macOS:** capture-lost is never sent (a leaked capture freezes all clicks); transient popups hover-
|
||||||
dismiss across a gap — anchor flush and re-verify the cursor; native modals (file/dir dialogs, native
|
dismiss across a gap — anchor flush and re-verify the cursor; native modals (file/dir dialogs, native
|
||||||
message boxes) and generic progress dialogs re-activate the main window, so re-raise a secondary window
|
message boxes) and generic progress dialogs re-activate the main window, so re-raise a secondary window
|
||||||
afterwards with a deferred, liveness-guarded `Raise()` — but never `Raise()` a `wxPopupWindow`, which makes
|
afterwards with a deferred, liveness-guarded `Raise()`; a live menu accelerator consumes the key before
|
||||||
it the key window; a live menu accelerator consumes the key before
|
|
||||||
any wx key event; Control+click arrives as a right-click.
|
any wx key event; Control+click arrives as a right-click.
|
||||||
- **Windows:** `IsDark()` and `wxSYS_COLOUR_*` follow the system app mode, not Orca's theme — use
|
- **Windows:** `IsDark()` and `wxSYS_COLOUR_*` follow the system app mode, not Orca's theme — use
|
||||||
`dark_mode()`; menu bitmaps follow `check_dark_mode()`; windows are not double-buffered by default in
|
`dark_mode()`; menu bitmaps follow `check_dark_mode()`; windows are not double-buffered by default in
|
||||||
|
|||||||
@@ -57,9 +57,8 @@ Contents: [Rules](#rules) · [1. Choosing the window kind](#1-choosing-the-windo
|
|||||||
17. Don't shrink a dropdown below two rows to fit the screen. (§7)
|
17. Don't shrink a dropdown below two rows to fit the screen. (§7)
|
||||||
18. Content that needs typing focus or hosts a `wxWebView` uses a frameless `wxDialog` that hides on
|
18. Content that needs typing focus or hosts a `wxWebView` uses a frameless `wxDialog` that hides on
|
||||||
deactivation, not a transient popup. (§10)
|
deactivation, not a transient popup. (§10)
|
||||||
19. Display-only overlays (HUDs, toasts) use a plain `wxPopupWindow`: `Show()` never gives it focus and it
|
19. Display-only overlays (HUDs, toasts) use a plain `wxPopupWindow`: it never takes focus and never
|
||||||
never auto-dismisses. Never `Raise()` any `wxPopupWindow`: `Raise()` is for top-level windows only, and on
|
auto-dismisses. (§4, §10)
|
||||||
macOS it makes the popup the key window. (§4, §5, §10)
|
|
||||||
20. On MSW, don't `SetFocus()` another window on hover while `wxCurrentPopupWindow` is non-null. (§8)
|
20. On MSW, don't `SetFocus()` another window on hover while `wxCurrentPopupWindow` is non-null. (§8)
|
||||||
21. Menu items use `wxID_ANY` and read `item->GetId()`. `wxNewId()` is deprecated. (§13)
|
21. Menu items use `wxID_ANY` and read `item->GetId()`. `wxNewId()` is deprecated. (§13)
|
||||||
22. Set a menu item's bitmap before `Append`. Don't expect icons on check or radio items. Never call
|
22. Set a menu item's bitmap before `Append`. Don't expect icons on check or radio items. Never call
|
||||||
@@ -357,13 +356,6 @@ compensates for (§6).
|
|||||||
with `ShowWithoutActivating` → `setHidesOnDeactivate:YES` + `orderFront` (`src/osx/carbon/popupwin.cpp:56-75`,
|
with `ShowWithoutActivating` → `setHidesOnDeactivate:YES` + `orderFront` (`src/osx/carbon/popupwin.cpp:56-75`,
|
||||||
`nonownedwnd.mm:938-945`). When the app deactivates, Cocoa hides the panel and shows it again on reactivation.
|
`nonownedwnd.mm:938-945`). When the app deactivates, Cocoa hides the panel and shows it again on reactivation.
|
||||||
wx never calls `OnDismiss`, and `IsShown()` stays true. This applies to plain `wxPopupWindow` overlays too.
|
wx never calls `OnDismiss`, and `IsShown()` stays true. This applies to plain `wxPopupWindow` overlays too.
|
||||||
- `Raise()` activates the popup. It is `makeKeyAndOrderFront` (`src/osx/nonownedwnd_osx.cpp:289-295`,
|
|
||||||
`nonownedwnd.mm:897-899`), and `wxNSPanel` answers `canBecomeKeyWindow` with YES (`nonownedwnd.mm:271`), so
|
|
||||||
the popup becomes the key window. Keys go to it, and the frame loses key status: `windowDidResignKey` →
|
|
||||||
`HandleActivated(0, false)` → `wxEVT_ACTIVATE(false)` on the frame (`nonownedwnd.mm:567-576`,
|
|
||||||
`nonownedwnd_osx.cpp:303-310`). Hiding the key popup gives key back to the frame, which then gets
|
|
||||||
`wxEVT_ACTIVATE(true)` (observed; AppKit behaviour, not in the wx tree). A popup at `NSPopUpMenuWindowLevel`
|
|
||||||
is already above its frame, so `Raise()` buys nothing.
|
|
||||||
- Capture: `Show(true)` makes `m_child` capture the mouse ("Assume that the mouse is outside the popup to begin
|
- Capture: `Show(true)` makes `m_child` capture the mouse ("Assume that the mouse is outside the popup to begin
|
||||||
with", `popupcmn.cpp:421-426`). `OnIdle` releases the capture while the cursor is inside and re-captures it
|
with", `popupcmn.cpp:421-426`). `OnIdle` releases the capture while the cursor is inside and re-captures it
|
||||||
outside, but only when the mouse position has changed since the last idle pass. `s_posLast` is a
|
outside, but only when the mouse position has changed since the last idle pass. `s_posLast` is a
|
||||||
@@ -747,26 +739,8 @@ created with `wxBORDER_NONE | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT | wxF
|
|||||||
- **Rule:** For overlays that must never take keyboard focus (above a GL surface), use a plain
|
- **Rule:** For overlays that must never take keyboard focus (above a GL surface), use a plain
|
||||||
`wxPopupWindow(top, wxBORDER_NONE)`, not a `wxFrame`.
|
`wxPopupWindow(top, wxBORDER_NONE)`, not a `wxFrame`.
|
||||||
**Why:** A frame took the X input focus and swallowed every shortcut until the user clicked the canvas. A popup
|
**Why:** A frame took the X input focus and swallowed every shortcut until the user clicked the canvas. A popup
|
||||||
window does not take focus when shown. On macOS these overlays hide while the app is inactive (§5).
|
window cannot take focus. On macOS these overlays hide while the app is inactive (§5).
|
||||||
Cite: `CAD/DesignCanvas.cpp` (`m_hud`, `m_status_hud`).
|
Cite: `CAD/DesignCanvas.cpp` (`m_hud`, `m_status_hud`).
|
||||||
- **Rule:** Never `Raise()` a `wxPopupWindow`. To bring an overlay up, `Show()` it if it is hidden, then
|
|
||||||
`Move()` it.
|
|
||||||
**Why:** `Raise()` is documented for top-level windows only (`interface/wx/window.h:3028-3029`), and a popup
|
|
||||||
derives from `wxNonOwnedWindow`, not `wxTopLevelWindow` (`include/wx/popupwin.h:33`). On macOS it makes the
|
|
||||||
popup the key window (§5): the popup takes the keys meant for the window below it, and the frame receives
|
|
||||||
`wxEVT_ACTIVATE(false)`. A frame activate handler that hides the overlay on deactivation and re-places it on
|
|
||||||
activation then loops: each `Raise()` deactivates the frame, the hide reactivates it, and the re-place raises
|
|
||||||
again, recursing until the main thread's stack overflows. A popup's `Show()` is `ShowWithoutActivating`
|
|
||||||
and is safe.
|
|
||||||
```cpp
|
|
||||||
// Wrong
|
|
||||||
if (!overlay->IsShown()) overlay->Show();
|
|
||||||
overlay->Move(pos);
|
|
||||||
overlay->Raise();
|
|
||||||
// Right
|
|
||||||
if (!overlay->IsShown()) overlay->Show();
|
|
||||||
overlay->Move(pos);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 11. wxComboCtrl / wxComboPopup
|
## 11. wxComboCtrl / wxComboPopup
|
||||||
|
|
||||||
|
|||||||
@@ -428,8 +428,7 @@ this function does *not* show it", top-level windows only (`interface/wx/window.
|
|||||||
since 3.3 (`docs/changes.txt:144-146`). **[source]** MSW = `::SetForegroundWindow`, subject to the
|
since 3.3 (`docs/changes.txt:144-146`). **[source]** MSW = `::SetForegroundWindow`, subject to the
|
||||||
foreground lock — Windows may only flash the taskbar button (`src/msw/toplevel.cpp:650-655`); GTK =
|
foreground lock — Windows may only flash the taskbar button (`src/msw/toplevel.cpp:650-655`); GTK =
|
||||||
`gtk_window_present` only if shown (`src/gtk/toplevel.cpp:1301-1310`; during a deferred X11 first show it
|
`gtk_window_present` only if shown (`src/gtk/toplevel.cpp:1301-1310`; during a deferred X11 first show it
|
||||||
already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:897-899`),
|
already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:896-899`).
|
||||||
which also makes a `wxPopupWindow` the key window — never `Raise()` a popup (`references/popups-menus.md` §5, §10).
|
|
||||||
|
|
||||||
**Enable.** `Enable(false)` on a parent disables children logically: `IsEnabled()` reflects ancestors,
|
**Enable.** `Enable(false)` on a parent disables children logically: `IsEnabled()` reflects ancestors,
|
||||||
`IsThisEnabled()` the window's own flag (`interface/wx/window.h:3060-3070, 3116-3138`). **[source]** On MSW/macOS wx
|
`IsThisEnabled()` the window's own flag (`interface/wx/window.h:3060-3070, 3116-3138`). **[source]** On MSW/macOS wx
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ on:
|
|||||||
|
|
||||||
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '15 2 * * *' # 10:15 AM Singapore time (UTC+8), when macOS runners are least busy
|
- cron: '0 17 * * *' # run once a day at 1 AM Singapore time (UTC+8)
|
||||||
|
|
||||||
workflow_dispatch: # allows for manual dispatch
|
workflow_dispatch: # allows for manual dispatch
|
||||||
inputs:
|
inputs:
|
||||||
|
|||||||
@@ -49,11 +49,28 @@ jobs:
|
|||||||
key: ${{ inputs.cache-key }}
|
key: ${{ inputs.cache-key }}
|
||||||
|
|
||||||
- uses: lukka/get-cmake@latest
|
- uses: lukka/get-cmake@latest
|
||||||
|
# The windows-11-arm runner needs CMake <= 3.31 (handled in the next step).
|
||||||
|
if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }}
|
||||||
with:
|
with:
|
||||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||||
useCloudCache: true
|
useCloudCache: true
|
||||||
|
|
||||||
|
- name: Install CMake 3.31.x (Windows ARM64)
|
||||||
|
# windows-11-arm ships CMake 4.x, which removed pre-3.5 policy
|
||||||
|
# compatibility AND has incomplete ASM_ARMASM linker modules
|
||||||
|
# (breaks Boost.Context on ARM64). Pin to the last 3.x release.
|
||||||
|
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$ver = "3.31.6"
|
||||||
|
$url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip"
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip"
|
||||||
|
Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force
|
||||||
|
$cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin"
|
||||||
|
if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" }
|
||||||
|
Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin
|
||||||
|
|
||||||
- name: setup dev on Windows
|
- name: setup dev on Windows
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: microsoft/setup-msbuild@v3
|
uses: microsoft/setup-msbuild@v3
|
||||||
|
|||||||
@@ -54,11 +54,28 @@ jobs:
|
|||||||
fail-on-cache-miss: true
|
fail-on-cache-miss: true
|
||||||
|
|
||||||
- uses: lukka/get-cmake@latest
|
- uses: lukka/get-cmake@latest
|
||||||
|
# The windows-11-arm runner needs CMake <= 3.31 (handled in the next step).
|
||||||
|
if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }}
|
||||||
with:
|
with:
|
||||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||||
useCloudCache: true
|
useCloudCache: true
|
||||||
|
|
||||||
|
- name: Install CMake 3.31.x (Windows ARM64)
|
||||||
|
# windows-11-arm ships CMake 4.x, which removed pre-3.5 policy
|
||||||
|
# compatibility AND has incomplete ASM_ARMASM linker modules
|
||||||
|
# (breaks Boost.Context on ARM64). Pin to the last 3.x release.
|
||||||
|
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$ver = "3.31.6"
|
||||||
|
$url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip"
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip"
|
||||||
|
Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force
|
||||||
|
$cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin"
|
||||||
|
if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" }
|
||||||
|
Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin
|
||||||
|
|
||||||
# Compiler cache. Pushes save it, so main keeps it warm; pull requests
|
# Compiler cache. Pushes save it, so main keeps it warm; pull requests
|
||||||
# restore it and discard what they compiled. Objects are keyed on the
|
# restore it and discard what they compiled. Objects are keyed on the
|
||||||
# preprocessed source, the compiler and the flags, so a leg only ever
|
# preprocessed source, the compiler and the flags, so a leg only ever
|
||||||
@@ -259,7 +276,6 @@ jobs:
|
|||||||
# Thanks to RaySajuuk, it's working now
|
# Thanks to RaySajuuk, it's working now
|
||||||
- name: Sign app and notary
|
- name: Sign app and notary
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'macOS' && inputs.macos-combine-only
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'macOS' && inputs.macos-combine-only
|
||||||
timeout-minutes: 30
|
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
env:
|
||||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
# Reports the newest push build of main that was not cancelled, for the README badge.
|
|
||||||
name: Main build status
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_run:
|
|
||||||
workflows: ["Build all"]
|
|
||||||
types: [completed]
|
|
||||||
branches: [main]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
status:
|
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
run: |
|
|
||||||
for attempt in 1 2 3; do
|
|
||||||
conclusion=$(gh api "repos/${{ github.repository }}/actions/workflows/build_all.yml/runs?branch=main&event=push&status=completed&per_page=100" \
|
|
||||||
--jq '[.workflow_runs[] | select(.conclusion != "cancelled")][0].conclusion') && break
|
|
||||||
sleep 10
|
|
||||||
done
|
|
||||||
echo "Latest finished push build of main: $conclusion"
|
|
||||||
[ "$conclusion" = success ]
|
|
||||||
@@ -303,7 +303,7 @@ jobs:
|
|||||||
- name: Mint profiles-repo token
|
- name: Mint profiles-repo token
|
||||||
id: token
|
id: token
|
||||||
if: steps.vendors.outputs.vendors != ''
|
if: steps.vendors.outputs.vendors != ''
|
||||||
uses: actions/create-github-app-token@v1
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
app-id: ${{ secrets.PROFILES_APP_ID }}
|
app-id: ${{ secrets.PROFILES_APP_ID }}
|
||||||
private-key: ${{ secrets.PROFILES_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.PROFILES_APP_PRIVATE_KEY }}
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ jobs:
|
|||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.artifact }}
|
name: ${{ inputs.artifact }}
|
||||||
|
# run_unit_tests.sh installs the plugin tests' numpy with the uv the build stages
|
||||||
|
# beside them; the Windows arm64 build bundles none, so put one on PATH there.
|
||||||
|
- name: Install uv
|
||||||
|
if: runner.os == 'Windows' && runner.arch == 'ARM64'
|
||||||
|
uses: astral-sh/setup-uv@v10.2.0
|
||||||
|
with:
|
||||||
|
version: "0.11.21" # ORCA_UV_VERSION in CMakeLists.txt
|
||||||
|
enable-cache: false
|
||||||
- uses: lukka/get-cmake@latest
|
- uses: lukka/get-cmake@latest
|
||||||
with:
|
with:
|
||||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||||
|
|||||||
@@ -135,7 +135,6 @@ set(ORCA_UV_SHA256_aarch64-apple-darwin "1f921d491ba5ffeea774eb04d6681ecee3
|
|||||||
set(ORCA_UV_SHA256_x86_64-apple-darwin "f3c8e5708a84b920c18b691214d54d2b0da6b984789caae95d47c95120cb7765")
|
set(ORCA_UV_SHA256_x86_64-apple-darwin "f3c8e5708a84b920c18b691214d54d2b0da6b984789caae95d47c95120cb7765")
|
||||||
set(ORCA_UV_SHA256_aarch64-unknown-linux-gnu "88e800834007cc5efd4675f166eb2a51e7e3ad19876d85fa8805a6fb5c922397")
|
set(ORCA_UV_SHA256_aarch64-unknown-linux-gnu "88e800834007cc5efd4675f166eb2a51e7e3ad19876d85fa8805a6fb5c922397")
|
||||||
set(ORCA_UV_SHA256_x86_64-unknown-linux-gnu "8c88519b0ef0af9801fcdee419bbb12116bd9e6b18e162ae093c932d8b264050")
|
set(ORCA_UV_SHA256_x86_64-unknown-linux-gnu "8c88519b0ef0af9801fcdee419bbb12116bd9e6b18e162ae093c932d8b264050")
|
||||||
set(ORCA_UV_SHA256_aarch64-pc-windows-msvc "74e443f8004022dde57a1bd0d10c097830f9ea8feb4ec927db52cd5d805c2f48")
|
|
||||||
set(ORCA_UV_SHA256_x86_64-pc-windows-msvc "ace861f360c6de2babedc1607d0f454b6b09a820dbc8182dc15af927e4df9589")
|
set(ORCA_UV_SHA256_x86_64-pc-windows-msvc "ace861f360c6de2babedc1607d0f454b6b09a820dbc8182dc15af927e4df9589")
|
||||||
|
|
||||||
# Version-scoped cache dir so a version bump invalidates the cached binary.
|
# Version-scoped cache dir so a version bump invalidates the cached binary.
|
||||||
@@ -174,10 +173,7 @@ if(NOT ORCA_BUNDLED_UV_EXECUTABLE)
|
|||||||
set(ORCA_UV_ARCH "x86_64-unknown-linux-gnu")
|
set(ORCA_UV_ARCH "x86_64-unknown-linux-gnu")
|
||||||
endif()
|
endif()
|
||||||
elseif(_orca_uv_proc MATCHES "aarch64|arm64|ARM64")
|
elseif(_orca_uv_proc MATCHES "aarch64|arm64|ARM64")
|
||||||
if(WIN32)
|
if(APPLE)
|
||||||
set(ORCA_UV_ARCH "aarch64-pc-windows-msvc")
|
|
||||||
set(ORCA_UV_EXT "zip")
|
|
||||||
elseif(APPLE)
|
|
||||||
set(ORCA_UV_ARCH "aarch64-apple-darwin")
|
set(ORCA_UV_ARCH "aarch64-apple-darwin")
|
||||||
else()
|
else()
|
||||||
set(ORCA_UV_ARCH "aarch64-unknown-linux-gnu")
|
set(ORCA_UV_ARCH "aarch64-unknown-linux-gnu")
|
||||||
@@ -823,9 +819,7 @@ if(SLIC3R_STATIC)
|
|||||||
set(TBB_STATIC 1)
|
set(TBB_STATIC 1)
|
||||||
endif()
|
endif()
|
||||||
set(TBB_DEBUG 1)
|
set(TBB_DEBUG 1)
|
||||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo" OR MSVC)
|
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "")
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "")
|
|
||||||
endif()
|
|
||||||
find_package(TBB REQUIRED)
|
find_package(TBB REQUIRED)
|
||||||
# include_directories(SYSTEM ${TBB_INCLUDE_DIRS})
|
# include_directories(SYSTEM ${TBB_INCLUDE_DIRS})
|
||||||
# add_definitions(${TBB_DEFINITIONS})
|
# add_definitions(${TBB_DEFINITIONS})
|
||||||
@@ -1307,14 +1301,6 @@ if (WIN32)
|
|||||||
endif()
|
endif()
|
||||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||||
include(InstallRequiredSystemLibraries)
|
include(InstallRequiredSystemLibraries)
|
||||||
# A missing MSVC runtime is an error because an installer without it cannot start on a clean machine.
|
|
||||||
set(_orca_runtime_names ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
|
|
||||||
list(TRANSFORM _orca_runtime_names REPLACE "^.*/" "")
|
|
||||||
if (MSVC AND (NOT "msvcp140.dll" IN_LIST _orca_runtime_names OR NOT "vcruntime140.dll" IN_LIST _orca_runtime_names))
|
|
||||||
set(_orca_runtime_error "CMake ${CMAKE_VERSION} did not find msvcp140.dll and vcruntime140.dll for MSVC ${MSVC_VERSION}. Update CMake to a release that supports this Visual Studio.")
|
|
||||||
message(WARNING "${_orca_runtime_error}")
|
|
||||||
install(CODE "message(FATAL_ERROR \"${_orca_runtime_error}\")")
|
|
||||||
endif ()
|
|
||||||
install (PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ".")
|
install (PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ".")
|
||||||
elseif (SLIC3R_FHS)
|
elseif (SLIC3R_FHS)
|
||||||
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
|
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<a href="https://trendshift.io/repositories/15552" target="_blank"><img src="https://trendshift.io/api/badge/repositories/15552" alt="OrcaSlicer%2FOrcaSlicer | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
<a href="https://trendshift.io/repositories/15552" target="_blank"><img src="https://trendshift.io/api/badge/repositories/15552" alt="OrcaSlicer%2FOrcaSlicer | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
[](https://github.com/OrcaSlicer/OrcaSlicer/stargazers) [](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml)
|
[](https://github.com/OrcaSlicer/OrcaSlicer/stargazers) [](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml)
|
||||||
|
|
||||||
OrcaSlicer: an open source Next-Gen Slicing Software for Precision 3D Prints.
|
OrcaSlicer: an open source Next-Gen Slicing Software for Precision 3D Prints.
|
||||||
Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.
|
Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.
|
||||||
|
|||||||
@@ -282,7 +282,11 @@ if "%install_deps%" == "ON" (
|
|||||||
call :note_failed "Visual Studio" !errorlevel!
|
call :note_failed "Visual Studio" !errorlevel!
|
||||||
)
|
)
|
||||||
|
|
||||||
call :print_and_run winget install !winget_args! --id=Kitware.CMake
|
REM CMake 4 dropped pre-3.5 policy support and ships incomplete ASM_ARMASM
|
||||||
|
REM linker modules, which breaks Boost.Context on ARM64. CI pins the same way.
|
||||||
|
set "cmake_version_flag="
|
||||||
|
if /I "%arch%" == "ARM64" set "cmake_version_flag=--version 3.31.8"
|
||||||
|
call :print_and_run winget install !winget_args! --id=Kitware.CMake !cmake_version_flag!
|
||||||
call :note_failed CMake !errorlevel!
|
call :note_failed CMake !errorlevel!
|
||||||
call :print_and_run winget install !winget_args! --id=StrawberryPerl.StrawberryPerl
|
call :print_and_run winget install !winget_args! --id=StrawberryPerl.StrawberryPerl
|
||||||
call :note_failed Perl !errorlevel!
|
call :note_failed Perl !errorlevel!
|
||||||
|
|||||||
@@ -29,15 +29,6 @@ if(WIN32)
|
|||||||
# driven through nmake from a Ninja configure step.
|
# driven through nmake from a Ninja configure step.
|
||||||
set(_conf_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} perl Configure )
|
set(_conf_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} perl Configure )
|
||||||
set(_cross_comp_prefix_line "")
|
set(_cross_comp_prefix_line "")
|
||||||
if("${DEPS_ARCH}" STREQUAL "arm64")
|
|
||||||
# OpenSSL's VC configs pass /Gs0, which puts a __chkstk probe in every
|
|
||||||
# function. MSVC 14.51 and 14.52 (VS 2026) for ARM64 emit that call
|
|
||||||
# before the prologue saves LR, so the function returns into itself;
|
|
||||||
# in tls_parse_all_extensions that breaks every TLS handshake. 14.44
|
|
||||||
# (VS 2022) is unaffected. Restore cl's default threshold: Configure
|
|
||||||
# appends /Gs4096 after /Gs0, and the later option wins.
|
|
||||||
set(_openssl_extra_cflags /Gs4096)
|
|
||||||
endif()
|
|
||||||
set(_make_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake)
|
set(_make_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake)
|
||||||
set(_install_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake install_sw )
|
set(_install_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake install_sw )
|
||||||
else()
|
else()
|
||||||
@@ -80,7 +71,6 @@ ExternalProject_Add(dep_OpenSSL
|
|||||||
# prefix stays single-layout.
|
# prefix stays single-layout.
|
||||||
"--libdir=lib"
|
"--libdir=lib"
|
||||||
${_cross_comp_prefix_line}
|
${_cross_comp_prefix_line}
|
||||||
${_openssl_extra_cflags}
|
|
||||||
no-shared
|
no-shared
|
||||||
no-asm
|
no-asm
|
||||||
no-ssl3-method
|
no-ssl3-method
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ add_subdirectory(stb_dxt) # Header-only STB DXT compression library
|
|||||||
# Static libraries
|
# Static libraries
|
||||||
add_subdirectory(Shiny)
|
add_subdirectory(Shiny)
|
||||||
add_subdirectory(admesh)
|
add_subdirectory(admesh)
|
||||||
|
add_subdirectory(clipper)
|
||||||
add_subdirectory(clipper2)
|
add_subdirectory(clipper2)
|
||||||
add_subdirectory(expat)
|
add_subdirectory(expat)
|
||||||
add_subdirectory(glu-libtess)
|
add_subdirectory(glu-libtess)
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(clipper)
|
||||||
|
|
||||||
|
add_library(clipper STATIC
|
||||||
|
# We are using ClipperLib compiled as part of the libslic3r project using Slic3r::Point as its base type.
|
||||||
|
# clipper.cpp
|
||||||
|
# clipper.hpp
|
||||||
|
clipper_z.cpp
|
||||||
|
clipper_z.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(clipper SYSTEM
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(clipper
|
||||||
|
PUBLIC Eigen3::Eigen
|
||||||
|
PRIVATE TBB::tbb TBB::tbbmalloc
|
||||||
|
)
|
||||||
@@ -0,0 +1,606 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Author : Angus Johnson *
|
||||||
|
* Version : 6.4.2 *
|
||||||
|
* Date : 27 February 2017 *
|
||||||
|
* Website : http://www.angusj.com *
|
||||||
|
* Copyright : Angus Johnson 2010-2017 *
|
||||||
|
* *
|
||||||
|
* License: *
|
||||||
|
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt *
|
||||||
|
* *
|
||||||
|
* Attributions: *
|
||||||
|
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
|
||||||
|
* "A generic solution to polygon clipping" *
|
||||||
|
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
|
||||||
|
* http://portal.acm.org/citation.cfm?id=129906 *
|
||||||
|
* *
|
||||||
|
* Computer graphics and geometric modeling: implementation and algorithms *
|
||||||
|
* By Max K. Agoston *
|
||||||
|
* Springer; 1 edition (January 4, 2005) *
|
||||||
|
* http://books.google.com/books?q=vatti+clipping+agoston *
|
||||||
|
* *
|
||||||
|
* See also: *
|
||||||
|
* "Polygon Offsetting by Computing Winding Numbers" *
|
||||||
|
* Paper no. DETC2005-85513 pp. 565-575 *
|
||||||
|
* ASME 2005 International Design Engineering Technical Conferences *
|
||||||
|
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
||||||
|
* September 24-28, 2005 , Long Beach, California, USA *
|
||||||
|
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
||||||
|
* *
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef clipper_hpp
|
||||||
|
#define clipper_hpp
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
#include <oneapi/tbb/scalable_allocator.h>
|
||||||
|
|
||||||
|
#define CLIPPER_VERSION "6.2.6"
|
||||||
|
|
||||||
|
//CLIPPERLIB_USE_XYZ: adds a Z member to IntPoint. Adds a minor cost to perfomance.
|
||||||
|
//#define CLIPPERLIB_USE_XYZ
|
||||||
|
|
||||||
|
//use_lines: Enables line clipping. Adds a very minor cost to performance.
|
||||||
|
#define use_lines
|
||||||
|
|
||||||
|
//use_deprecated: Enables temporary support for the obsolete functions
|
||||||
|
//#define use_deprecated
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ostream>
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_NAMESPACE_PREFIX
|
||||||
|
namespace CLIPPERLIB_NAMESPACE_PREFIX {
|
||||||
|
#endif // CLIPPERLIB_NAMESPACE_PREFIX
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
namespace ClipperLib_Z {
|
||||||
|
#else
|
||||||
|
namespace ClipperLib {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
|
||||||
|
enum PolyType { ptSubject, ptClip };
|
||||||
|
//By far the most widely used winding rules for polygon filling are
|
||||||
|
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
|
||||||
|
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
|
||||||
|
//see http://glprogramming.com/red/chapter11.html
|
||||||
|
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||||
|
|
||||||
|
// If defined, Clipper will work with 32bit signed int coordinates to reduce memory
|
||||||
|
// consumption and to speed up exact orientation predicate calculation.
|
||||||
|
// In that case, coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||||
|
// #define CLIPPERLIB_INT32
|
||||||
|
|
||||||
|
// Point coordinate type
|
||||||
|
#ifdef CLIPPERLIB_INT32
|
||||||
|
// Coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||||
|
using cInt = int32_t;
|
||||||
|
using CrossProductType = int64_t;
|
||||||
|
#else
|
||||||
|
using cInt = int64_t;
|
||||||
|
using CrossProductType = double;
|
||||||
|
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
|
||||||
|
static constexpr cInt const loRange = 0x3FFFFFFF; // 0x3FFFFFFF = 1 073 741 823
|
||||||
|
// Maximum allowed cInt value.
|
||||||
|
static constexpr cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||||
|
#endif // CLIPPERLIB_INT32
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_INTPOINT_TYPE
|
||||||
|
using IntPoint = CLIPPERLIB_INTPOINT_TYPE;
|
||||||
|
#else // CLIPPERLIB_INTPOINT_TYPE
|
||||||
|
using IntPoint = Eigen::Matrix<cInt,
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
3
|
||||||
|
#else // CLIPPERLIB_USE_XYZ
|
||||||
|
2
|
||||||
|
#endif // CLIPPERLIB_USE_XYZ
|
||||||
|
, 1, Eigen::DontAlign>;
|
||||||
|
#endif // CLIPPERLIB_INTPOINT_TYPE
|
||||||
|
|
||||||
|
using DoublePoint = Eigen::Matrix<double, 2, 1, Eigen::DontAlign>;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<typename BaseType>
|
||||||
|
using Allocator = tbb::scalable_allocator<BaseType>;
|
||||||
|
//using Allocator = std::allocator<BaseType>;
|
||||||
|
using Path = std::vector<IntPoint, Allocator<IntPoint>>;
|
||||||
|
using Paths = std::vector<Path, Allocator<Path>>;
|
||||||
|
|
||||||
|
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
|
||||||
|
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
|
||||||
|
|
||||||
|
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
|
||||||
|
std::ostream& operator <<(std::ostream &s, const Path &p);
|
||||||
|
std::ostream& operator <<(std::ostream &s, const Paths &p);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
typedef std::function<void(const IntPoint& e1bot, const IntPoint& e1top, const IntPoint& e2bot, const IntPoint& e2top, IntPoint& pt)> ZFillCallback;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
|
||||||
|
enum JoinType {jtSquare, jtRound, jtMiter};
|
||||||
|
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
|
||||||
|
|
||||||
|
class PolyNode;
|
||||||
|
typedef std::vector<PolyNode*, Allocator<PolyNode*>> PolyNodes;
|
||||||
|
|
||||||
|
class PolyNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PolyNode() : Parent(0), Index(0), m_IsOpen(false) {}
|
||||||
|
virtual ~PolyNode(){};
|
||||||
|
Path Contour;
|
||||||
|
PolyNodes Childs;
|
||||||
|
PolyNode* Parent;
|
||||||
|
// Traversal of the polygon tree in a depth first fashion.
|
||||||
|
PolyNode* GetNext() const { return Childs.empty() ? GetNextSiblingUp() : Childs.front(); }
|
||||||
|
bool IsHole() const;
|
||||||
|
bool IsOpen() const { return m_IsOpen; }
|
||||||
|
int ChildCount() const { return (int)Childs.size(); }
|
||||||
|
private:
|
||||||
|
unsigned Index; //node index in Parent.Childs
|
||||||
|
bool m_IsOpen;
|
||||||
|
JoinType m_jointype;
|
||||||
|
EndType m_endtype;
|
||||||
|
PolyNode* GetNextSiblingUp() const { return Parent ? ((Index == Parent->Childs.size() - 1) ? Parent->GetNextSiblingUp() : Parent->Childs[Index + 1]) : nullptr; }
|
||||||
|
void AddChild(PolyNode& child);
|
||||||
|
friend class Clipper; //to access Index
|
||||||
|
friend class ClipperOffset;
|
||||||
|
friend class PolyTree; //to implement the PolyTree::move operator
|
||||||
|
};
|
||||||
|
|
||||||
|
class PolyTree: public PolyNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PolyTree() {}
|
||||||
|
PolyTree(PolyTree &&src) { *this = std::move(src); }
|
||||||
|
virtual ~PolyTree(){Clear();};
|
||||||
|
PolyTree& operator=(PolyTree &&src) {
|
||||||
|
AllNodes = std::move(src.AllNodes);
|
||||||
|
Contour = std::move(src.Contour);
|
||||||
|
Childs = std::move(src.Childs);
|
||||||
|
Parent = nullptr;
|
||||||
|
Index = src.Index;
|
||||||
|
m_IsOpen = src.m_IsOpen;
|
||||||
|
m_jointype = src.m_jointype;
|
||||||
|
m_endtype = src.m_endtype;
|
||||||
|
for (size_t i = 0; i < Childs.size(); ++ i)
|
||||||
|
Childs[i]->Parent = this;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
PolyNode* GetFirst() const { return Childs.empty() ? nullptr : Childs.front(); }
|
||||||
|
void Clear() { AllNodes.clear(); Childs.clear(); }
|
||||||
|
int Total() const;
|
||||||
|
void RemoveOutermostPolygon();
|
||||||
|
private:
|
||||||
|
PolyTree(const PolyTree &src) = delete;
|
||||||
|
PolyTree& operator=(const PolyTree &src) = delete;
|
||||||
|
std::vector<PolyNode, Allocator<PolyNode>> AllNodes;
|
||||||
|
friend class Clipper; //to access AllNodes
|
||||||
|
};
|
||||||
|
|
||||||
|
double Area(const Path &poly);
|
||||||
|
inline bool Orientation(const Path &poly) { return Area(poly) >= 0; }
|
||||||
|
int PointInPolygon(const IntPoint &pt, const Path &path);
|
||||||
|
|
||||||
|
// Union with "strictly simple" fix enabled.
|
||||||
|
Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType = pftNonZero, bool strictly_simple = true);
|
||||||
|
|
||||||
|
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
|
||||||
|
void CleanPolygon(Path& poly, double distance = 1.415);
|
||||||
|
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
|
||||||
|
void CleanPolygons(Paths& polys, double distance = 1.415);
|
||||||
|
|
||||||
|
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
|
||||||
|
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
|
||||||
|
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
|
||||||
|
|
||||||
|
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
|
||||||
|
void PolyTreeToPaths(PolyTree&& polytree, Paths& paths);
|
||||||
|
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
|
||||||
|
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
|
||||||
|
|
||||||
|
void ReversePath(Path& p);
|
||||||
|
void ReversePaths(Paths& p);
|
||||||
|
|
||||||
|
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
|
||||||
|
|
||||||
|
//enums that are used internally ...
|
||||||
|
enum EdgeSide { esLeft = 1, esRight = 2};
|
||||||
|
|
||||||
|
// namespace Internal {
|
||||||
|
//forward declarations (for stuff used internally) ...
|
||||||
|
struct TEdge {
|
||||||
|
// Bottom point of this edge (with minimum Y).
|
||||||
|
IntPoint Bot;
|
||||||
|
// Current position.
|
||||||
|
IntPoint Curr;
|
||||||
|
// Top point of this edge (with maximum Y).
|
||||||
|
IntPoint Top;
|
||||||
|
// Slope (dx/dy). For horiontal edges, the slope is set to HORIZONTAL (-1.0E+40).
|
||||||
|
double Dx;
|
||||||
|
PolyType PolyTyp;
|
||||||
|
EdgeSide Side;
|
||||||
|
// Winding number delta. 1 or -1 depending on winding direction, 0 for open paths and flat closed paths.
|
||||||
|
int WindDelta;
|
||||||
|
int WindCnt;
|
||||||
|
int WindCnt2; //winding count of the opposite polytype
|
||||||
|
int OutIdx;
|
||||||
|
// Next edge in the input path.
|
||||||
|
TEdge *Next;
|
||||||
|
// Previous edge in the input path.
|
||||||
|
TEdge *Prev;
|
||||||
|
// Next edge in the Local Minima List chain.
|
||||||
|
TEdge *NextInLML;
|
||||||
|
TEdge *NextInAEL;
|
||||||
|
TEdge *PrevInAEL;
|
||||||
|
TEdge *NextInSEL;
|
||||||
|
TEdge *PrevInSEL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntersectNode {
|
||||||
|
IntersectNode(TEdge *Edge1, TEdge *Edge2, IntPoint Pt) :
|
||||||
|
Edge1(Edge1), Edge2(Edge2), Pt(Pt) {}
|
||||||
|
TEdge *Edge1;
|
||||||
|
TEdge *Edge2;
|
||||||
|
IntPoint Pt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalMinimum {
|
||||||
|
cInt Y;
|
||||||
|
TEdge *LeftBound;
|
||||||
|
TEdge *RightBound;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Point of an output polygon.
|
||||||
|
// 36B on 64bit system without CLIPPERLIB_USE_XYZ.
|
||||||
|
struct OutPt {
|
||||||
|
// 4B
|
||||||
|
int Idx;
|
||||||
|
// 16B without CLIPPERLIB_USE_XYZ / 24B with CLIPPERLIB_USE_XYZ
|
||||||
|
IntPoint Pt;
|
||||||
|
// 4B on 32bit system, 8B on 64bit system
|
||||||
|
OutPt *Next;
|
||||||
|
// 4B on 32bit system, 8B on 64bit system
|
||||||
|
OutPt *Prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
using OutPts = std::vector<OutPt, Allocator<OutPt>>;
|
||||||
|
|
||||||
|
// Output polygon.
|
||||||
|
struct OutRec {
|
||||||
|
int Idx;
|
||||||
|
bool IsHole;
|
||||||
|
bool IsOpen;
|
||||||
|
//The 'FirstLeft' field points to another OutRec that contains or is the
|
||||||
|
//'parent' of OutRec. It is 'first left' because the ActiveEdgeList (AEL) is
|
||||||
|
//parsed left from the current edge (owning OutRec) until the owner OutRec
|
||||||
|
//is found. This field simplifies sorting the polygons into a tree structure
|
||||||
|
//which reflects the parent/child relationships of all polygons.
|
||||||
|
//This field should be renamed Parent, and will be later.
|
||||||
|
OutRec* FirstLeft;
|
||||||
|
// Used only by void Clipper::BuildResult2(PolyTree& polytree)
|
||||||
|
PolyNode* PolyNd;
|
||||||
|
// Linked list of output points, dynamically allocated.
|
||||||
|
OutPt* Pts;
|
||||||
|
OutPt* BottomPt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Join {
|
||||||
|
Join(OutPt *OutPt1, OutPt *OutPt2, IntPoint OffPt) :
|
||||||
|
OutPt1(OutPt1), OutPt2(OutPt2), OffPt(OffPt) {}
|
||||||
|
OutPt *OutPt1;
|
||||||
|
OutPt *OutPt2;
|
||||||
|
IntPoint OffPt;
|
||||||
|
};
|
||||||
|
// }; // namespace Internal
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//ClipperBase is the ancestor to the Clipper class. It should not be
|
||||||
|
//instantiated directly. This class simply abstracts the conversion of sets of
|
||||||
|
//polygon coordinates into edge objects that are stored in a LocalMinima list.
|
||||||
|
class ClipperBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClipperBase() :
|
||||||
|
#ifndef CLIPPERLIB_INT32
|
||||||
|
m_UseFullRange(false),
|
||||||
|
#endif // CLIPPERLIB_INT32
|
||||||
|
m_HasOpenPaths(false) {}
|
||||||
|
~ClipperBase() { Clear(); }
|
||||||
|
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
|
||||||
|
|
||||||
|
template<typename PathsProvider>
|
||||||
|
bool AddPaths(PathsProvider &&paths_provider, PolyType PolyTyp, bool Closed)
|
||||||
|
{
|
||||||
|
size_t num_paths = paths_provider.size();
|
||||||
|
if (num_paths == 0)
|
||||||
|
return false;
|
||||||
|
if (num_paths == 1)
|
||||||
|
return AddPath(*paths_provider.begin(), PolyTyp, Closed);
|
||||||
|
|
||||||
|
std::vector<int, Allocator<int>> num_edges(num_paths, 0);
|
||||||
|
int num_edges_total = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
for (const Path &pg : paths_provider) {
|
||||||
|
// Remove duplicate end point from a closed input path.
|
||||||
|
// Remove duplicate points from the end of the input path.
|
||||||
|
int highI = (int)pg.size() -1;
|
||||||
|
if (Closed)
|
||||||
|
while (highI > 0 && (pg[highI] == pg[0]))
|
||||||
|
--highI;
|
||||||
|
while (highI > 0 && (pg[highI] == pg[highI -1]))
|
||||||
|
--highI;
|
||||||
|
if ((Closed && highI < 2) || (!Closed && highI < 1))
|
||||||
|
highI = -1;
|
||||||
|
num_edges[i ++] = highI + 1;
|
||||||
|
num_edges_total += highI + 1;
|
||||||
|
}
|
||||||
|
if (num_edges_total == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Allocate a new edge array.
|
||||||
|
std::vector<TEdge, Allocator<TEdge>> edges(num_edges_total);
|
||||||
|
// Fill in the edge array.
|
||||||
|
bool result = false;
|
||||||
|
TEdge *p_edge = edges.data();
|
||||||
|
i = 0;
|
||||||
|
for (const Path &pg : paths_provider) {
|
||||||
|
if (num_edges[i] && !pg.empty()) {
|
||||||
|
bool res = AddPathInternal(pg, num_edges[i] - 1, PolyTyp, Closed, p_edge);
|
||||||
|
if (res) {
|
||||||
|
p_edge += num_edges[i];
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
// At least some edges were generated. Remember the edge array.
|
||||||
|
m_edges.emplace_back(std::move(edges));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
IntRect GetBounds();
|
||||||
|
// By default, when three or more vertices are collinear in input polygons (subject or clip), the Clipper object removes the 'inner' vertices before clipping.
|
||||||
|
// When enabled the PreserveCollinear property prevents this default behavior to allow these inner vertices to appear in the solution.
|
||||||
|
bool PreserveCollinear() const {return m_PreserveCollinear;};
|
||||||
|
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
|
||||||
|
protected:
|
||||||
|
bool AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge* edges);
|
||||||
|
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
|
||||||
|
void Reset();
|
||||||
|
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
|
||||||
|
TEdge* DescendToMin(TEdge *&E);
|
||||||
|
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
|
||||||
|
|
||||||
|
// Local minima (Y, left edge, right edge) sorted by ascending Y.
|
||||||
|
std::vector<LocalMinimum, Allocator<LocalMinimum>> m_MinimaList;
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_INT32
|
||||||
|
static constexpr const bool m_UseFullRange = false;
|
||||||
|
#else // CLIPPERLIB_INT32
|
||||||
|
// True if the input polygons have abs values higher than loRange, but lower than hiRange.
|
||||||
|
// False if the input polygons have abs values lower or equal to loRange.
|
||||||
|
bool m_UseFullRange;
|
||||||
|
#endif // CLIPPERLIB_INT32
|
||||||
|
|
||||||
|
// A vector of edges per each input path.
|
||||||
|
using Edges = std::vector<TEdge, Allocator<TEdge>>;
|
||||||
|
std::vector<Edges, Allocator<Edges>> m_edges;
|
||||||
|
// Don't remove intermediate vertices of a collinear sequence of points.
|
||||||
|
bool m_PreserveCollinear;
|
||||||
|
// Is any of the paths inserted by AddPath() or AddPaths() open?
|
||||||
|
bool m_HasOpenPaths;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Clipper : public ClipperBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Clipper(int initOptions = 0);
|
||||||
|
~Clipper() { Clear(); }
|
||||||
|
void Clear() { ClipperBase::Clear(); DisposeAllOutRecs(); }
|
||||||
|
bool Execute(ClipType clipType,
|
||||||
|
Paths &solution,
|
||||||
|
PolyFillType fillType = pftEvenOdd)
|
||||||
|
{ return Execute(clipType, solution, fillType, fillType); }
|
||||||
|
bool Execute(ClipType clipType,
|
||||||
|
Paths &solution,
|
||||||
|
PolyFillType subjFillType,
|
||||||
|
PolyFillType clipFillType);
|
||||||
|
bool Execute(ClipType clipType,
|
||||||
|
PolyTree &polytree,
|
||||||
|
PolyFillType fillType = pftEvenOdd)
|
||||||
|
{ return Execute(clipType, polytree, fillType, fillType); }
|
||||||
|
bool Execute(ClipType clipType,
|
||||||
|
PolyTree &polytree,
|
||||||
|
PolyFillType subjFillType,
|
||||||
|
PolyFillType clipFillType);
|
||||||
|
bool ReverseSolution() const { return m_ReverseOutput; };
|
||||||
|
void ReverseSolution(bool value) {m_ReverseOutput = value;};
|
||||||
|
bool StrictlySimple() const {return m_StrictSimple;};
|
||||||
|
void StrictlySimple(bool value) {m_StrictSimple = value;};
|
||||||
|
//set the callback function for z value filling on intersections (otherwise Z is 0)
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
void ZFillFunction(ZFillCallback zFillFunc) { m_ZFill = zFillFunc; }
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
|
void Reset();
|
||||||
|
virtual bool ExecuteInternal();
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Output polygons.
|
||||||
|
std::deque<OutRec, Allocator<OutRec>> m_PolyOuts;
|
||||||
|
// Output points, allocated by a continuous sets of m_OutPtsChunkSize.
|
||||||
|
static constexpr const size_t m_OutPtsChunkSize = 32;
|
||||||
|
std::deque<std::array<OutPt, m_OutPtsChunkSize>, Allocator<std::array<OutPt, m_OutPtsChunkSize>>> m_OutPts;
|
||||||
|
// List of free output points, to be used before taking a point from m_OutPts or allocating a new chunk.
|
||||||
|
OutPt *m_OutPtsFree;
|
||||||
|
size_t m_OutPtsChunkLast;
|
||||||
|
|
||||||
|
std::vector<Join, Allocator<Join>> m_Joins;
|
||||||
|
std::vector<Join, Allocator<Join>> m_GhostJoins;
|
||||||
|
std::vector<IntersectNode, Allocator<IntersectNode>> m_IntersectList;
|
||||||
|
ClipType m_ClipType;
|
||||||
|
// A priority queue (a binary heap) of Y coordinates.
|
||||||
|
using cInts = std::vector<cInt, Allocator<cInt>>;
|
||||||
|
std::priority_queue<cInt, cInts> m_Scanbeam;
|
||||||
|
// Maxima are collected by ProcessEdgesAtTopOfScanbeam(), consumed by ProcessHorizontal().
|
||||||
|
cInts m_Maxima;
|
||||||
|
TEdge *m_ActiveEdges;
|
||||||
|
TEdge *m_SortedEdges;
|
||||||
|
PolyFillType m_ClipFillType;
|
||||||
|
PolyFillType m_SubjFillType;
|
||||||
|
bool m_ReverseOutput;
|
||||||
|
// Does the result go to a PolyTree or Paths?
|
||||||
|
bool m_UsingPolyTree;
|
||||||
|
bool m_StrictSimple;
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
ZFillCallback m_ZFill; //custom callback
|
||||||
|
#endif
|
||||||
|
void SetWindingCount(TEdge& edge) const;
|
||||||
|
bool IsEvenOddFillType(const TEdge& edge) const
|
||||||
|
{ return (edge.PolyTyp == ptSubject) ? m_SubjFillType == pftEvenOdd : m_ClipFillType == pftEvenOdd; }
|
||||||
|
bool IsEvenOddAltFillType(const TEdge& edge) const
|
||||||
|
{ return (edge.PolyTyp == ptSubject) ? m_ClipFillType == pftEvenOdd : m_SubjFillType == pftEvenOdd; }
|
||||||
|
void InsertLocalMinimaIntoAEL(const cInt botY);
|
||||||
|
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
|
||||||
|
void AddEdgeToSEL(TEdge *edge);
|
||||||
|
void CopyAELToSEL();
|
||||||
|
void DeleteFromSEL(TEdge *e);
|
||||||
|
void DeleteFromAEL(TEdge *e);
|
||||||
|
void UpdateEdgeIntoAEL(TEdge *&e);
|
||||||
|
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
|
||||||
|
bool IsContributing(const TEdge& edge) const;
|
||||||
|
bool IsTopHorz(const cInt XPos);
|
||||||
|
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
|
||||||
|
void DoMaxima(TEdge *e);
|
||||||
|
void ProcessHorizontals();
|
||||||
|
void ProcessHorizontal(TEdge *horzEdge);
|
||||||
|
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
|
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
|
OutRec* GetOutRec(int idx);
|
||||||
|
void AppendPolygon(TEdge *e1, TEdge *e2);
|
||||||
|
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
|
||||||
|
OutRec* CreateOutRec();
|
||||||
|
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
|
||||||
|
OutPt* GetLastOutPt(TEdge *e);
|
||||||
|
OutPt* AllocateOutPt();
|
||||||
|
OutPt* DupOutPt(OutPt* outPt, bool InsertAfter);
|
||||||
|
// Add the point to a list of free points.
|
||||||
|
void DisposeOutPt(OutPt *pt) { pt->Next = m_OutPtsFree; m_OutPtsFree = pt; }
|
||||||
|
void DisposeOutPts(OutPt*& pp) { if (pp != nullptr) { pp->Prev->Next = m_OutPtsFree; m_OutPtsFree = pp; } }
|
||||||
|
void DisposeAllOutRecs();
|
||||||
|
bool ProcessIntersections(const cInt topY);
|
||||||
|
void BuildIntersectList(const cInt topY);
|
||||||
|
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
|
||||||
|
void BuildResult(Paths& polys);
|
||||||
|
void BuildResult2(PolyTree& polytree);
|
||||||
|
void SetHoleState(TEdge *e, OutRec *outrec);
|
||||||
|
bool FixupIntersectionOrder();
|
||||||
|
void FixupOutPolygon(OutRec &outrec);
|
||||||
|
void FixupOutPolyline(OutRec &outrec);
|
||||||
|
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
|
||||||
|
void FixHoleLinkage(OutRec &outrec);
|
||||||
|
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
|
||||||
|
bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, const IntPoint &Pt, bool DiscardLeft);
|
||||||
|
void JoinCommonEdges();
|
||||||
|
void DoSimplePolygons();
|
||||||
|
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||||
|
void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
|
||||||
|
void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||||
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
|
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ClipperOffset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25, double shortestEdgeLength = 0.) :
|
||||||
|
MiterLimit(miterLimit), ArcTolerance(roundPrecision), ShortestEdgeLength(shortestEdgeLength), m_lowest(-1, 0) {}
|
||||||
|
~ClipperOffset() { Clear(); }
|
||||||
|
void AddPath(const Path& path, JoinType joinType, EndType endType);
|
||||||
|
template<typename PathsProvider>
|
||||||
|
void AddPaths(PathsProvider &&paths, JoinType joinType, EndType endType) {
|
||||||
|
for (const Path &path : paths)
|
||||||
|
AddPath(path, joinType, endType);
|
||||||
|
}
|
||||||
|
void Execute(Paths& solution, double delta);
|
||||||
|
void Execute(PolyTree& solution, double delta);
|
||||||
|
void Clear();
|
||||||
|
double MiterLimit;
|
||||||
|
double ArcTolerance;
|
||||||
|
double ShortestEdgeLength;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Paths m_destPolys;
|
||||||
|
Path m_srcPoly;
|
||||||
|
Path m_destPoly;
|
||||||
|
std::vector<DoublePoint, Allocator<DoublePoint>> m_normals;
|
||||||
|
double m_delta, m_sinA, m_sin, m_cos;
|
||||||
|
double m_miterLim, m_StepsPerRad;
|
||||||
|
// x: index of the lowest contour in m_polyNodes
|
||||||
|
// y: index of the lowest point in the lowest contour
|
||||||
|
IntPoint m_lowest;
|
||||||
|
PolyNode m_polyNodes;
|
||||||
|
|
||||||
|
void FixOrientations();
|
||||||
|
void DoOffset(double delta);
|
||||||
|
void OffsetPoint(int j, int& k, JoinType jointype);
|
||||||
|
void DoSquare(int j, int k);
|
||||||
|
void DoMiter(int j, int k, double r);
|
||||||
|
void DoRound(int j, int k);
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class clipperException : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
clipperException(const char* description): m_descr(description) {}
|
||||||
|
virtual ~clipperException() throw() {}
|
||||||
|
virtual const char* what() const throw() {return m_descr.c_str();}
|
||||||
|
private:
|
||||||
|
std::string m_descr;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Union with "strictly simple" fix enabled.
|
||||||
|
template<typename PathsProvider>
|
||||||
|
inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftNonZero, bool strictly_simple = true) {
|
||||||
|
Clipper c;
|
||||||
|
c.StrictlySimple(strictly_simple);
|
||||||
|
c.AddPaths(std::forward<PathsProvider>(in_polys), ptSubject, true);
|
||||||
|
Paths out;
|
||||||
|
c.Execute(ctUnion, out, fillType, fillType);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //ClipperLib namespace
|
||||||
|
|
||||||
|
#ifdef CLIPPERLIB_NAMESPACE_PREFIX
|
||||||
|
} // namespace CLIPPERLIB_NAMESPACE_PREFIX
|
||||||
|
#endif // CLIPPERLIB_NAMESPACE_PREFIX
|
||||||
|
|
||||||
|
#endif //clipper_hpp
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// Hackish wrapper around the ClipperLib library to compile the Clipper library with the Z support.
|
||||||
|
|
||||||
|
// Enable the Z coordinate support.
|
||||||
|
#define CLIPPERLIB_USE_XYZ
|
||||||
|
|
||||||
|
// and let it compile
|
||||||
|
#include "clipper.cpp"
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Hackish wrapper around the ClipperLib library to compile the Clipper library with the Z support.
|
||||||
|
|
||||||
|
#ifndef clipper_z_hpp
|
||||||
|
#ifdef clipper_hpp
|
||||||
|
#error "You should include clipper_z.hpp before clipper.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define clipper_z_hpp
|
||||||
|
|
||||||
|
// Enable the Z coordinate support.
|
||||||
|
#define CLIPPERLIB_USE_XYZ
|
||||||
|
|
||||||
|
#include "clipper.hpp"
|
||||||
|
|
||||||
|
#undef clipper_hpp
|
||||||
|
#undef CLIPPERLIB_USE_XYZ
|
||||||
|
|
||||||
|
#endif // clipper_z_hpp
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(Clipper2 VERSION 2.0.1 LANGUAGES C CXX)
|
project(Clipper2 VERSION 1.5.2 LANGUAGES C CXX)
|
||||||
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
@@ -19,7 +19,6 @@ set(CLIPPER2_INC
|
|||||||
Clipper2Lib/include/clipper2/clipper.minkowski.h
|
Clipper2Lib/include/clipper2/clipper.minkowski.h
|
||||||
Clipper2Lib/include/clipper2/clipper.offset.h
|
Clipper2Lib/include/clipper2/clipper.offset.h
|
||||||
Clipper2Lib/include/clipper2/clipper.rectclip.h
|
Clipper2Lib/include/clipper2/clipper.rectclip.h
|
||||||
Clipper2Lib/include/clipper2/clipper.triangulation.h
|
|
||||||
Clipper2Lib/include/clipper2/clipper2_z.hpp
|
Clipper2Lib/include/clipper2/clipper2_z.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,7 +26,6 @@ set(CLIPPER2_SRC
|
|||||||
Clipper2Lib/src/clipper.engine.cpp
|
Clipper2Lib/src/clipper.engine.cpp
|
||||||
Clipper2Lib/src/clipper.offset.cpp
|
Clipper2Lib/src/clipper.offset.cpp
|
||||||
Clipper2Lib/src/clipper.rectclip.cpp
|
Clipper2Lib/src/clipper.rectclip.cpp
|
||||||
Clipper2Lib/src/clipper.triangulation.cpp
|
|
||||||
Clipper2Lib/src/clipper2_z.cpp
|
Clipper2Lib/src/clipper2_z.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,9 +36,6 @@ target_include_directories(Clipper2
|
|||||||
PUBLIC Clipper2Lib/include
|
PUBLIC Clipper2Lib/include
|
||||||
)
|
)
|
||||||
|
|
||||||
# Engine nodes are allocated through tbbmalloc (see clipper.engine.cpp).
|
|
||||||
target_link_libraries(Clipper2 PRIVATE TBB::tbbmalloc)
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (MSVC AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (MSVC AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Author : Angus Johnson *
|
* Author : Angus Johnson *
|
||||||
* Date : 12 October 2025 *
|
* Date : 12 May 2024 *
|
||||||
* Website : https://www.angusj.com *
|
* Website : https://www.angusj.com *
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
* Copyright : Angus Johnson 2010-2024 *
|
||||||
* Purpose : Core Clipper Library structures and functions *
|
* Purpose : Core Clipper Library structures and functions *
|
||||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@@ -251,20 +251,6 @@ namespace Clipper2Lib {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using Paths = std::vector<Path<T>>;
|
using Paths = std::vector<Path<T>>;
|
||||||
|
|
||||||
template <typename T, typename T2=T>
|
|
||||||
Path<T>& operator<<(Path<T>& poly, const Point<T2>& p)
|
|
||||||
{
|
|
||||||
poly.emplace_back(p);
|
|
||||||
return poly;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Paths<T>& operator<<(Paths<T>& polys, const Path<T>& p)
|
|
||||||
{
|
|
||||||
polys.emplace_back(p);
|
|
||||||
return polys;
|
|
||||||
}
|
|
||||||
|
|
||||||
using Path64 = Path<int64_t>;
|
using Path64 = Path<int64_t>;
|
||||||
using PathD = Path<double>;
|
using PathD = Path<double>;
|
||||||
using Paths64 = std::vector< Path64>;
|
using Paths64 = std::vector< Path64>;
|
||||||
@@ -702,28 +688,29 @@ namespace Clipper2Lib {
|
|||||||
return (x > 0) - (x < 0);
|
return (x > 0) - (x < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UInt128Struct
|
struct MultiplyUInt64Result
|
||||||
{
|
{
|
||||||
const uint64_t lo = 0;
|
const uint64_t result = 0;
|
||||||
const uint64_t hi = 0;
|
const uint64_t carry = 0;
|
||||||
|
|
||||||
bool operator==(const UInt128Struct& other) const
|
bool operator==(const MultiplyUInt64Result& other) const
|
||||||
{
|
{
|
||||||
return lo == other.lo && hi == other.hi;
|
return result == other.result && carry == other.carry;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
inline MultiplyUInt64Result Multiply(uint64_t a, uint64_t b) // #834, #835
|
||||||
|
|
||||||
inline UInt128Struct MultiplyUInt64(uint64_t a, uint64_t b) // #834, #835
|
|
||||||
{
|
{
|
||||||
// note to self - lamba expressions follow
|
|
||||||
const auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
|
const auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
|
||||||
const auto hi = [](uint64_t x) { return x >> 32; };
|
const auto hi = [](uint64_t x) { return x >> 32; };
|
||||||
|
|
||||||
const uint64_t x1 = lo(a) * lo(b);
|
const uint64_t x1 = lo(a) * lo(b);
|
||||||
const uint64_t x2 = hi(a) * lo(b) + hi(x1);
|
const uint64_t x2 = hi(a) * lo(b) + hi(x1);
|
||||||
const uint64_t x3 = lo(a) * hi(b) + lo(x2);
|
const uint64_t x3 = lo(a) * hi(b) + lo(x2);
|
||||||
return { uint64_t(lo(x3) << 32 | lo(x1)), uint64_t(hi(a) * hi(b) + hi(x2) + hi(x3)) };
|
const uint64_t result = lo(x3) << 32 | lo(x1);
|
||||||
|
const uint64_t carry = hi(a) * hi(b) + hi(x2) + hi(x3);
|
||||||
|
|
||||||
|
return { result, carry };
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if (and only if) a * b == c * d
|
// returns true if (and only if) a * b == c * d
|
||||||
@@ -740,50 +727,14 @@ namespace Clipper2Lib {
|
|||||||
const auto abs_c = static_cast<uint64_t>(std::abs(c));
|
const auto abs_c = static_cast<uint64_t>(std::abs(c));
|
||||||
const auto abs_d = static_cast<uint64_t>(std::abs(d));
|
const auto abs_d = static_cast<uint64_t>(std::abs(d));
|
||||||
|
|
||||||
const auto ab = MultiplyUInt64(abs_a, abs_b);
|
const auto abs_ab = Multiply(abs_a, abs_b);
|
||||||
const auto cd = MultiplyUInt64(abs_c, abs_d);
|
const auto abs_cd = Multiply(abs_c, abs_d);
|
||||||
|
|
||||||
// nb: it's important to differentiate 0 values here from other values
|
// nb: it's important to differentiate 0 values here from other values
|
||||||
const auto sign_ab = TriSign(a) * TriSign(b);
|
const auto sign_ab = TriSign(a) * TriSign(b);
|
||||||
const auto sign_cd = TriSign(c) * TriSign(d);
|
const auto sign_cd = TriSign(c) * TriSign(d);
|
||||||
|
|
||||||
return ab == cd && sign_ab == sign_cd;
|
return abs_ab == abs_cd && sign_ab == sign_cd;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline int CrossProductSign(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3)
|
|
||||||
{
|
|
||||||
const auto a = pt2.x - pt1.x;
|
|
||||||
const auto b = pt3.y - pt2.y;
|
|
||||||
const auto c = pt2.y - pt1.y;
|
|
||||||
const auto d = pt3.x - pt2.x;
|
|
||||||
|
|
||||||
#if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
|
|
||||||
const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
|
|
||||||
const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
|
|
||||||
if (ab > cd) return 1;
|
|
||||||
else if (ab < cd) return -1;
|
|
||||||
else return 0;
|
|
||||||
#else
|
|
||||||
const auto ab = MultiplyUInt64(std::abs(a), std::abs(b));
|
|
||||||
const auto cd = MultiplyUInt64(std::abs(c), std::abs(d));
|
|
||||||
|
|
||||||
const auto sign_ab = TriSign(a) * TriSign(b);
|
|
||||||
const auto sign_cd = TriSign(c) * TriSign(d);
|
|
||||||
|
|
||||||
if (sign_ab == sign_cd)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if (ab.hi == cd.hi)
|
|
||||||
{
|
|
||||||
if (ab.lo == cd.lo) return 0;
|
|
||||||
result = (ab.lo > cd.lo) ? 1 : -1;
|
|
||||||
}
|
|
||||||
else result = (ab.hi > cd.hi) ? 1 : -1;
|
|
||||||
return (sign_ab > 0) ? result : -result;
|
|
||||||
}
|
|
||||||
return (sign_ab > sign_cd) ? 1 : -1;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,10 +838,6 @@ namespace Clipper2Lib {
|
|||||||
return Area<T>(poly) >= 0;
|
return Area<T>(poly) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLineIntersectPt - a 'true' result is non-parallel. The 'ip' will also
|
|
||||||
// be constrained to seg1. However, it's possible that 'ip' won't be inside
|
|
||||||
// seg2, even when 'ip' hasn't been constrained (ie 'ip' is inside seg1).
|
|
||||||
|
|
||||||
#if CLIPPER2_HI_PRECISION
|
#if CLIPPER2_HI_PRECISION
|
||||||
// caution: this will compromise performance
|
// caution: this will compromise performance
|
||||||
// https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
|
// https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
|
||||||
@@ -898,7 +845,7 @@ namespace Clipper2Lib {
|
|||||||
#define CC_MIN(x,y) ((x)>(y)?(y):(x))
|
#define CC_MIN(x,y) ((x)>(y)?(y):(x))
|
||||||
#define CC_MAX(x,y) ((x)<(y)?(y):(x))
|
#define CC_MAX(x,y) ((x)<(y)?(y):(x))
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||||
{
|
{
|
||||||
double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
|
double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
|
||||||
@@ -944,14 +891,11 @@ namespace Clipper2Lib {
|
|||||||
ip.x = originx + static_cast<T>(hitx);
|
ip.x = originx + static_cast<T>(hitx);
|
||||||
ip.y = originy + static_cast<T>(hity);
|
ip.y = originy + static_cast<T>(hity);
|
||||||
}
|
}
|
||||||
#ifdef USINGZ
|
|
||||||
ip.z = 0;
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||||
{
|
{
|
||||||
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
||||||
@@ -969,9 +913,6 @@ namespace Clipper2Lib {
|
|||||||
{
|
{
|
||||||
ip.x = static_cast<T>(ln1a.x + t * dx1);
|
ip.x = static_cast<T>(ln1a.x + t * dx1);
|
||||||
ip.y = static_cast<T>(ln1a.y + t * dy1);
|
ip.y = static_cast<T>(ln1a.y + t * dy1);
|
||||||
#ifdef USINGZ
|
|
||||||
ip.z = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1008,44 +949,21 @@ namespace Clipper2Lib {
|
|||||||
inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
|
inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
|
||||||
const Point64& seg2a, const Point64& seg2b, bool inclusive = false)
|
const Point64& seg2a, const Point64& seg2b, bool inclusive = false)
|
||||||
{
|
{
|
||||||
double dy1 = static_cast<double>(seg1b.y - seg1a.y);
|
|
||||||
double dx1 = static_cast<double>(seg1b.x - seg1a.x);
|
|
||||||
double dy2 = static_cast<double>(seg2b.y - seg2a.y);
|
|
||||||
double dx2 = static_cast<double>(seg2b.x - seg2a.x);
|
|
||||||
double cp = dy1 * dx2 - dy2 * dx1;
|
|
||||||
if (cp == 0) return false; // ie parallel segments
|
|
||||||
|
|
||||||
if (inclusive)
|
if (inclusive)
|
||||||
{
|
{
|
||||||
//result **includes** segments that touch at an end point
|
double res1 = CrossProduct(seg1a, seg2a, seg2b);
|
||||||
double t = ((seg1a.x - seg2a.x) * dy2 - (seg1a.y - seg2a.y) * dx2);
|
double res2 = CrossProduct(seg1b, seg2a, seg2b);
|
||||||
if (t == 0) return true;
|
if (res1 * res2 > 0) return false;
|
||||||
if (t > 0)
|
double res3 = CrossProduct(seg2a, seg1a, seg1b);
|
||||||
{
|
double res4 = CrossProduct(seg2b, seg1a, seg1b);
|
||||||
if (cp < 0 || t > cp) return false;
|
if (res3 * res4 > 0) return false;
|
||||||
|
return (res1 || res2 || res3 || res4); // ensures not collinear
|
||||||
}
|
}
|
||||||
else if (cp > 0 || t < cp) return false; // false when t more neg. than cp
|
else {
|
||||||
|
return (GetSign(CrossProduct(seg1a, seg2a, seg2b)) *
|
||||||
t = ((seg1a.x - seg2a.x) * dy1 - (seg1a.y - seg2a.y) * dx1);
|
GetSign(CrossProduct(seg1b, seg2a, seg2b)) < 0) &&
|
||||||
if (t == 0) return true;
|
(GetSign(CrossProduct(seg2a, seg1a, seg1b)) *
|
||||||
if (t > 0) return (cp > 0 && t <= cp);
|
GetSign(CrossProduct(seg2b, seg1a, seg1b)) < 0);
|
||||||
else return (cp < 0 && t >= cp); // true when t less neg. than cp
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//result **excludes** segments that touch at an end point
|
|
||||||
double t = ((seg1a.x - seg2a.x) * dy2 - (seg1a.y - seg2a.y) * dx2);
|
|
||||||
if (t == 0) return false;
|
|
||||||
if (t > 0)
|
|
||||||
{
|
|
||||||
if (cp < 0 || t >= cp) return false;
|
|
||||||
}
|
|
||||||
else if (cp > 0 || t <= cp ) return false; // false when t more neg. than cp
|
|
||||||
|
|
||||||
t = ((seg1a.x - seg2a.x) * dy1 - (seg1a.y - seg2a.y) * dx1);
|
|
||||||
if (t == 0) return false;
|
|
||||||
if (t > 0) return (cp > 0 && t < cp);
|
|
||||||
else return (cp < 0 && t > cp); // true when t less neg. than cp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,7 +1051,7 @@ namespace Clipper2Lib {
|
|||||||
val = 1 - val; // toggle val
|
val = 1 - val; // toggle val
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int d = CrossProductSign(*prev, *curr, pt);
|
double d = CrossProduct(*prev, *curr, pt);
|
||||||
if (d == 0) return PointInPolygonResult::IsOn;
|
if (d == 0) return PointInPolygonResult::IsOn;
|
||||||
if ((d < 0) == is_above) val = 1 - val;
|
if ((d < 0) == is_above) val = 1 - val;
|
||||||
}
|
}
|
||||||
@@ -1147,7 +1065,7 @@ namespace Clipper2Lib {
|
|||||||
if (curr == cend) curr = cbegin;
|
if (curr == cend) curr = cbegin;
|
||||||
if (curr == cbegin) prev = cend - 1;
|
if (curr == cbegin) prev = cend - 1;
|
||||||
else prev = curr - 1;
|
else prev = curr - 1;
|
||||||
int d = CrossProductSign(*prev, *curr, pt);
|
double d = CrossProduct(*prev, *curr, pt);
|
||||||
if (d == 0) return PointInPolygonResult::IsOn;
|
if (d == 0) return PointInPolygonResult::IsOn;
|
||||||
if ((d < 0) == is_above) val = 1 - val;
|
if ((d < 0) == is_above) val = 1 - val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,6 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// Orca: engine nodes are allocated through tbbmalloc, see clipper.engine.cpp.
|
|
||||||
#define CLIPPER2_NODE_ALLOCATOR \
|
|
||||||
static void* operator new(size_t size); \
|
|
||||||
static void operator delete(void* ptr) noexcept; \
|
|
||||||
static void* operator new[](size_t size); \
|
|
||||||
static void operator delete[](void* ptr) noexcept;
|
|
||||||
|
|
||||||
#ifdef USINGZ
|
#ifdef USINGZ
|
||||||
namespace Clipper2Lib_Z {
|
namespace Clipper2Lib_Z {
|
||||||
#else
|
#else
|
||||||
@@ -57,7 +50,6 @@ namespace Clipper2Lib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
Point64 pt;
|
Point64 pt;
|
||||||
Vertex* next = nullptr;
|
Vertex* next = nullptr;
|
||||||
Vertex* prev = nullptr;
|
Vertex* prev = nullptr;
|
||||||
@@ -65,7 +57,6 @@ namespace Clipper2Lib {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct OutPt {
|
struct OutPt {
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
Point64 pt;
|
Point64 pt;
|
||||||
OutPt* next = nullptr;
|
OutPt* next = nullptr;
|
||||||
OutPt* prev = nullptr;
|
OutPt* prev = nullptr;
|
||||||
@@ -90,7 +81,6 @@ namespace Clipper2Lib {
|
|||||||
//OutRec: contains a path in the clipping solution. Edges in the AEL will
|
//OutRec: contains a path in the clipping solution. Edges in the AEL will
|
||||||
//have OutRec pointers assigned when they form part of the clipping solution.
|
//have OutRec pointers assigned when they form part of the clipping solution.
|
||||||
struct OutRec {
|
struct OutRec {
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
OutRec* owner = nullptr;
|
OutRec* owner = nullptr;
|
||||||
Active* front_edge = nullptr;
|
Active* front_edge = nullptr;
|
||||||
@@ -116,7 +106,6 @@ namespace Clipper2Lib {
|
|||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Active {
|
struct Active {
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
Point64 bot;
|
Point64 bot;
|
||||||
Point64 top;
|
Point64 top;
|
||||||
int64_t curr_x = 0; //current (updated at every new scanline)
|
int64_t curr_x = 0; //current (updated at every new scanline)
|
||||||
@@ -144,7 +133,6 @@ namespace Clipper2Lib {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct LocalMinima {
|
struct LocalMinima {
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
Vertex* vertex;
|
Vertex* vertex;
|
||||||
PathType polytype;
|
PathType polytype;
|
||||||
bool is_open;
|
bool is_open;
|
||||||
@@ -315,7 +303,6 @@ namespace Clipper2Lib {
|
|||||||
protected:
|
protected:
|
||||||
PolyPath* parent_;
|
PolyPath* parent_;
|
||||||
public:
|
public:
|
||||||
CLIPPER2_NODE_ALLOCATOR
|
|
||||||
PolyPath(PolyPath* parent = nullptr): parent_(parent){}
|
PolyPath(PolyPath* parent = nullptr): parent_(parent){}
|
||||||
virtual ~PolyPath() {};
|
virtual ~PolyPath() {};
|
||||||
//https://en.cppreference.com/w/cpp/language/rule_of_three
|
//https://en.cppreference.com/w/cpp/language/rule_of_three
|
||||||
@@ -343,7 +330,6 @@ namespace Clipper2Lib {
|
|||||||
//Even levels except level 0
|
//Even levels except level 0
|
||||||
return lvl && !(lvl & 1);
|
return lvl && !(lvl & 1);
|
||||||
}
|
}
|
||||||
// Area() of the namespace this header is compiled into (Clipper2Lib or Clipper2Lib_Z).
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static double Clipper2LibArea(const Path<T> &poly)
|
static double Clipper2LibArea(const Path<T> &poly)
|
||||||
{
|
{
|
||||||
@@ -402,8 +388,7 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
double Area() const
|
double Area() const
|
||||||
{
|
{
|
||||||
return std::accumulate(childs_.cbegin(), childs_.cend(),
|
return std::accumulate(childs_.cbegin(), childs_.cend(), Clipper2LibArea<int64_t>(polygon_),
|
||||||
Clipper2LibArea<int64_t>(polygon_),
|
|
||||||
[](double a, const auto& child) {return a + child->Area(); });
|
[](double a, const auto& child) {return a + child->Area(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,8 +462,7 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
double Area() const
|
double Area() const
|
||||||
{
|
{
|
||||||
return std::accumulate(childs_.begin(), childs_.end(),
|
return std::accumulate(childs_.begin(), childs_.end(), Clipper2LibArea<double>(polygon_),
|
||||||
Clipper2LibArea<double>(polygon_),
|
|
||||||
[](double a, const auto& child) {return a + child->Area(); });
|
[](double a, const auto& child) {return a + child->Area(); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,10 +116,13 @@ the four vertices that define the two segments that are intersecting.
|
|||||||
#include "clipper2/clipper.engine.h"
|
#include "clipper2/clipper.engine.h"
|
||||||
#include "clipper2/clipper.offset.h"
|
#include "clipper2/clipper.offset.h"
|
||||||
#include "clipper2/clipper.rectclip.h"
|
#include "clipper2/clipper.rectclip.h"
|
||||||
#include "clipper2/clipper.triangulation.h"
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#ifdef USINGZ
|
||||||
|
namespace Clipper2Lib_Z {
|
||||||
|
#else
|
||||||
namespace Clipper2Lib {
|
namespace Clipper2Lib {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef int64_t* CPath64;
|
typedef int64_t* CPath64;
|
||||||
typedef int64_t* CPaths64;
|
typedef int64_t* CPaths64;
|
||||||
@@ -813,24 +816,6 @@ EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath6
|
|||||||
return CreateCPathsFromPathsT(solution);
|
return CreateCPathsFromPathsT(solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXTERN_DLL_EXPORT CPaths64 Triangulate64(const CPaths64 paths, bool use_delaunay)
|
|
||||||
{
|
|
||||||
Paths64 pp = ConvertCPathsToPathsT(paths);
|
|
||||||
Paths64 sol;
|
|
||||||
if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
|
|
||||||
return CreateCPathsFromPathsT(sol);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXTERN_DLL_EXPORT CPathsD TriangulateD(const CPathsD paths, int decimal_precison, bool use_delaunay)
|
|
||||||
{
|
|
||||||
if (decimal_precison < -8 || decimal_precison > 8) return nullptr;
|
|
||||||
const double scale = std::pow(10, decimal_precison);
|
|
||||||
Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
|
|
||||||
Paths64 sol;
|
|
||||||
if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
|
|
||||||
return CreateCPathsDFromPaths64(sol, 1 / scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USINGZ
|
#ifdef USINGZ
|
||||||
typedef void (*DLLZCallback64)(const Point64& e1bot, const Point64& e1top, const Point64& e2bot, const Point64& e2top, Point64& pt);
|
typedef void (*DLLZCallback64)(const Point64& e1bot, const Point64& e1top, const Point64& e2bot, const Point64& e2top, Point64& pt);
|
||||||
typedef void (*DLLZCallbackD)(const PointD& e1bot, const PointD& e1top, const PointD& e2bot, const PointD& e2top, PointD& pt);
|
typedef void (*DLLZCallbackD)(const PointD& e1bot, const PointD& e1top, const PointD& e2bot, const PointD& e2top, PointD& pt);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Author : Angus Johnson *
|
* Author : Angus Johnson *
|
||||||
* Date : 5 March 2025 *
|
* Date : 27 April 2024 *
|
||||||
* Website : https://www.angusj.com *
|
* Website : https://www.angusj.com *
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
* Copyright : Angus Johnson 2010-2024 *
|
||||||
* Purpose : This module provides a simple interface to the Clipper Library *
|
* Purpose : This module provides a simple interface to the Clipper Library *
|
||||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@@ -13,15 +13,14 @@
|
|||||||
#include "clipper2/clipper.core.h"
|
#include "clipper2/clipper.core.h"
|
||||||
#include "clipper2/clipper.engine.h"
|
#include "clipper2/clipper.engine.h"
|
||||||
#include "clipper2/clipper.offset.h"
|
#include "clipper2/clipper.offset.h"
|
||||||
#include "clipper2/clipper.rectclip.h"
|
|
||||||
#include "clipper2/clipper.minkowski.h"
|
#include "clipper2/clipper.minkowski.h"
|
||||||
#include "clipper2/clipper.triangulation.h"
|
#include "clipper2/clipper.rectclip.h"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#ifdef USINGZ
|
#ifdef USINGZ
|
||||||
namespace Clipper2Lib_Z {
|
namespace Clipper2Lib_Z {
|
||||||
#else
|
#else
|
||||||
namespace Clipper2Lib {
|
namespace Clipper2Lib {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline Paths64 BooleanOp(ClipType cliptype, FillRule fillrule,
|
inline Paths64 BooleanOp(ClipType cliptype, FillRule fillrule,
|
||||||
@@ -155,7 +154,7 @@ namespace Clipper2Lib {
|
|||||||
if (!delta) return paths;
|
if (!delta) return paths;
|
||||||
if (error_code) return PathsD();
|
if (error_code) return PathsD();
|
||||||
const double scale = std::pow(10, precision);
|
const double scale = std::pow(10, precision);
|
||||||
ClipperOffset clip_offset(miter_limit, arc_tolerance * scale);
|
ClipperOffset clip_offset(miter_limit, arc_tolerance);
|
||||||
clip_offset.AddPaths(ScalePaths<int64_t,double>(paths, scale, error_code), jt, et);
|
clip_offset.AddPaths(ScalePaths<int64_t,double>(paths, scale, error_code), jt, et);
|
||||||
if (error_code) return PathsD();
|
if (error_code) return PathsD();
|
||||||
Paths64 solution;
|
Paths64 solution;
|
||||||
@@ -356,29 +355,6 @@ namespace Clipper2Lib {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t GetNext(size_t current, size_t high,
|
|
||||||
const std::vector<bool>& flags)
|
|
||||||
{
|
|
||||||
++current;
|
|
||||||
while (current <= high && flags[current]) ++current;
|
|
||||||
if (current <= high) return current;
|
|
||||||
current = 0;
|
|
||||||
while (flags[current]) ++current;
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t GetPrior(size_t current, size_t high,
|
|
||||||
const std::vector<bool>& flags)
|
|
||||||
{
|
|
||||||
if (current == 0) current = high;
|
|
||||||
else --current;
|
|
||||||
while (current > 0 && flags[current]) --current;
|
|
||||||
if (!flags[current]) return current;
|
|
||||||
current = high;
|
|
||||||
while (flags[current]) --current;
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end details namespace
|
} // end details namespace
|
||||||
|
|
||||||
inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
|
inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
|
||||||
@@ -639,6 +615,29 @@ namespace Clipper2Lib {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline size_t GetNext(size_t current, size_t high,
|
||||||
|
const std::vector<bool>& flags)
|
||||||
|
{
|
||||||
|
++current;
|
||||||
|
while (current <= high && flags[current]) ++current;
|
||||||
|
if (current <= high) return current;
|
||||||
|
current = 0;
|
||||||
|
while (flags[current]) ++current;
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t GetPrior(size_t current, size_t high,
|
||||||
|
const std::vector<bool>& flags)
|
||||||
|
{
|
||||||
|
if (current == 0) current = high;
|
||||||
|
else --current;
|
||||||
|
while (current > 0 && flags[current]) --current;
|
||||||
|
if (!flags[current]) return current;
|
||||||
|
current = high;
|
||||||
|
while (flags[current]) --current;
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline Path<T> SimplifyPath(const Path<T> &path,
|
inline Path<T> SimplifyPath(const Path<T> &path,
|
||||||
double epsilon, bool isClosedPath = true)
|
double epsilon, bool isClosedPath = true)
|
||||||
@@ -670,13 +669,13 @@ namespace Clipper2Lib {
|
|||||||
start = curr;
|
start = curr;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
curr = details::GetNext(curr, high, flags);
|
curr = GetNext(curr, high, flags);
|
||||||
} while (curr != start && distSqr[curr] > epsSqr);
|
} while (curr != start && distSqr[curr] > epsSqr);
|
||||||
if (curr == start) break;
|
if (curr == start) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
prior = details::GetPrior(curr, high, flags);
|
prior = GetPrior(curr, high, flags);
|
||||||
next = details::GetNext(curr, high, flags);
|
next = GetNext(curr, high, flags);
|
||||||
if (next == prior) break;
|
if (next == prior) break;
|
||||||
|
|
||||||
// flag for removal the smaller of adjacent 'distances'
|
// flag for removal the smaller of adjacent 'distances'
|
||||||
@@ -685,14 +684,14 @@ namespace Clipper2Lib {
|
|||||||
prior2 = prior;
|
prior2 = prior;
|
||||||
prior = curr;
|
prior = curr;
|
||||||
curr = next;
|
curr = next;
|
||||||
next = details::GetNext(next, high, flags);
|
next = GetNext(next, high, flags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
prior2 = details::GetPrior(prior, high, flags);
|
prior2 = GetPrior(prior, high, flags);
|
||||||
|
|
||||||
flags[curr] = true;
|
flags[curr] = true;
|
||||||
curr = next;
|
curr = next;
|
||||||
next = details::GetNext(next, high, flags);
|
next = GetNext(next, high, flags);
|
||||||
|
|
||||||
if (isClosedPath || ((curr != high) && (curr != 0)))
|
if (isClosedPath || ((curr != high) && (curr != 0)))
|
||||||
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
|
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
|
||||||
@@ -717,35 +716,6 @@ namespace Clipper2Lib {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline bool Path2ContainsPath1(const Path<T>& path1, const Path<T>& path2)
|
|
||||||
{
|
|
||||||
// precondition: paths must not intersect, except for
|
|
||||||
// transient (and presumed 'micro') path intersections
|
|
||||||
PointInPolygonResult pip = PointInPolygonResult::IsOn;
|
|
||||||
for (const Point<T>& pt : path1)
|
|
||||||
{
|
|
||||||
switch (PointInPolygon(pt, path2))
|
|
||||||
{
|
|
||||||
case PointInPolygonResult::IsOutside:
|
|
||||||
if (pip == PointInPolygonResult::IsOutside) return false;
|
|
||||||
pip = PointInPolygonResult::IsOutside;
|
|
||||||
break;
|
|
||||||
case PointInPolygonResult::IsInside:
|
|
||||||
if (pip == PointInPolygonResult::IsInside) return true;
|
|
||||||
pip = PointInPolygonResult::IsInside;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pip != PointInPolygonResult::IsInside) return false;
|
|
||||||
// result is likely true but check midpoint
|
|
||||||
Point<T> mp1 = GetBounds(path1).MidPoint();
|
|
||||||
return PointInPolygon(mp1, path2) == PointInPolygonResult::IsInside;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void RDP(const Path<T> path, std::size_t begin,
|
inline void RDP(const Path<T> path, std::size_t begin,
|
||||||
std::size_t end, double epsSqrd, std::vector<bool>& flags)
|
std::size_t end, double epsSqrd, std::vector<bool>& flags)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Author : Angus Johnson *
|
|
||||||
* Date : 6 December 2025 *
|
|
||||||
* Release : BETA RELEASE *
|
|
||||||
* Website : https://www.angusj.com *
|
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
|
||||||
* Purpose : Delaunay Triangulation *
|
|
||||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef CLIPPER_TRIANGULATION_H
|
|
||||||
#define CLIPPER_TRIANGULATION_H
|
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
#include "clipper2/clipper.core.h"
|
|
||||||
|
|
||||||
#ifdef USINGZ
|
|
||||||
namespace Clipper2Lib_Z {
|
|
||||||
#else
|
|
||||||
namespace Clipper2Lib {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum class TriangulateResult { success, fail, no_polygons, paths_intersect };
|
|
||||||
|
|
||||||
// Triangulate - this function will not accept intesecting paths
|
|
||||||
TriangulateResult Triangulate(const Paths64& pp, Paths64& solution, bool useDelaunay = true);
|
|
||||||
TriangulateResult Triangulate(const PathsD& pp, int decPlaces, PathsD& solution, bool useDelaunay = true);
|
|
||||||
|
|
||||||
} // Clipper2Lib namespace
|
|
||||||
#endif // CLIPPER_TRIANGULATION_H
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef CLIPPER_VERSION_H
|
#ifndef CLIPPER_VERSION_H
|
||||||
#define CLIPPER_VERSION_H
|
#define CLIPPER_VERSION_H
|
||||||
|
|
||||||
constexpr auto CLIPPER2_VERSION = "2.0.1";
|
constexpr auto CLIPPER2_VERSION = "1.5.2";
|
||||||
|
|
||||||
#endif // CLIPPER_VERSION_H
|
#endif // CLIPPER_VERSION_H
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Author : Angus Johnson *
|
* Author : Angus Johnson *
|
||||||
* Date : 5 November 2025 *
|
* Date : 17 September 2024 *
|
||||||
* Website : https://www.angusj.com *
|
* Website : https://www.angusj.com *
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
* Copyright : Angus Johnson 2010-2024 *
|
||||||
* Purpose : This is the main polygon clipping module *
|
* Purpose : This is the main polygon clipping module *
|
||||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@@ -10,8 +10,6 @@
|
|||||||
#include "clipper2/clipper.engine.h"
|
#include "clipper2/clipper.engine.h"
|
||||||
#include "clipper2/clipper.h"
|
#include "clipper2/clipper.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <new>
|
|
||||||
#include <oneapi/tbb/scalable_allocator.h>
|
|
||||||
|
|
||||||
// https://github.com/AngusJohnson/Clipper2/discussions/334
|
// https://github.com/AngusJohnson/Clipper2/discussions/334
|
||||||
// #discussioncomment-4248602
|
// #discussioncomment-4248602
|
||||||
@@ -29,26 +27,6 @@ namespace Clipper2Lib_Z {
|
|||||||
namespace Clipper2Lib {
|
namespace Clipper2Lib {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Orca: tbbmalloc scales far better than the default heap when all slicing threads clip at once.
|
|
||||||
static void* NodeAlloc(size_t size)
|
|
||||||
{
|
|
||||||
if (void* p = scalable_malloc(size)) return p;
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CLIPPER2_DEFINE_NODE_ALLOCATOR(T) \
|
|
||||||
void* T::operator new(size_t size) { return NodeAlloc(size); } \
|
|
||||||
void T::operator delete(void* ptr) noexcept { scalable_free(ptr); } \
|
|
||||||
void* T::operator new[](size_t size) { return NodeAlloc(size); } \
|
|
||||||
void T::operator delete[](void* ptr) noexcept { scalable_free(ptr); }
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(Vertex)
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(OutPt)
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(OutRec)
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(Active)
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(LocalMinima)
|
|
||||||
CLIPPER2_DEFINE_NODE_ALLOCATOR(PolyPath)
|
|
||||||
#undef CLIPPER2_DEFINE_NODE_ALLOCATOR
|
|
||||||
|
|
||||||
static const Rect64 invalid_rect = Rect64(false);
|
static const Rect64 invalid_rect = Rect64(false);
|
||||||
|
|
||||||
// Every closed path (ie polygon) is made up of a series of vertices forming edge
|
// Every closed path (ie polygon) is made up of a series of vertices forming edge
|
||||||
@@ -504,7 +482,8 @@ namespace Clipper2Lib {
|
|||||||
inline void SetOwner(OutRec* outrec, OutRec* new_owner)
|
inline void SetOwner(OutRec* outrec, OutRec* new_owner)
|
||||||
{
|
{
|
||||||
//precondition1: new_owner is never null
|
//precondition1: new_owner is never null
|
||||||
new_owner->owner = GetRealOutRec(new_owner->owner);
|
while (new_owner->owner && !new_owner->owner->pts)
|
||||||
|
new_owner->owner = new_owner->owner->owner;
|
||||||
OutRec* tmp = new_owner;
|
OutRec* tmp = new_owner;
|
||||||
while (tmp && tmp != outrec) tmp = tmp->owner;
|
while (tmp && tmp != outrec) tmp = tmp->owner;
|
||||||
if (tmp) new_owner->owner = outrec->owner;
|
if (tmp) new_owner->owner = outrec->owner;
|
||||||
@@ -557,9 +536,9 @@ namespace Clipper2Lib {
|
|||||||
val = 1 - val; // toggle val
|
val = 1 - val; // toggle val
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||||
if (i == 0) return PointInPolygonResult::IsOn;
|
if (d == 0) return PointInPolygonResult::IsOn;
|
||||||
if ((i < 0) == is_above) val = 1 - val;
|
if ((d < 0) == is_above) val = 1 - val;
|
||||||
}
|
}
|
||||||
is_above = !is_above;
|
is_above = !is_above;
|
||||||
op2 = op2->next;
|
op2 = op2->next;
|
||||||
@@ -567,9 +546,9 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
if (is_above != starting_above)
|
if (is_above != starting_above)
|
||||||
{
|
{
|
||||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||||
if (i == 0) return PointInPolygonResult::IsOn;
|
if (d == 0) return PointInPolygonResult::IsOn;
|
||||||
if ((i < 0) == is_above) val = 1 - val;
|
if ((d < 0) == is_above) val = 1 - val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val == 0) return PointInPolygonResult::IsOutside;
|
if (val == 0) return PointInPolygonResult::IsOutside;
|
||||||
@@ -599,31 +578,30 @@ namespace Clipper2Lib {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Path2ContainsPath1(OutPt* op1, OutPt* op2)
|
inline bool Path1InsidePath2(OutPt* op1, OutPt* op2)
|
||||||
{
|
{
|
||||||
// this function accommodates rounding errors that
|
// we need to make some accommodation for rounding errors
|
||||||
// can cause path micro intersections
|
// so we won't jump if the first vertex is found outside
|
||||||
PointInPolygonResult pip = PointInPolygonResult::IsOn;
|
PointInPolygonResult result;
|
||||||
|
int outside_cnt = 0;
|
||||||
OutPt* op = op1;
|
OutPt* op = op1;
|
||||||
do {
|
do
|
||||||
switch (PointInOpPolygon(op->pt, op2))
|
|
||||||
{
|
{
|
||||||
case PointInPolygonResult::IsOutside:
|
result = PointInOpPolygon(op->pt, op2);
|
||||||
if (pip == PointInPolygonResult::IsOutside) return false;
|
if (result == PointInPolygonResult::IsOutside) ++outside_cnt;
|
||||||
pip = PointInPolygonResult::IsOutside;
|
else if (result == PointInPolygonResult::IsInside) --outside_cnt;
|
||||||
break;
|
|
||||||
case PointInPolygonResult::IsInside:
|
|
||||||
if (pip == PointInPolygonResult::IsInside) return true;
|
|
||||||
pip = PointInPolygonResult::IsInside;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
op = op->next;
|
op = op->next;
|
||||||
} while (op != op1);
|
} while (op != op1 && std::abs(outside_cnt) < 2);
|
||||||
// result unclear, so try again using cleaned paths
|
if (std::abs(outside_cnt) > 1) return (outside_cnt < 0);
|
||||||
return Path2ContainsPath1(GetCleanPath(op1), GetCleanPath(op2)); // (#973)
|
// since path1's location is still equivocal, check its midpoint
|
||||||
|
Point64 mp = GetBounds(GetCleanPath(op1)).MidPoint();
|
||||||
|
Path64 path2 = GetCleanPath(op2);
|
||||||
|
return PointInPolygon(mp, path2) != PointInPolygonResult::IsOutside;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
void AddLocMin(LocalMinimaList& list,
|
void AddLocMin(LocalMinimaList& list,
|
||||||
Vertex& vert, PathType polytype, bool is_open)
|
Vertex& vert, PathType polytype, bool is_open)
|
||||||
{
|
{
|
||||||
@@ -1148,19 +1126,21 @@ namespace Clipper2Lib {
|
|||||||
return newcomer.curr_x > resident.curr_x;
|
return newcomer.curr_x > resident.curr_x;
|
||||||
|
|
||||||
//get the turning direction a1.top, a2.bot, a2.top
|
//get the turning direction a1.top, a2.bot, a2.top
|
||||||
int i = CrossProductSign(resident.top, newcomer.bot, newcomer.top);
|
double d = CrossProduct(resident.top, newcomer.bot, newcomer.top);
|
||||||
if (i != 0) return i < 0;
|
if (d != 0) return d < 0;
|
||||||
|
|
||||||
//edges must be collinear to get here
|
//edges must be collinear to get here
|
||||||
//for starting open paths, place them according to
|
//for starting open paths, place them according to
|
||||||
//the direction they're about to turn
|
//the direction they're about to turn
|
||||||
if (!IsMaxima(resident) && (resident.top.y > newcomer.top.y))
|
if (!IsMaxima(resident) && (resident.top.y > newcomer.top.y))
|
||||||
{
|
{
|
||||||
return (CrossProductSign(newcomer.bot, resident.top, NextVertex(resident)->pt) <= 0);
|
return CrossProduct(newcomer.bot,
|
||||||
|
resident.top, NextVertex(resident)->pt) <= 0;
|
||||||
}
|
}
|
||||||
else if (!IsMaxima(newcomer) && (newcomer.top.y > resident.top.y))
|
else if (!IsMaxima(newcomer) && (newcomer.top.y > resident.top.y))
|
||||||
{
|
{
|
||||||
return (CrossProductSign(newcomer.bot, newcomer.top, NextVertex(newcomer)->pt) >= 0);
|
return CrossProduct(newcomer.bot,
|
||||||
|
newcomer.top, NextVertex(newcomer)->pt) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t y = newcomer.bot.y;
|
int64_t y = newcomer.bot.y;
|
||||||
@@ -1175,7 +1155,7 @@ namespace Clipper2Lib {
|
|||||||
resident.bot, resident.top)) return true;
|
resident.bot, resident.top)) return true;
|
||||||
else
|
else
|
||||||
//compare turning direction of the alternate bound
|
//compare turning direction of the alternate bound
|
||||||
return (CrossProductSign(PrevPrevVertex(resident)->pt,
|
return (CrossProduct(PrevPrevVertex(resident)->pt,
|
||||||
newcomer.bot, PrevPrevVertex(newcomer)->pt) > 0) == newcomerIsLeft;
|
newcomer.bot, PrevPrevVertex(newcomer)->pt) > 0) == newcomerIsLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1585,7 +1565,7 @@ namespace Clipper2Lib {
|
|||||||
FixSelfIntersects(outrec);
|
FixSelfIntersects(outrec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClipperBase::DoSplitOp (OutRec* outrec, OutPt* splitOp)
|
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
|
||||||
{
|
{
|
||||||
// splitOp.prev -> splitOp &&
|
// splitOp.prev -> splitOp &&
|
||||||
// splitOp.next -> splitOp.next.next are intersecting
|
// splitOp.next -> splitOp.next.next are intersecting
|
||||||
@@ -1594,7 +1574,7 @@ namespace Clipper2Lib {
|
|||||||
outrec->pts = prevOp;
|
outrec->pts = prevOp;
|
||||||
|
|
||||||
Point64 ip;
|
Point64 ip;
|
||||||
GetLineIntersectPt(prevOp->pt, splitOp->pt,
|
GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
|
||||||
splitOp->next->pt, nextNextOp->pt, ip);
|
splitOp->next->pt, nextNextOp->pt, ip);
|
||||||
|
|
||||||
#ifdef USINGZ
|
#ifdef USINGZ
|
||||||
@@ -1650,7 +1630,7 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
if (using_polytree_)
|
if (using_polytree_)
|
||||||
{
|
{
|
||||||
if (Path2ContainsPath1(prevOp, newOp))
|
if (Path1InsidePath2(prevOp, newOp))
|
||||||
{
|
{
|
||||||
newOr->splits = new OutRecList();
|
newOr->splits = new OutRecList();
|
||||||
newOr->splits->emplace_back(outrec);
|
newOr->splits->emplace_back(outrec);
|
||||||
@@ -1672,33 +1652,20 @@ namespace Clipper2Lib {
|
|||||||
void ClipperBase::FixSelfIntersects(OutRec* outrec)
|
void ClipperBase::FixSelfIntersects(OutRec* outrec)
|
||||||
{
|
{
|
||||||
OutPt* op2 = outrec->pts;
|
OutPt* op2 = outrec->pts;
|
||||||
if (op2->prev == op2->next->next)
|
|
||||||
return; // because triangles can't self-intersect
|
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
|
// triangles can't self-intersect
|
||||||
|
if (op2->prev == op2->next->next) break;
|
||||||
if (SegmentsIntersect(op2->prev->pt,
|
if (SegmentsIntersect(op2->prev->pt,
|
||||||
op2->pt, op2->next->pt, op2->next->next->pt))
|
op2->pt, op2->next->pt, op2->next->next->pt))
|
||||||
{
|
|
||||||
if (SegmentsIntersect(op2->prev->pt,
|
|
||||||
op2->pt, op2->next->next->pt, op2->next->next->next->pt))
|
|
||||||
{
|
|
||||||
// adjacent intersections (ie a micro self-intersections)
|
|
||||||
op2 = DuplicateOp(op2, false);
|
|
||||||
op2->pt = op2->next->next->next->pt;
|
|
||||||
op2 = op2->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (op2 == outrec->pts || op2->next == outrec->pts)
|
if (op2 == outrec->pts || op2->next == outrec->pts)
|
||||||
outrec->pts = outrec->pts->prev;
|
outrec->pts = outrec->pts->prev;
|
||||||
DoSplitOp(outrec, op2);
|
DoSplitOp(outrec, op2);
|
||||||
if (!outrec->pts) break;
|
if (!outrec->pts) break;
|
||||||
op2 = outrec->pts;
|
op2 = outrec->pts;
|
||||||
if (op2->prev == op2->next->next)
|
|
||||||
break; // again, because triangles can't self-intersect
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
op2 = op2->next;
|
op2 = op2->next;
|
||||||
|
|
||||||
@@ -2145,8 +2112,9 @@ namespace Clipper2Lib {
|
|||||||
e->prev_in_sel = e->prev_in_ael;
|
e->prev_in_sel = e->prev_in_ael;
|
||||||
e->next_in_sel = e->next_in_ael;
|
e->next_in_sel = e->next_in_ael;
|
||||||
e->jump = e->next_in_sel;
|
e->jump = e->next_in_sel;
|
||||||
// it is safe to ignore 'joined' edges here because
|
if (e->join_with == JoinWith::Left)
|
||||||
// if necessary they will be split in IntersectEdges()
|
e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
|
||||||
|
else
|
||||||
e->curr_x = TopX(*e, top_y);
|
e->curr_x = TopX(*e, top_y);
|
||||||
e = e->next_in_ael;
|
e = e->next_in_ael;
|
||||||
}
|
}
|
||||||
@@ -2294,14 +2262,15 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
||||||
{
|
{
|
||||||
|
if (!fromOr->splits) return;
|
||||||
if (!toOr->splits) toOr->splits = new OutRecList();
|
if (!toOr->splits) toOr->splits = new OutRecList();
|
||||||
OutRecList::iterator orIter = fromOr->splits->begin();
|
OutRecList::iterator orIter = fromOr->splits->begin();
|
||||||
for (; orIter != fromOr->splits->end(); ++orIter)
|
for (; orIter != fromOr->splits->end(); ++orIter)
|
||||||
if (toOr != *orIter) // #987
|
|
||||||
toOr->splits->emplace_back(*orIter);
|
toOr->splits->emplace_back(*orIter);
|
||||||
fromOr->splits->clear();
|
fromOr->splits->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClipperBase::ProcessHorzJoins()
|
void ClipperBase::ProcessHorzJoins()
|
||||||
{
|
{
|
||||||
for (const HorzJoin& j : horz_join_list_)
|
for (const HorzJoin& j : horz_join_list_)
|
||||||
@@ -2331,7 +2300,7 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
if (using_polytree_) //#498, #520, #584, D#576, #618
|
if (using_polytree_) //#498, #520, #584, D#576, #618
|
||||||
{
|
{
|
||||||
if (Path2ContainsPath1(or1->pts, or2->pts))
|
if (Path1InsidePath2(or1->pts, or2->pts))
|
||||||
{
|
{
|
||||||
//swap or1's & or2's pts
|
//swap or1's & or2's pts
|
||||||
OutPt* tmp = or1->pts;
|
OutPt* tmp = or1->pts;
|
||||||
@@ -2342,7 +2311,7 @@ namespace Clipper2Lib {
|
|||||||
//or2 is now inside or1
|
//or2 is now inside or1
|
||||||
or2->owner = or1;
|
or2->owner = or1;
|
||||||
}
|
}
|
||||||
else if (Path2ContainsPath1(or2->pts, or1->pts))
|
else if (Path1InsidePath2(or2->pts, or1->pts))
|
||||||
{
|
{
|
||||||
or2->owner = or1;
|
or2->owner = or1;
|
||||||
}
|
}
|
||||||
@@ -2355,13 +2324,12 @@ namespace Clipper2Lib {
|
|||||||
else
|
else
|
||||||
or2->owner = or1;
|
or2->owner = or1;
|
||||||
}
|
}
|
||||||
else // joining, not splitting
|
else
|
||||||
{
|
{
|
||||||
or2->pts = nullptr;
|
or2->pts = nullptr;
|
||||||
if (using_polytree_)
|
if (using_polytree_)
|
||||||
{
|
{
|
||||||
SetOwner(or2, or1);
|
SetOwner(or2, or1);
|
||||||
if (or2->splits)
|
|
||||||
MoveSplits(or2, or1); //#618
|
MoveSplits(or2, or1); //#618
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2382,7 +2350,7 @@ namespace Clipper2Lib {
|
|||||||
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
||||||
{
|
{
|
||||||
Point64 ip;
|
Point64 ip;
|
||||||
if (!GetLineIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
if (!GetSegmentIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
||||||
ip = Point64(e1.curr_x, top_y); //parallel edges
|
ip = Point64(e1.curr_x, top_y); //parallel edges
|
||||||
|
|
||||||
//rounding errors can occasionally place the calculated intersection
|
//rounding errors can occasionally place the calculated intersection
|
||||||
@@ -2966,28 +2934,22 @@ namespace Clipper2Lib {
|
|||||||
|
|
||||||
bool ClipperBase::CheckSplitOwner(OutRec* outrec, OutRecList* splits)
|
bool ClipperBase::CheckSplitOwner(OutRec* outrec, OutRecList* splits)
|
||||||
{
|
{
|
||||||
// nb: use indexing (not an iterator) in case 'splits' is modified inside this loop (#1029)
|
for (auto split : *splits)
|
||||||
for (size_t idx = 0; idx < splits->size(); ++idx)
|
|
||||||
{
|
{
|
||||||
OutRec* split = (*splits)[idx];
|
|
||||||
if (!split->pts && split->splits &&
|
|
||||||
CheckSplitOwner(outrec, split->splits)) return true; //#942
|
|
||||||
split = GetRealOutRec(split);
|
split = GetRealOutRec(split);
|
||||||
if (!split || split == outrec || split->recursive_split == outrec) continue;
|
if(!split || split == outrec || split->recursive_split == outrec) continue;
|
||||||
split->recursive_split = outrec; // prevent infinite loops
|
split->recursive_split = outrec; // prevent infinite loops
|
||||||
|
|
||||||
if (split->splits && CheckSplitOwner(outrec, split->splits))
|
if (split->splits && CheckSplitOwner(outrec, split->splits))
|
||||||
return true;
|
return true;
|
||||||
|
else if (CheckBounds(split) &&
|
||||||
if (!CheckBounds(split) || !split->bounds.Contains(outrec->bounds) ||
|
IsValidOwner(outrec, split) &&
|
||||||
!Path2ContainsPath1(outrec->pts, split->pts)) continue;
|
split->bounds.Contains(outrec->bounds) &&
|
||||||
|
Path1InsidePath2(outrec->pts, split->pts))
|
||||||
if (!IsValidOwner(outrec, split)) // split is owned by outrec! (#957)
|
{
|
||||||
split->owner = outrec->owner;
|
outrec->owner = split; //found in split
|
||||||
|
|
||||||
outrec->owner = split;
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2998,12 +2960,13 @@ namespace Clipper2Lib {
|
|||||||
// post-condition: if a valid path, outrec will have a polypath
|
// post-condition: if a valid path, outrec will have a polypath
|
||||||
|
|
||||||
if (outrec->polypath || outrec->bounds.IsEmpty()) return;
|
if (outrec->polypath || outrec->bounds.IsEmpty()) return;
|
||||||
|
|
||||||
while (outrec->owner)
|
while (outrec->owner)
|
||||||
{
|
{
|
||||||
if (outrec->owner->splits && CheckSplitOwner(outrec, outrec->owner->splits)) break;
|
if (outrec->owner->splits && CheckSplitOwner(outrec, outrec->owner->splits)) break;
|
||||||
if (outrec->owner->pts && CheckBounds(outrec->owner) &&
|
if (outrec->owner->pts && CheckBounds(outrec->owner) &&
|
||||||
outrec->owner->bounds.Contains(outrec->bounds) &&
|
outrec->owner->bounds.Contains(outrec->bounds) &&
|
||||||
Path2ContainsPath1(outrec->pts, outrec->owner->pts)) break;
|
Path1InsidePath2(outrec->pts, outrec->owner->pts)) break;
|
||||||
outrec->owner = outrec->owner->owner;
|
outrec->owner = outrec->owner->owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3066,7 +3029,6 @@ namespace Clipper2Lib {
|
|||||||
{
|
{
|
||||||
OutRec* outrec = outrec_list_[i];
|
OutRec* outrec = outrec_list_[i];
|
||||||
if (!outrec || !outrec->pts) continue;
|
if (!outrec || !outrec->pts) continue;
|
||||||
|
|
||||||
if (outrec->is_open)
|
if (outrec->is_open)
|
||||||
{
|
{
|
||||||
Path64 path;
|
Path64 path;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Author : Angus Johnson *
|
* Author : Angus Johnson *
|
||||||
* Date : 11 October 2025 *
|
* Date : 22 January 2025 *
|
||||||
* Website : https://www.angusj.com *
|
* Website : https://www.angusj.com *
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
* Copyright : Angus Johnson 2010-2025 *
|
||||||
* Purpose : Path Offset (Inflate/Shrink) *
|
* Purpose : Path Offset (Inflate/Shrink) *
|
||||||
@@ -37,28 +37,22 @@ const double arc_const = 0.002; // <-- 1/500
|
|||||||
// Miscellaneous methods
|
// Miscellaneous methods
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
void GetLowestClosedPathInfo(const Paths64& paths, std::optional<size_t>& idx, bool& is_neg_area)
|
std::optional<size_t> GetLowestClosedPathIdx(const Paths64& paths)
|
||||||
{
|
{
|
||||||
idx.reset();
|
std::optional<size_t> result;
|
||||||
Point64 botPt = Point64(INT64_MAX, INT64_MIN);
|
Point64 botPt = Point64(INT64_MAX, INT64_MIN);
|
||||||
for (size_t i = 0; i < paths.size(); ++i)
|
for (size_t i = 0; i < paths.size(); ++i)
|
||||||
{
|
{
|
||||||
double a = MAX_DBL;
|
|
||||||
for (const Point64& pt : paths[i])
|
for (const Point64& pt : paths[i])
|
||||||
{
|
{
|
||||||
if ((pt.y < botPt.y) ||
|
if ((pt.y < botPt.y) ||
|
||||||
((pt.y == botPt.y) && (pt.x >= botPt.x))) continue;
|
((pt.y == botPt.y) && (pt.x >= botPt.x))) continue;
|
||||||
if (a == MAX_DBL)
|
result = i;
|
||||||
{
|
|
||||||
a = Area(paths[i]);
|
|
||||||
if (a == 0) break; // invalid closed path, so break from inner loop
|
|
||||||
is_neg_area = a < 0;
|
|
||||||
}
|
|
||||||
idx = i;
|
|
||||||
botPt.x = pt.x;
|
botPt.x = pt.x;
|
||||||
botPt.y = pt.y;
|
botPt.y = pt.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double Hypot(double x, double y)
|
inline double Hypot(double x, double y)
|
||||||
@@ -151,16 +145,15 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
|
|||||||
|
|
||||||
if (end_type == EndType::Polygon)
|
if (end_type == EndType::Polygon)
|
||||||
{
|
{
|
||||||
bool is_neg_area;
|
lowest_path_idx = GetLowestClosedPathIdx(paths_in);
|
||||||
GetLowestClosedPathInfo(paths_in, lowest_path_idx, is_neg_area);
|
|
||||||
// the lowermost path must be an outer path, so if its orientation is negative,
|
// the lowermost path must be an outer path, so if its orientation is negative,
|
||||||
// then flag the whole group is 'reversed' (will negate delta etc.)
|
// then flag the whole group is 'reversed' (will negate delta etc.)
|
||||||
// as this is much more efficient than reversing every path.
|
// as this is much more efficient than reversing every path.
|
||||||
is_reversed = lowest_path_idx.has_value() && is_neg_area;
|
is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lowest_path_idx.reset();
|
lowest_path_idx = std::nullopt;
|
||||||
is_reversed = false;
|
is_reversed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +236,7 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
|
|||||||
{
|
{
|
||||||
PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_);
|
PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_);
|
||||||
PointD pt = ptQ;
|
PointD pt = ptQ;
|
||||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||||
//get the second intersect point through reflecion
|
//get the second intersect point through reflecion
|
||||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||||
path_out.emplace_back(pt);
|
path_out.emplace_back(pt);
|
||||||
@@ -252,7 +245,7 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
|
|||||||
{
|
{
|
||||||
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
|
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
|
||||||
PointD pt = ptQ;
|
PointD pt = ptQ;
|
||||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||||
path_out.emplace_back(pt);
|
path_out.emplace_back(pt);
|
||||||
//get the second intersect point through reflecion
|
//get the second intersect point through reflecion
|
||||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||||
@@ -298,8 +291,7 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle
|
|||||||
#else
|
#else
|
||||||
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y);
|
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y);
|
||||||
#endif
|
#endif
|
||||||
// Orca: round the step count like Clipper1 did, so round offsets keep their vertices.
|
int steps = static_cast<int>(std::ceil(steps_per_rad_ * std::abs(angle))); // #448, #456
|
||||||
int steps = std::max(static_cast<int>(std::round(steps_per_rad_ * std::abs(angle))), 1);
|
|
||||||
for (int i = 1; i < steps; ++i) // ie 1 less than steps
|
for (int i = 1; i < steps; ++i) // ie 1 less than steps
|
||||||
{
|
{
|
||||||
offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y,
|
offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y,
|
||||||
@@ -374,30 +366,10 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
|
|||||||
DoSquare(path, j, k);
|
DoSquare(path, j, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orca: join concave corners at the crossing of both edge offsets where safe, 3-point loops make dense inward offsets slow.
|
|
||||||
static bool OffsetConcaveCrossing(const Path64& path, const PathD& norms, size_t j, size_t k, size_t next,
|
|
||||||
double delta, Path64& path_out)
|
|
||||||
{
|
|
||||||
const double sin_a = CrossProduct(norms[j], norms[k]);
|
|
||||||
const double cos_a = DotProduct(norms[j], norms[k]);
|
|
||||||
if (cos_a <= -0.999 || sin_a * delta >= 0) return false;
|
|
||||||
const double x = std::fabs(delta * sin_a) / (1 + cos_a);
|
|
||||||
if (4 * x * x > DistanceSqr(path[k], path[j]) || 4 * x * x > DistanceSqr(path[j], path[next])) return false;
|
|
||||||
const double q = delta / (1 + cos_a);
|
|
||||||
#ifdef USINGZ
|
|
||||||
path_out.emplace_back(path[j].x + (norms[k].x + norms[j].x) * q, path[j].y + (norms[k].y + norms[j].y) * q, path[j].z);
|
|
||||||
#else
|
|
||||||
path_out.emplace_back(path[j].x + (norms[k].x + norms[j].x) * q, path[j].y + (norms[k].y + norms[j].y) * q);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipperOffset::OffsetPolygon(Group& group, const Path64& path)
|
void ClipperOffset::OffsetPolygon(Group& group, const Path64& path)
|
||||||
{
|
{
|
||||||
path_out.clear();
|
path_out.clear();
|
||||||
for (Path64::size_type j = 0, k = path.size() - 1; j < path.size(); k = j, ++j)
|
for (Path64::size_type j = 0, k = path.size() - 1; j < path.size(); k = j, ++j)
|
||||||
if (deltaCallback64_ || path[j] == path[k] ||
|
|
||||||
!OffsetConcaveCrossing(path, norms, j, k, j + 1 == path.size() ? 0 : j + 1, group_delta_, path_out))
|
|
||||||
OffsetPoint(group, path, j, k);
|
OffsetPoint(group, path, j, k);
|
||||||
solution->emplace_back(path_out);
|
solution->emplace_back(path_out);
|
||||||
}
|
}
|
||||||
@@ -632,7 +604,7 @@ void ClipperOffset::ExecuteInternal(double delta)
|
|||||||
bool paths_reversed = CheckReverseOrientation();
|
bool paths_reversed = CheckReverseOrientation();
|
||||||
//clean up self-intersections ...
|
//clean up self-intersections ...
|
||||||
Clipper64 c;
|
Clipper64 c;
|
||||||
c.PreserveCollinear(preserve_collinear_);
|
c.PreserveCollinear(false);
|
||||||
//the solution should retain the orientation of the input
|
//the solution should retain the orientation of the input
|
||||||
c.ReverseSolution(reverse_solution_ != paths_reversed);
|
c.ReverseSolution(reverse_solution_ != paths_reversed);
|
||||||
#ifdef USINGZ
|
#ifdef USINGZ
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Author : Angus Johnson *
|
* Author : Angus Johnson *
|
||||||
* Date : 11 October 2025 *
|
* Date : 5 July 2024 *
|
||||||
* Website : https://www.angusj.com *
|
* Website : https://www.angusj.com *
|
||||||
* Copyright : Angus Johnson 2010-2025 *
|
* Copyright : Angus Johnson 2010-2024 *
|
||||||
* Purpose : FAST rectangular clipping *
|
* Purpose : FAST rectangular clipping *
|
||||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@@ -77,8 +77,8 @@ namespace Clipper2Lib {
|
|||||||
bool GetSegmentIntersection(const Point64& p1,
|
bool GetSegmentIntersection(const Point64& p1,
|
||||||
const Point64& p2, const Point64& p3, const Point64& p4, Point64& ip)
|
const Point64& p2, const Point64& p3, const Point64& p4, Point64& ip)
|
||||||
{
|
{
|
||||||
int res1 = CrossProductSign(p1, p3, p4);
|
double res1 = CrossProduct(p1, p3, p4);
|
||||||
int res2 = CrossProductSign(p2, p3, p4);
|
double res2 = CrossProduct(p2, p3, p4);
|
||||||
if (res1 == 0)
|
if (res1 == 0)
|
||||||
{
|
{
|
||||||
ip = p1;
|
ip = p1;
|
||||||
@@ -97,8 +97,8 @@ namespace Clipper2Lib {
|
|||||||
}
|
}
|
||||||
if ((res1 > 0) == (res2 > 0)) return false;
|
if ((res1 > 0) == (res2 > 0)) return false;
|
||||||
|
|
||||||
int res3 = CrossProductSign(p3, p1, p2);
|
double res3 = CrossProduct(p3, p1, p2);
|
||||||
int res4 = CrossProductSign(p4, p1, p2);
|
double res4 = CrossProduct(p4, p1, p2);
|
||||||
if (res3 == 0)
|
if (res3 == 0)
|
||||||
{
|
{
|
||||||
ip = p3;
|
ip = p3;
|
||||||
@@ -116,7 +116,7 @@ namespace Clipper2Lib {
|
|||||||
if ((res3 > 0) == (res4 > 0)) return false;
|
if ((res3 > 0) == (res4 > 0)) return false;
|
||||||
|
|
||||||
// segments must intersect to get here
|
// segments must intersect to get here
|
||||||
return GetLineIntersectPt(p1, p2, p3, p4, ip);
|
return GetSegmentIntersectPt(p1, p2, p3, p4, ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool GetIntersection(const Path64& rectPath,
|
inline bool GetIntersection(const Path64& rectPath,
|
||||||
@@ -227,7 +227,7 @@ namespace Clipper2Lib {
|
|||||||
const Point64& prev_pt, const Point64& curr_pt, const Point64& rect_mp)
|
const Point64& prev_pt, const Point64& curr_pt, const Point64& rect_mp)
|
||||||
{
|
{
|
||||||
if (AreOpposites(prev, curr))
|
if (AreOpposites(prev, curr))
|
||||||
return CrossProductSign(prev_pt, rect_mp, curr_pt) < 0;
|
return CrossProduct(prev_pt, rect_mp, curr_pt) < 0;
|
||||||
else
|
else
|
||||||
return HeadingClockwise(prev, curr);
|
return HeadingClockwise(prev, curr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,3 @@
|
|||||||
#include "clipper.engine.cpp"
|
#include "clipper.engine.cpp"
|
||||||
#include "clipper.offset.cpp"
|
#include "clipper.offset.cpp"
|
||||||
#include "clipper.rectclip.cpp"
|
#include "clipper.rectclip.cpp"
|
||||||
#include "clipper.triangulation.cpp"
|
|
||||||
|
|||||||
@@ -132,14 +132,14 @@ template<>
|
|||||||
inline void offset(Slic3r::ExPolygon& sh, coord_t distance, const PolygonTag&)
|
inline void offset(Slic3r::ExPolygon& sh, coord_t distance, const PolygonTag&)
|
||||||
{
|
{
|
||||||
#define DISABLE_BOOST_OFFSET
|
#define DISABLE_BOOST_OFFSET
|
||||||
auto res = Slic3r::offset_ex(sh, distance, Slic3r::jtSquare);
|
auto res = Slic3r::offset_ex(sh, distance, Slic3r::ClipperLib::jtSquare);
|
||||||
if (!res.empty()) sh = res.front();
|
if (!res.empty()) sh = res.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void offset(Slic3r::Polygon& sh, coord_t distance, const PathTag&)
|
inline void offset(Slic3r::Polygon& sh, coord_t distance, const PathTag&)
|
||||||
{
|
{
|
||||||
auto res = Slic3r::offset(sh, distance, Slic3r::jtSquare);
|
auto res = Slic3r::offset(sh, distance, Slic3r::ClipperLib::jtSquare);
|
||||||
if (!res.empty()) sh = res.front();
|
if (!res.empty()) sh = res.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ if(Qhull_FOUND)
|
|||||||
message(STATUS "Using qhull from system.")
|
message(STATUS "Using qhull from system.")
|
||||||
if(SLIC3R_STATIC)
|
if(SLIC3R_STATIC)
|
||||||
slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release)
|
slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release)
|
||||||
|
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
target_link_libraries(qhull INTERFACE Qhull::qhullcpp_d Qhull::qhullstatic_rd)
|
||||||
|
else()
|
||||||
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r)
|
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release)
|
slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release)
|
||||||
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r)
|
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r)
|
||||||
|
|||||||
@@ -1,148 +0,0 @@
|
|||||||
# Polygon Clipping — High Level Design
|
|
||||||
|
|
||||||
## Purpose and scope
|
|
||||||
|
|
||||||
Almost every stage of slicing works on 2D regions: slices, perimeters, infill
|
|
||||||
areas, bridges, supports and brims are all produced by boolean operations and
|
|
||||||
offsets on polygons. libslic3r does this through two interfaces, both built on
|
|
||||||
the Clipper2 library vendored in `deps_src/clipper2`:
|
|
||||||
|
|
||||||
- `ClipperUtils` (`src/libslic3r/ClipperUtils.hpp`) takes and returns Slic3r
|
|
||||||
geometry: `Polygon(s)`, `ExPolygon(s)`, `Polyline(s)`, `Lines` and
|
|
||||||
`Surfaces`. It provides unions, intersections, differences and xor, closed
|
|
||||||
and open offsets, morphological opening and closing, variable width offsets
|
|
||||||
and polyline clipping.
|
|
||||||
- `ClipperZUtils` (`src/libslic3r/ClipperZUtils.hpp`) clips paths whose
|
|
||||||
vertices carry a Z value, which callers use to tag vertices with a source
|
|
||||||
index or an extrusion width.
|
|
||||||
|
|
||||||
No other code calls Clipper2.
|
|
||||||
|
|
||||||
`ClipperUtils` declares its own `JoinType`, `EndType`, `PolyFillType` and
|
|
||||||
`ClipType` enums and maps them to Clipper2's. Every call builds its own
|
|
||||||
Clipper2 objects and shares no state, so slicing threads can clip
|
|
||||||
concurrently.
|
|
||||||
|
|
||||||
Clipping is one of the largest costs of slicing, and nearly all of it goes
|
|
||||||
through `ClipperUtils`. The layer is therefore designed for throughput as much
|
|
||||||
as for predictable geometry.
|
|
||||||
|
|
||||||
## Vendored Clipper2
|
|
||||||
|
|
||||||
`deps_src/clipper2` builds the static target `Clipper2`. It carries four
|
|
||||||
changes to the upstream sources that must be carried over when Clipper2 is
|
|
||||||
updated. The namespace switch sits at the top of every header and source, the
|
|
||||||
other three are marked with `Orca:` comments.
|
|
||||||
|
|
||||||
| Change | Files | Why |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Z build in its own namespace | all headers and sources, `clipper2_z.cpp`, `clipper2_z.hpp` | The library is compiled a second time with `USINGZ` in namespace `Clipper2Lib_Z`, so the 2D and the Z variants link into one binary. |
|
|
||||||
| Engine nodes from tbbmalloc | `clipper.engine.h`, `clipper.engine.cpp` | Vertices, active edges, output points and records, local minima and `PolyTree` nodes are allocated one by one. `CLIPPER2_NODE_ALLOCATOR` routes them through `scalable_malloc`, because the default heap does not scale when all slicing threads clip at once. |
|
|
||||||
| Concave joins at the edge crossing | `clipper.offset.cpp` | For closed paths, a concave corner is joined at the crossing of the two offset edges when that point lies within half of both adjacent edges. The upstream 3-point loop makes inward offsets of dense curves very slow to union. |
|
|
||||||
| Rounded arc steps | `clipper.offset.cpp` | Round joins use the rounded number of steps, not the ceiling, which keeps the vertex count of round offsets that the rest of the code is tuned for. |
|
|
||||||
|
|
||||||
## ClipperUtils semantics
|
|
||||||
|
|
||||||
The callers of `ClipperUtils` rely on a fixed set of behaviours. Where
|
|
||||||
Clipper2 behaves differently by default, the wrapper adjusts it.
|
|
||||||
|
|
||||||
### Booleans
|
|
||||||
|
|
||||||
- The fill rule is non-zero unless the function takes a `PolyFillType`. One
|
|
||||||
rule applies to both subject and clip; Clipper2 has no per-operand rule.
|
|
||||||
- Collinear vertices are removed from the result. Clipper2 keeps them by
|
|
||||||
default, so every boolean sets `PreserveCollinear(false)`.
|
|
||||||
- Outer contours are CCW and holes are CW. No output contour touches
|
|
||||||
itself: where one would pass twice through a vertex, it is split there into
|
|
||||||
two contours.
|
|
||||||
- `ExPolygons` results are built from one `PolyTree64` pass. An island inside
|
|
||||||
a hole becomes an `ExPolygon` of its own.
|
|
||||||
- `ApplySafetyOffset::Yes` grows the clip polygons by `ClipperSafetyOffset`
|
|
||||||
before an intersection or a difference, so that edges shared by subject and
|
|
||||||
clip do not leave slivers.
|
|
||||||
- Open polylines are clipped with the non-zero rule and keep their direction.
|
|
||||||
|
|
||||||
### Tiled booleans
|
|
||||||
|
|
||||||
The sweep slows down with the number of edges crossing a scan line, so a layer
|
|
||||||
cut into thousands of pieces makes every whole-layer boolean expensive.
|
|
||||||
`diff_ex_by_piece()` and `intersection_ex_by_piece()` take a subject of
|
|
||||||
non-overlapping `ExPolygons`, group them into tiles with
|
|
||||||
`ClipperUtils::tile_expolygons()`, and run each tile in parallel against only
|
|
||||||
the clip polygons near it, cut to the tile's box. Below 128 pieces there is a
|
|
||||||
single tile, and they are the plain `diff_ex()` / `intersection_ex()`.
|
|
||||||
|
|
||||||
The result covers the same area as the plain call. Without the safety offset
|
|
||||||
the rings are the same. With it, each tile unites only the clip polygons near
|
|
||||||
it, so a clip edge that the whole-layer union splits where it crosses a distant
|
|
||||||
clip polygon stays whole, and a crossing with the subject can round 1 unit
|
|
||||||
differently. The tiles' results are concatenated in tile order, so the order of
|
|
||||||
the output `ExPolygons` differs from the plain call.
|
|
||||||
|
|
||||||
### Offsets
|
|
||||||
|
|
||||||
- Before offsetting, input vertices closer than
|
|
||||||
`ClipperOffsetShortestEdgeFactor` × |delta| to the previously kept vertex
|
|
||||||
are dropped. This bounds the work on dense contours, and the error it
|
|
||||||
introduces is far below the offset distance.
|
|
||||||
- The miter limit is at least 2. For `jtRound`, a positive `miterLimit`
|
|
||||||
argument is the arc tolerance, capped at |delta| / 4, and 0.25 is used
|
|
||||||
otherwise. Other joins use the smaller of 0.25 and |delta| / 4 for round end
|
|
||||||
caps.
|
|
||||||
- A single `Polygon` keeps its orientation: a CCW polygon grows with a
|
|
||||||
positive delta, a CW polygon is a hole and shrinks.
|
|
||||||
- `Polygons` follow the same rule per path. When every CW path lies strictly
|
|
||||||
inside the bounding box of a CCW path, which is the usual case of contours
|
|
||||||
with their holes, all paths are offset in one Clipper2 group. Otherwise
|
|
||||||
each path is offset on its own and the results are united, with the
|
|
||||||
non-zero rule when growing and the positive rule when shrinking.
|
|
||||||
- `ExPolygons` and `Surfaces` are offset as one group after the contours are
|
|
||||||
oriented CCW and the holes CW, whatever their input orientation.
|
|
||||||
- Zero-area paths vanish under a negative offset instead of growing.
|
|
||||||
- Polyline offsets use the requested end type. Clipper2 already unites the
|
|
||||||
result, so no further union is done.
|
|
||||||
|
|
||||||
### Coordinate range
|
|
||||||
|
|
||||||
Clipper2 computes intersections and slopes in doubles, which hold integers
|
|
||||||
exactly only up to 2^53 (about 9e15 units, 9,000 km). Geometry passed to
|
|
||||||
`ClipperUtils` must stay well inside that range; near the int64 limit the
|
|
||||||
results shift by hundreds of units. This is why the arrange `InfiniteBed` is a
|
|
||||||
box of ±2^50 units around its centre rather than libnest2d's infinite box,
|
|
||||||
which reaches ±2.3e18.
|
|
||||||
|
|
||||||
## ClipperZUtils
|
|
||||||
|
|
||||||
`ZPoint` is a `Vec3crd`, and a `ZPath` is a vector of them.
|
|
||||||
`clip_zpaths()` runs one boolean with the non-zero rule on the Clipper2 Z
|
|
||||||
build. The subject may be open, the clip is closed, and the result lists the
|
|
||||||
closed paths before the open ones.
|
|
||||||
|
|
||||||
The Z of each output vertex follows these rules:
|
|
||||||
|
|
||||||
- An input vertex keeps its Z.
|
|
||||||
- An intersection that lies on an end point of one of the two crossing edges
|
|
||||||
takes that end point's Z, preferring the subject edge.
|
|
||||||
- Any other intersection gets its Z from the callback, which receives both
|
|
||||||
crossing edges, the subject edge first.
|
|
||||||
|
|
||||||
Clipper2 calls the callback only when it creates an output vertex at an
|
|
||||||
intersection, not for every crossing it processes. A callback that records
|
|
||||||
intersections, like `ClipperZIntersectionVisitor`, therefore sees only those.
|
|
||||||
|
|
||||||
The users are:
|
|
||||||
|
|
||||||
| User | Z carries |
|
|
||||||
| --- | --- |
|
|
||||||
| `Algorithm::wave_seeds()` (region expansion) | source and boundary index; intersections get a negative index into the visitor's list of crossing pairs |
|
|
||||||
| `Algorithm::split_line()` | index of the source vertex; an intersection gets the negated index of its source edge, so the pieces can be put back in path order |
|
|
||||||
| `PerimeterGenerator` overhang and top-surface clipping of Arachne walls | extrusion width, interpolated along the edge at intersections |
|
|
||||||
| Tree support anchors in `SupportCommon` | index of the source contour, -1 at intersections |
|
|
||||||
| `extrusion_paths_append()` | extrusion width, turned into extrusion paths |
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
`tests/libslic3r/test_clipper_utils.cpp` and `test_clipper_offset.cpp` cover
|
|
||||||
the wrapper's booleans, orientation and offset rules. The perimeter, support
|
|
||||||
and region expansion users are exercised by the slicing tests in
|
|
||||||
`tests/fff_print`.
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
# 3D Scene Benchmark: High Level Design
|
|
||||||
|
|
||||||
## Why it exists
|
|
||||||
|
|
||||||
Rendering changes, such as the realistic view, shadows or SSAO, need a number to compare
|
|
||||||
before and after, and user reports of a slow viewport need a way to say how slow. The FPS
|
|
||||||
overlay and the render timings overlay show live values while someone drags the camera,
|
|
||||||
which varies from run to run with the model, the path of the mouse and the view.
|
|
||||||
|
|
||||||
The benchmark renders a fixed model along a fixed camera path in both 3D views, so two
|
|
||||||
runs on the same machine differ only by the code or the settings, and prints a report that
|
|
||||||
can be pasted into an issue.
|
|
||||||
|
|
||||||
## What it does
|
|
||||||
|
|
||||||
`run_scene_benchmark()` in `src/slic3r/GUI/SceneBenchmark.cpp` is reached from Help >
|
|
||||||
Benchmark 3D Scene, the command palette and Preferences > Graphics. After a confirmation
|
|
||||||
it starts a new project, which asks to save the current one if needed, loads the
|
|
||||||
OrcaSliced Combo handy model and arranges it. A small dialog in a corner of the 3D view
|
|
||||||
then shows the progress; every other window is disabled until the run ends, so a click
|
|
||||||
cannot change the scene being measured. Cancel or Esc stops the run.
|
|
||||||
|
|
||||||
The run goes through these stages, driven by a timer while it waits and by idle events
|
|
||||||
while it renders:
|
|
||||||
|
|
||||||
1. Loading: waits until the UI job worker is idle, so the arrange job has moved the
|
|
||||||
objects. The orbit target is the center of the objects on the current plate, and the
|
|
||||||
base zoom fits their bounding box in the viewport.
|
|
||||||
2. Prepare: renders the scene in the Prepare view.
|
|
||||||
3. Slicing: slices the plate and switches to Preview, then waits for the G-code preview
|
|
||||||
to load. If slicing fails, the report holds Prepare alone.
|
|
||||||
4. Preview: renders the scene in the Preview view, with the slicing progress notification
|
|
||||||
hidden.
|
|
||||||
5. Layers: renders the Preview view again while the layer slider moves, which is what
|
|
||||||
makes dragging it feel slow on large prints.
|
|
||||||
|
|
||||||
The dialog then shows the report, with a button to copy it. A scene cut short, because its
|
|
||||||
view was hidden, is left out of the report.
|
|
||||||
|
|
||||||
## Rendering a scene
|
|
||||||
|
|
||||||
Each scene renders 30 warm-up frames, then the camera path twice, 360 frames each time.
|
|
||||||
|
|
||||||
- The first pass times the frames. A frame's time is the interval between the starts of
|
|
||||||
consecutive benchmark frames, so it includes the event loop between them.
|
|
||||||
- The second pass averages the render timings. The frame profiler flushes the GL command
|
|
||||||
queue after each section, which slows a frame down, so it only runs in this pass.
|
|
||||||
`FrameProfiler::start_averaging()` flags every frame begun afterwards, and
|
|
||||||
`finish_averaging()` waits for the flagged frames still on the GPU and returns the mean
|
|
||||||
CPU and GPU time of each section per profiled frame.
|
|
||||||
- A section's GPU time is taken between a timestamp before its commands and one after
|
|
||||||
them. The first is only sent along with those commands, so when the GPU finishes a
|
|
||||||
section before the CPU has issued the next one, the wait counts in neither.
|
|
||||||
|
|
||||||
The dialog renders one frame per idle event by calling `GLCanvas3D::render()`, which
|
|
||||||
redraws the whole scene. While `GLCanvas3D::set_benchmarking()` is on, the canvas does not
|
|
||||||
render from its own idle handler, so no other frame is drawn in between, and it skips the
|
|
||||||
picking pass and the FPS and render timings overlays, which depend on the mouse and on
|
|
||||||
preferences. The FPS cap does not apply, since it only paces idle redraws.
|
|
||||||
|
|
||||||
VSync is turned off for the scene through `wxGLCanvas::SetSwapInterval(0)`, so the frame
|
|
||||||
rate is what the GPU and CPU can reach rather than the display's refresh rate, and the
|
|
||||||
previous interval is restored afterwards. When the platform cannot report the current
|
|
||||||
interval (EGL), it is left as it is and the report says so.
|
|
||||||
|
|
||||||
The camera path makes two turns around the target while the view rises three times from
|
|
||||||
25 degrees below the plate to 85 degrees above it and the zoom goes twice between 0.6 and
|
|
||||||
1.4 times the base zoom. The camera stays at the default distance, so the perspective is
|
|
||||||
the same in every run. The camera the scene started with is restored at its end.
|
|
||||||
|
|
||||||
The Layers scene holds the camera at the start of that path and moves the top of the layer
|
|
||||||
slider instead, from the last layer down to the first and back up in each pass. It goes
|
|
||||||
through `IMSlider::SetHigherValue()`, as a drag does, so every frame applies a new layer
|
|
||||||
range to the toolpaths and the objects before drawing them, including a new shadow map when
|
|
||||||
the shadows are static. Its warm-up frames lead into the start of the path, so the slider
|
|
||||||
moves in every frame. The slider position it started from is restored at its end.
|
|
||||||
|
|
||||||
## The report
|
|
||||||
|
|
||||||
The report is plain English text, so it reads the same in every language:
|
|
||||||
|
|
||||||
- The version and build commit, the GPU and OpenGL version, the viewport size and camera
|
|
||||||
type, and the graphics settings that change the cost of a frame: MSAA samples as read
|
|
||||||
from the framebuffer, FXAA, the scene cache, VSync and the realistic view options.
|
|
||||||
- The printer and process presets the model was sliced with, marked when they have
|
|
||||||
unsaved changes, and the toolpath vertices and layers they produced, since the Preview
|
|
||||||
scenes cost more with more toolpaths.
|
|
||||||
- For each scene, the average FPS and the average, median, 95th percentile, 99th
|
|
||||||
percentile and maximum frame time. Percentiles are nearest-rank, so each is a measured
|
|
||||||
frame (`frame_time_stats()`).
|
|
||||||
- For each scene, the render timings table: the CPU and GPU milliseconds of each section
|
|
||||||
of a frame, and their total. Without timer queries (OpenGL 3.3 or `ARB_timer_query`) the
|
|
||||||
table says that the driver does not support them.
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
# Section view — High Level Design
|
|
||||||
|
|
||||||
## Purpose and scope
|
|
||||||
|
|
||||||
Section view hides whatever lies between the camera and a plane, so the user can look inside
|
|
||||||
objects in Prepare and in the assembly view, and inside the toolpaths in Preview. It is a view
|
|
||||||
setting: it changes nothing in the model, the slice or the project file, and it does not reach
|
|
||||||
plate thumbnails.
|
|
||||||
|
|
||||||
The user controls it from the section button of the canvas toolbar in the bottom left corner of
|
|
||||||
the 3D view. The button opens a panel above it with a slider for the depth of the cut, a "Set
|
|
||||||
viewing angle" button that turns the plane to face the camera at the same depth, and a button that
|
|
||||||
resets the depth to zero. The panel is an ordinary overlay window, not a popup, so the scene keeps
|
|
||||||
taking clicks and drags while it is open; the button or Esc closes it again. Esc closes the panel
|
|
||||||
before it closes a gizmo or clears the selection. The button is highlighted
|
|
||||||
while a section cuts the scene and has shortcuts of its own: the mouse wheel over it moves the
|
|
||||||
plane, a right click switches the section off and back on, and a middle click sets the viewing
|
|
||||||
angle. Alt + mouse wheel moves the plane anywhere in the 3D view, with or without a gizmo open.
|
|
||||||
|
|
||||||
## State
|
|
||||||
|
|
||||||
Prepare and Preview share one section view, so a cut made in either tab is the same cut in the
|
|
||||||
other. The assembly view, whose objects sit apart from their places on the plate, and the Design
|
|
||||||
tab keep their own. The section itself is two values.
|
|
||||||
|
|
||||||
- **Ratio**, from 0 to 1. At 0 the section is off. As the ratio grows, the plane sweeps the
|
|
||||||
sphere around the objects, from its side facing the camera to the opposite side, so at 1
|
|
||||||
everything is cut away.
|
|
||||||
- **Normal**, taken from the camera direction the first time the section is switched on, and
|
|
||||||
again whenever the user sets the viewing angle. The plane keeps that orientation while the
|
|
||||||
camera orbits and while the section is off, so the cut face can be seen from any side and
|
|
||||||
bringing the depth back to 0 does not lose the angle.
|
|
||||||
|
|
||||||
The ratio in use when the section is switched off is kept, and the right click on the button
|
|
||||||
brings the section back at that ratio, which restores the same cut. Whether the panel is open is
|
|
||||||
shared along with the section.
|
|
||||||
|
|
||||||
The sphere is recomputed every frame from the volumes of the canvas the section view belongs to:
|
|
||||||
the objects on the current plate, or every object when that plate is empty. Preview holds no
|
|
||||||
objects of its own, so it places the plane across the volumes of Prepare, which makes it cut the
|
|
||||||
toolpaths exactly where Prepare cuts the objects. Only G-code opened on its own, without objects,
|
|
||||||
is measured by its toolpaths. In the assembly view the sphere is around the whole assembly. The
|
|
||||||
ratio therefore keeps its meaning when objects move or the user switches plates. It is not a
|
|
||||||
fixed position in world space.
|
|
||||||
|
|
||||||
Only the tab on screen can change the section, and switching tabs redraws the whole scene and
|
|
||||||
closes the open gizmo, so neither tab ever shows a stale cut.
|
|
||||||
|
|
||||||
## Where the plane applies
|
|
||||||
|
|
||||||
`GLCanvas3D::_get_section_view_plane()` turns the state into a plane in the convention of
|
|
||||||
`ClippingPlane::is_point_clipped()`. Everything that draws or picks the scene reads that plane.
|
|
||||||
|
|
||||||
- **Volumes.** The plane goes to the `clipping_plane` uniform of the volume shaders. The same
|
|
||||||
uniform serves the gouraud, phong and X-ray passes and the colour picking pass.
|
|
||||||
- **Cut faces.** Clipping only discards fragments, which would leave the cut volumes hollow.
|
|
||||||
`_render_section_view_caps()` draws their cut faces with one `MeshClipper` per model part the
|
|
||||||
plane passes through. A clipper recomputes its face only when the plane or the volume moves.
|
|
||||||
Modifiers, the wipe tower and SLA auxiliaries get no face.
|
|
||||||
- **Toolpaths.** libvgcode takes the plane through `Viewer::set_clipping_plane()`. It draws each
|
|
||||||
extrusion as only the faces of a diamond-section prism that turn towards the camera, so
|
|
||||||
discarding the fragments on the clipped side would leave open shells. Instead, the segment
|
|
||||||
shader follows the view ray from a fragment that is cut away to the plane. When the
|
|
||||||
extrusion's diamond section still holds that point, the fragment is shaded as the cut face, lit
|
|
||||||
as the plane faces; otherwise it is discarded. The cut face keeps the depth of the fragment it
|
|
||||||
replaces, which is safe: along that ray everything else still shown lies behind the plane. The
|
|
||||||
shader writes no `gl_FragDepth`, so early depth testing survives. Option markers are cut away
|
|
||||||
whole, by their centres. The shadow casters draw with a program of their own, which takes the
|
|
||||||
plane and discards the fragments on the clipped side, so what is cut away casts no shadow either.
|
|
||||||
Their cut faces are not drawn, since the part left behind casts the shadow of its own section.
|
|
||||||
Preview shells are drawn by another shader and are not clipped.
|
|
||||||
- **Picking.** `get_raycaster_clipping_plane()` returns the same plane, so hover, selection and
|
|
||||||
the perspective pan anchor ignore what the user cannot see.
|
|
||||||
|
|
||||||
## Gizmos
|
|
||||||
|
|
||||||
A gizmo that clips its object itself owns the gizmo data pool's `ObjectClipper`, and its plane
|
|
||||||
replaces the canvas section while the gizmo is open. `GLGizmosManager::get_clipping_plane()`
|
|
||||||
reports that plane, or nothing when no open gizmo has a clipper. There are two cases.
|
|
||||||
|
|
||||||
- **Painting tools and brim ears** show the canvas section on the object they edit.
|
|
||||||
`GLGizmosManager::update_section_view()` copies the ratio and normal into their clipper
|
|
||||||
whenever the pool is updated or the section changes. The clipper then places the plane across
|
|
||||||
the edited instance, which is the only object shown. The painting tools keep clipping their
|
|
||||||
own triangles, raycasts and cut face through it. Brim ears always cut horizontally from the
|
|
||||||
top, because the ears sit on the plate. At ratio 0 the clipper holds no plane at all, so the
|
|
||||||
raycasts are not clipped.
|
|
||||||
- **Cut and mesh boolean** use the clipper for their own purposes, so the canvas section is
|
|
||||||
suspended while they are open.
|
|
||||||
|
|
||||||
Every other gizmo, including move, rotate and scale, leaves the canvas section in place.
|
|
||||||
|
|
||||||
## Alt + mouse wheel
|
|
||||||
|
|
||||||
The canvas handles Alt + wheel after the gizmos had their turn, so it works the same in every
|
|
||||||
tab and with any gizmo open. On Windows, releasing Alt when no key was pressed since it went down
|
|
||||||
opens the window menu, and a wheel turn does not count as a key. Under the custom title bar that
|
|
||||||
menu is invisible, yet it takes the keyboard and the next click, which looks like a frozen 3D
|
|
||||||
view. After Alt + wheel the canvas therefore consumes the Alt release instead of passing it on.
|
|
||||||
|
|
||||||
## Redraw
|
|
||||||
|
|
||||||
The button and the panel are part of the ImGui overlay, which is built after the frame's scene is
|
|
||||||
drawn. A change to the section therefore marks the scene dirty and asks for one more frame. The
|
|
||||||
cached scene is never reused across a change.
|
|
||||||
@@ -180,7 +180,6 @@ src/slic3r/GUI/PrivacyUpdateDialog.cpp
|
|||||||
src/slic3r/GUI/PublishDialog.cpp
|
src/slic3r/GUI/PublishDialog.cpp
|
||||||
src/slic3r/GUI/PublishSettingsDialog.cpp
|
src/slic3r/GUI/PublishSettingsDialog.cpp
|
||||||
src/slic3r/GUI/SavePresetDialog.cpp
|
src/slic3r/GUI/SavePresetDialog.cpp
|
||||||
src/slic3r/GUI/SceneBenchmark.cpp
|
|
||||||
src/slic3r/GUI/Search.cpp
|
src/slic3r/GUI/Search.cpp
|
||||||
src/slic3r/GUI/SettingsIndex.cpp
|
src/slic3r/GUI/SettingsIndex.cpp
|
||||||
src/slic3r/GUI/SpeedDialDialog.cpp
|
src/slic3r/GUI/SpeedDialDialog.cpp
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#fafafa;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#2b3436; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#009688;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#ffffff; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#00675b;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#ffffff; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#008172;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#ffffff; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#26a69a;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#ffffff; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#ffffff; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#393c42;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#b6b6b6; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#283232;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#b6b6b6; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#b6b6b6; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36"><circle cx="17.5" cy="17.5" r="17.5" style="fill:#e5f0ee;"/><polygon points="13.82,11.62 21.18,15.88 21.18,23.38 13.82,19.12" style="fill:#2b3436; fill-opacity:.55;"/><polygon points="8.75,14.55 16.11,18.80 16.11,26.30 8.75,22.05" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="8.75,14.55 12.43,12.43 19.79,16.68 16.11,18.80" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polyline points="19.79,16.68 19.79,24.18 16.11,26.30" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round; stroke-opacity:.45;"/><polygon points="13.82,11.62 17.50,9.50 24.86,13.75 24.86,21.25 21.18,23.38 13.82,19.12" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/><polyline points="13.82,11.62 21.18,15.88 24.86,13.75" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/><line x1="21.18" y1="15.88" x2="21.18" y2="23.38" style="fill:none; stroke:#2b3436; stroke-linecap:round; stroke-linejoin:round;"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Snapmaker",
|
"name": "Snapmaker",
|
||||||
"version": "02.04.00.17",
|
"version": "02.04.00.16",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Snapmaker configurations",
|
"description": "Snapmaker configurations",
|
||||||
"machine_model_list": [
|
"machine_model_list": [
|
||||||
@@ -1448,10 +1448,6 @@
|
|||||||
"name": "Snapmaker PETG HF @U1 0.2 nozzle",
|
"name": "Snapmaker PETG HF @U1 0.2 nozzle",
|
||||||
"sub_path": "filament/Snapmaker PETG HF @U1 0.2 nozzle.json"
|
"sub_path": "filament/Snapmaker PETG HF @U1 0.2 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Snapmaker PETG HF @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Snapmaker PETG HF @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Snapmaker PETG HF @U1 0.6 nozzle",
|
"name": "Snapmaker PETG HF @U1 0.6 nozzle",
|
||||||
"sub_path": "filament/Snapmaker PETG HF @U1 0.6 nozzle.json"
|
"sub_path": "filament/Snapmaker PETG HF @U1 0.6 nozzle.json"
|
||||||
@@ -1924,122 +1920,6 @@
|
|||||||
"name": "Snapmaker Breakaway Support For PLA @U1 0.8 nozzle",
|
"name": "Snapmaker Breakaway Support For PLA @U1 0.8 nozzle",
|
||||||
"sub_path": "filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json"
|
"sub_path": "filament/Snapmaker Breakaway Support For PLA @U1 0.8 nozzle.json"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Generic PETG @U1 0.2 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG @U1 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG HF @U1 0.2 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG HF @U1 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG HF @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG HF @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG HF @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG HF @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG HF @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG HF @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG-CF @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG-CF @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG-CF @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG-CF @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PETG-CF @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PETG-CF @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @U1 0.2 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA @U1 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA High Speed @U1 0.2 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA High Speed @U1 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA High Speed @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA High Speed @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA High Speed @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA High Speed @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA High Speed @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA High Speed @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA Silk @U1 0.2 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA Silk @U1 0.2 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA Silk @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA Silk @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA Silk @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA Silk @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA Silk @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA Silk @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA-CF @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA-CF @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA-CF @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA-CF @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic PLA-CF @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic PLA-CF @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic TPU @U1 0.4 nozzle",
|
|
||||||
"sub_path": "filament/Generic TPU @U1 0.4 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic TPU @U1 0.6 nozzle",
|
|
||||||
"sub_path": "filament/Generic TPU @U1 0.6 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic TPU @U1 0.8 nozzle",
|
|
||||||
"sub_path": "filament/Generic TPU @U1 0.8 nozzle.json"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "PolyTerra J1 PLA",
|
"name": "PolyTerra J1 PLA",
|
||||||
"sub_path": "filament/Polymaker/PolyTerra J1 PLA.json"
|
"sub_path": "filament/Polymaker/PolyTerra J1 PLA.json"
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @U1 0.2 nozzle",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Iw7T4qqDf1fbSAa1",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.2 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"10",
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "VHRa4TXU7HPz7Fld",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"10",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Ubr8v7BTxiQMntVk",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"10",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PETG @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "ro0mXCLzC5rY95oX",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"10",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG HF @U1 0.2 nozzle",
|
|
||||||
"inherits": "Generic PETG HF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "7yjLWAdcQe4ndo1z",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.2 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20",
|
|
||||||
"1"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG HF @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PETG HF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "XWWLYZWkD9ZNRPeO",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20",
|
|
||||||
"16"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG HF @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PETG HF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "1dj4JdFabSql3cEg",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20",
|
|
||||||
"16"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG HF @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PETG HF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "1LYZ0KG5kQtaOOKt",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"20",
|
|
||||||
"16"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG-CF @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PETG-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "wIKcBM1qLgzLEUJP",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"11.5",
|
|
||||||
"11"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"5",
|
|
||||||
"5"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG-CF @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PETG-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "FvrnBiPbjSvIF3kN",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"5",
|
|
||||||
"5"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PETG-CF @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PETG-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "SCfvzDgUWkFHmbtP",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"5",
|
|
||||||
"5"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"40",
|
|
||||||
"40"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @U1 0.2 nozzle",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "8pb3tert1D4w0SKP",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.2 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"1.6"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Uilm8oVmZzyxE3ba",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "aj4G9OSdgtQPqpkI",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PLA @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "zom29gBgIZmvjFmh",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA High Speed @U1 0.2 nozzle",
|
|
||||||
"inherits": "Generic PLA High Speed @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "rT8e5f81vwUpwPuq",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.2 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"18",
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA High Speed @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PLA High Speed @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "ZUetX0WveqW8fy6f",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"18",
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA High Speed @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PLA High Speed @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "y2WY6qLA3xKZM1Mm",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"18",
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA High Speed @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PLA High Speed @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "VwXJrdwxvzjlIGal",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"18",
|
|
||||||
"18"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA Silk @U1 0.2 nozzle",
|
|
||||||
"inherits": "Generic PLA Silk @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "381SJIDBre8HxHy2",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.2 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"7.5",
|
|
||||||
"2"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA Silk @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PLA Silk @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Fd1g9OdeM3pUx8f5",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA Silk @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PLA Silk @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "8rhmpBFmMj9vVZwG",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA Silk @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PLA Silk @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Fo7U7GYHZh1aZPLs",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA-CF @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic PLA-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "6AWubtDE4PqrKVNJ",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA-CF @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic PLA-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "AvM44HgMCkOCnmzY",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic PLA-CF @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic PLA-CF @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "tvYAUvQEbbdBCIg2",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"filament_max_volumetric_speed": [
|
|
||||||
"12",
|
|
||||||
"12"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic TPU @U1 0.4 nozzle",
|
|
||||||
"inherits": "Generic TPU @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "9d0jRdMgkPMahYL7",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.4 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic TPU @U1 0.6 nozzle",
|
|
||||||
"inherits": "Generic TPU @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "LLjEPSU4l09N3Zb8",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.6 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "filament",
|
|
||||||
"name": "Generic TPU @U1 0.8 nozzle",
|
|
||||||
"inherits": "Generic TPU @System",
|
|
||||||
"from": "system",
|
|
||||||
"setting_id": "Wfhd3jLEjSKzCeHE",
|
|
||||||
"instantiation": "true",
|
|
||||||
"compatible_printers": [
|
|
||||||
"Snapmaker U1 (0.8 nozzle)"
|
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -10,18 +10,15 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
"Polymaker"
|
"Polymaker"
|
||||||
],
|
],
|
||||||
"nozzle_temperature_range_high": [
|
"nozzle_temperature_range_high": [
|
||||||
"230",
|
|
||||||
"230"
|
"230"
|
||||||
],
|
],
|
||||||
"temperature_vitrification": [
|
"temperature_vitrification": [
|
||||||
@@ -32,21 +29,5 @@
|
|||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"65"
|
"65"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,12 @@
|
|||||||
"Polymaker"
|
"Polymaker"
|
||||||
],
|
],
|
||||||
"nozzle_temperature": [
|
"nozzle_temperature": [
|
||||||
"230",
|
|
||||||
"230"
|
"230"
|
||||||
],
|
],
|
||||||
"nozzle_temperature_initial_layer": [
|
"nozzle_temperature_initial_layer": [
|
||||||
"230",
|
|
||||||
"230"
|
"230"
|
||||||
],
|
],
|
||||||
"nozzle_temperature_range_high": [
|
"nozzle_temperature_range_high": [
|
||||||
"230",
|
|
||||||
"230"
|
"230"
|
||||||
],
|
],
|
||||||
"textured_plate_temp": [
|
"textured_plate_temp": [
|
||||||
@@ -32,21 +29,5 @@
|
|||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"65"
|
"65"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
"1.23"
|
"1.23"
|
||||||
],
|
],
|
||||||
"filament_flow_ratio": [
|
"filament_flow_ratio": [
|
||||||
"0.96",
|
|
||||||
"0.96"
|
"0.96"
|
||||||
],
|
],
|
||||||
"filament_vendor": [
|
"filament_vendor": [
|
||||||
@@ -30,21 +29,5 @@
|
|||||||
],
|
],
|
||||||
"textured_plate_temp_initial_layer": [
|
"textured_plate_temp_initial_layer": [
|
||||||
"65"
|
"65"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,27 +9,9 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.05",
|
|
||||||
"0.05"
|
"0.05"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"30",
|
|
||||||
"30"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,35 +9,18 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"filament_retraction_length": [
|
"filament_retraction_length": [
|
||||||
"1.0",
|
|
||||||
"1.0"
|
"1.0"
|
||||||
],
|
],
|
||||||
"filament_z_hop": [
|
"filament_z_hop": [
|
||||||
"0.0",
|
|
||||||
"0.0"
|
"0.0"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1",
|
|
||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.05",
|
|
||||||
"0.05"
|
"0.05"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"20",
|
|
||||||
"20"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"50",
|
|
||||||
"50"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,35 +9,18 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"filament_retraction_length": [
|
"filament_retraction_length": [
|
||||||
"1.0",
|
|
||||||
"1.0"
|
"1.0"
|
||||||
],
|
],
|
||||||
"filament_z_hop": [
|
"filament_z_hop": [
|
||||||
"0.0",
|
|
||||||
"0.0"
|
"0.0"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1",
|
|
||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.08",
|
|
||||||
"0.08"
|
"0.08"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,32 +9,16 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"filament_retraction_length": [
|
"filament_retraction_length": [
|
||||||
"1.0",
|
|
||||||
"1.0"
|
"1.0"
|
||||||
],
|
],
|
||||||
"filament_z_hop": [
|
"filament_z_hop": [
|
||||||
"0.0",
|
|
||||||
"0.0"
|
"0.0"
|
||||||
],
|
],
|
||||||
"description": " ",
|
"description": " ",
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"1",
|
|
||||||
"1"
|
"1"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"supertack_plate_temp": [
|
"supertack_plate_temp": [
|
||||||
@@ -19,19 +18,6 @@
|
|||||||
"70"
|
"70"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.04",
|
|
||||||
"0.04"
|
"0.04"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"20",
|
|
||||||
"20"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,7 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"description": " ",
|
"description": " "
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"10",
|
|
||||||
"10"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"0",
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,27 +10,9 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"filament_wipe": [
|
"filament_wipe": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,30 +10,18 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"fan_max_speed": [
|
"fan_max_speed": [
|
||||||
"100",
|
|
||||||
"100"
|
"100"
|
||||||
],
|
],
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"100",
|
|
||||||
"100"
|
"100"
|
||||||
],
|
],
|
||||||
"filament_flow_ratio": [
|
"filament_flow_ratio": [
|
||||||
"0.98",
|
|
||||||
"0.98"
|
"0.98"
|
||||||
],
|
],
|
||||||
"filament_max_volumetric_speed": [
|
"filament_max_volumetric_speed": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
],
|
||||||
"slow_down_layer_time": [
|
"slow_down_layer_time": [
|
||||||
"4"
|
"4"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,6 @@
|
|||||||
"Snapmaker U1 (0.4 nozzle)"
|
"Snapmaker U1 (0.4 nozzle)"
|
||||||
],
|
],
|
||||||
"filament_minimal_purge_on_wipe_tower": [
|
"filament_minimal_purge_on_wipe_tower": [
|
||||||
"15",
|
|
||||||
"15"
|
"15"
|
||||||
],
|
|
||||||
"filament_extruder_variant": [
|
|
||||||
"Direct Drive Standard",
|
|
||||||
"Direct Drive High Flow"
|
|
||||||
],
|
|
||||||
"fan_min_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"fan_max_speed": [
|
|
||||||
"100",
|
|
||||||
"100"
|
|
||||||
],
|
|
||||||
"additional_cooling_fan_speed": [
|
|
||||||
"70",
|
|
||||||
"70"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||