Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d80c69341c | ||
|
|
4a63a7d916 | ||
|
|
de1dfd0611 | ||
|
|
11a5971cef | ||
|
|
82f37ddb3a | ||
|
|
fb03d1a1cb | ||
|
|
2b4bdead73 | ||
|
|
b1f0d6c6f6 | ||
|
|
14751a8b06 | ||
|
|
9a86d79038 | ||
|
|
d905f1a39b | ||
|
|
84ec518f26 | ||
|
|
1fc153308f | ||
|
|
3167c3665a | ||
|
|
6d34d83e78 | ||
|
|
222c6a2df5 | ||
|
|
70bc02467b | ||
|
|
4ffba13210 | ||
|
|
a1ad2b4425 | ||
|
|
6c6e8be43d | ||
|
|
205de9ce63 | ||
|
|
1255af1e9c | ||
|
|
8bf7b73141 | ||
|
|
e63c6d0594 | ||
|
|
79a89f817f | ||
|
|
83ee4f4476 | ||
|
|
390b7d8e6d | ||
|
|
1a5f91d727 | ||
|
|
9d71125495 | ||
|
|
88f05d3060 | ||
|
|
4743d00793 | ||
|
|
2f4758446a | ||
|
|
c023632a7d |
@@ -0,0 +1,47 @@
|
||||
# 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,7 +206,8 @@ 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-
|
||||
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
|
||||
afterwards with a deferred, liveness-guarded `Raise()`; a live menu accelerator consumes the key before
|
||||
afterwards with a deferred, liveness-guarded `Raise()` — but never `Raise()` a `wxPopupWindow`, which makes
|
||||
it the key window; a live menu accelerator consumes the key before
|
||||
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
|
||||
`dark_mode()`; menu bitmaps follow `check_dark_mode()`; windows are not double-buffered by default in
|
||||
|
||||
@@ -57,8 +57,9 @@ 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)
|
||||
18. Content that needs typing focus or hosts a `wxWebView` uses a frameless `wxDialog` that hides on
|
||||
deactivation, not a transient popup. (§10)
|
||||
19. Display-only overlays (HUDs, toasts) use a plain `wxPopupWindow`: it never takes focus and never
|
||||
auto-dismisses. (§4, §10)
|
||||
19. Display-only overlays (HUDs, toasts) use a plain `wxPopupWindow`: `Show()` never gives it focus and it
|
||||
never auto-dismisses. Never `Raise()` any `wxPopupWindow`: `Raise()` is for top-level windows only, and on
|
||||
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)
|
||||
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
|
||||
@@ -356,6 +357,13 @@ compensates for (§6).
|
||||
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.
|
||||
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
|
||||
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
|
||||
@@ -739,8 +747,26 @@ 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
|
||||
`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
|
||||
window cannot take focus. On macOS these overlays hide while the app is inactive (§5).
|
||||
window does not take focus when shown. On macOS these overlays hide while the app is inactive (§5).
|
||||
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
|
||||
|
||||
|
||||
@@ -428,7 +428,8 @@ 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
|
||||
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
|
||||
already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:896-899`).
|
||||
already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:897-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,
|
||||
`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:
|
||||
- cron: '0 17 * * *' # run once a day at 1 AM Singapore time (UTC+8)
|
||||
- cron: '15 2 * * *' # 10:15 AM Singapore time (UTC+8), when macOS runners are least busy
|
||||
|
||||
workflow_dispatch: # allows for manual dispatch
|
||||
inputs:
|
||||
|
||||
@@ -49,28 +49,11 @@ jobs:
|
||||
key: ${{ inputs.cache-key }}
|
||||
|
||||
- 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:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||
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
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
@@ -54,28 +54,11 @@ jobs:
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- 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:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||
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
|
||||
# restore it and discard what they compiled. Objects are keyed on the
|
||||
# preprocessed source, the compiler and the flags, so a leg only ever
|
||||
@@ -276,6 +259,7 @@ jobs:
|
||||
# Thanks to RaySajuuk, it's working now
|
||||
- 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
|
||||
timeout-minutes: 30
|
||||
working-directory: ${{ github.workspace }}
|
||||
env:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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 ]
|
||||
@@ -44,14 +44,6 @@ jobs:
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
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
|
||||
with:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
|
||||
@@ -135,6 +135,7 @@ set(ORCA_UV_SHA256_aarch64-apple-darwin "1f921d491ba5ffeea774eb04d6681ecee3
|
||||
set(ORCA_UV_SHA256_x86_64-apple-darwin "f3c8e5708a84b920c18b691214d54d2b0da6b984789caae95d47c95120cb7765")
|
||||
set(ORCA_UV_SHA256_aarch64-unknown-linux-gnu "88e800834007cc5efd4675f166eb2a51e7e3ad19876d85fa8805a6fb5c922397")
|
||||
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")
|
||||
|
||||
# Version-scoped cache dir so a version bump invalidates the cached binary.
|
||||
@@ -173,7 +174,10 @@ if(NOT ORCA_BUNDLED_UV_EXECUTABLE)
|
||||
set(ORCA_UV_ARCH "x86_64-unknown-linux-gnu")
|
||||
endif()
|
||||
elseif(_orca_uv_proc MATCHES "aarch64|arm64|ARM64")
|
||||
if(APPLE)
|
||||
if(WIN32)
|
||||
set(ORCA_UV_ARCH "aarch64-pc-windows-msvc")
|
||||
set(ORCA_UV_EXT "zip")
|
||||
elseif(APPLE)
|
||||
set(ORCA_UV_ARCH "aarch64-apple-darwin")
|
||||
else()
|
||||
set(ORCA_UV_ARCH "aarch64-unknown-linux-gnu")
|
||||
@@ -819,7 +823,9 @@ if(SLIC3R_STATIC)
|
||||
set(TBB_STATIC 1)
|
||||
endif()
|
||||
set(TBB_DEBUG 1)
|
||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "")
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo" OR MSVC)
|
||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "")
|
||||
endif()
|
||||
find_package(TBB REQUIRED)
|
||||
# include_directories(SYSTEM ${TBB_INCLUDE_DIRS})
|
||||
# add_definitions(${TBB_DEFINITIONS})
|
||||
@@ -1301,6 +1307,14 @@ if (WIN32)
|
||||
endif()
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
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 ".")
|
||||
elseif (SLIC3R_FHS)
|
||||
# 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>
|
||||
|
||||
[](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.
|
||||
Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.
|
||||
|
||||
@@ -282,11 +282,7 @@ if "%install_deps%" == "ON" (
|
||||
call :note_failed "Visual Studio" !errorlevel!
|
||||
)
|
||||
|
||||
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 :print_and_run winget install !winget_args! --id=Kitware.CMake
|
||||
call :note_failed CMake !errorlevel!
|
||||
call :print_and_run winget install !winget_args! --id=StrawberryPerl.StrawberryPerl
|
||||
call :note_failed Perl !errorlevel!
|
||||
|
||||
@@ -29,6 +29,15 @@ if(WIN32)
|
||||
# driven through nmake from a Ninja configure step.
|
||||
set(_conf_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} perl Configure )
|
||||
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(_install_cmd ${CMAKE_COMMAND} -E env ${_openssl_msvc_env} nmake install_sw )
|
||||
else()
|
||||
@@ -71,6 +80,7 @@ ExternalProject_Add(dep_OpenSSL
|
||||
# prefix stays single-layout.
|
||||
"--libdir=lib"
|
||||
${_cross_comp_prefix_line}
|
||||
${_openssl_extra_cflags}
|
||||
no-shared
|
||||
no-asm
|
||||
no-ssl3-method
|
||||
|
||||
@@ -15,7 +15,6 @@ add_subdirectory(stb_dxt) # Header-only STB DXT compression library
|
||||
# Static libraries
|
||||
add_subdirectory(Shiny)
|
||||
add_subdirectory(admesh)
|
||||
add_subdirectory(clipper)
|
||||
add_subdirectory(clipper2)
|
||||
add_subdirectory(expat)
|
||||
add_subdirectory(glu-libtess)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
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
|
||||
)
|
||||
@@ -1,606 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* 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
|
||||
@@ -1,7 +0,0 @@
|
||||
// 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"
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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)
|
||||
project(Clipper2 VERSION 1.5.2 LANGUAGES C CXX)
|
||||
project(Clipper2 VERSION 2.0.1 LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
@@ -19,6 +19,7 @@ set(CLIPPER2_INC
|
||||
Clipper2Lib/include/clipper2/clipper.minkowski.h
|
||||
Clipper2Lib/include/clipper2/clipper.offset.h
|
||||
Clipper2Lib/include/clipper2/clipper.rectclip.h
|
||||
Clipper2Lib/include/clipper2/clipper.triangulation.h
|
||||
Clipper2Lib/include/clipper2/clipper2_z.hpp
|
||||
)
|
||||
|
||||
@@ -26,6 +27,7 @@ set(CLIPPER2_SRC
|
||||
Clipper2Lib/src/clipper.engine.cpp
|
||||
Clipper2Lib/src/clipper.offset.cpp
|
||||
Clipper2Lib/src/clipper.rectclip.cpp
|
||||
Clipper2Lib/src/clipper.triangulation.cpp
|
||||
Clipper2Lib/src/clipper2_z.cpp
|
||||
)
|
||||
|
||||
@@ -36,6 +38,9 @@ target_include_directories(Clipper2
|
||||
PUBLIC Clipper2Lib/include
|
||||
)
|
||||
|
||||
# Engine nodes are allocated through tbbmalloc (see clipper.engine.cpp).
|
||||
target_link_libraries(Clipper2 PRIVATE TBB::tbbmalloc)
|
||||
|
||||
if (WIN32)
|
||||
if (MSVC AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 12 May 2024 *
|
||||
* Date : 12 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Core Clipper Library structures and functions *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -251,6 +251,20 @@ namespace Clipper2Lib {
|
||||
template <typename 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 PathD = Path<double>;
|
||||
using Paths64 = std::vector< Path64>;
|
||||
@@ -685,32 +699,31 @@ namespace Clipper2Lib {
|
||||
|
||||
inline int TriSign(int64_t x) // returns 0, 1 or -1
|
||||
{
|
||||
return (x > 0) - (x < 0);
|
||||
return (x > 0) - (x < 0);
|
||||
}
|
||||
|
||||
struct MultiplyUInt64Result
|
||||
struct UInt128Struct
|
||||
{
|
||||
const uint64_t result = 0;
|
||||
const uint64_t carry = 0;
|
||||
const uint64_t lo = 0;
|
||||
const uint64_t hi = 0;
|
||||
|
||||
bool operator==(const MultiplyUInt64Result& other) const
|
||||
bool operator==(const UInt128Struct& other) const
|
||||
{
|
||||
return result == other.result && carry == other.carry;
|
||||
return lo == other.lo && hi == other.hi;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
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 hi = [](uint64_t x) { return x >> 32; };
|
||||
|
||||
const uint64_t x1 = lo(a) * lo(b);
|
||||
const uint64_t x2 = hi(a) * lo(b) + hi(x1);
|
||||
const uint64_t x3 = lo(a) * hi(b) + lo(x2);
|
||||
const uint64_t result = lo(x3) << 32 | lo(x1);
|
||||
const uint64_t carry = hi(a) * hi(b) + hi(x2) + hi(x3);
|
||||
|
||||
return { result, carry };
|
||||
return { uint64_t(lo(x3) << 32 | lo(x1)), uint64_t(hi(a) * hi(b) + hi(x2) + hi(x3)) };
|
||||
}
|
||||
|
||||
// returns true if (and only if) a * b == c * d
|
||||
@@ -727,14 +740,50 @@ namespace Clipper2Lib {
|
||||
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_ab = Multiply(abs_a, abs_b);
|
||||
const auto abs_cd = Multiply(abs_c, abs_d);
|
||||
const auto ab = MultiplyUInt64(abs_a, abs_b);
|
||||
const auto cd = MultiplyUInt64(abs_c, abs_d);
|
||||
|
||||
// nb: it's important to differentiate 0 values here from other values
|
||||
const auto sign_ab = TriSign(a) * TriSign(b);
|
||||
const auto sign_cd = TriSign(c) * TriSign(d);
|
||||
|
||||
return abs_ab == abs_cd && sign_ab == sign_cd;
|
||||
return ab == 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
|
||||
}
|
||||
|
||||
@@ -838,6 +887,10 @@ namespace Clipper2Lib {
|
||||
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
|
||||
// caution: this will compromise performance
|
||||
// https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
|
||||
@@ -845,7 +898,7 @@ namespace Clipper2Lib {
|
||||
#define CC_MIN(x,y) ((x)>(y)?(y):(x))
|
||||
#define CC_MAX(x,y) ((x)<(y)?(y):(x))
|
||||
template<typename T>
|
||||
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||
{
|
||||
double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
|
||||
@@ -891,11 +944,14 @@ namespace Clipper2Lib {
|
||||
ip.x = originx + static_cast<T>(hitx);
|
||||
ip.y = originy + static_cast<T>(hity);
|
||||
}
|
||||
#ifdef USINGZ
|
||||
ip.z = 0;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
||||
@@ -913,7 +969,10 @@ namespace Clipper2Lib {
|
||||
{
|
||||
ip.x = static_cast<T>(ln1a.x + t * dx1);
|
||||
ip.y = static_cast<T>(ln1a.y + t * dy1);
|
||||
}
|
||||
#ifdef USINGZ
|
||||
ip.z = 0;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -940,30 +999,53 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline int GetSign(const T& val)
|
||||
{
|
||||
if (!val) return 0;
|
||||
inline int GetSign(const T& val)
|
||||
{
|
||||
if (!val) return 0;
|
||||
return (val > 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
|
||||
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)
|
||||
{
|
||||
double res1 = CrossProduct(seg1a, seg2a, seg2b);
|
||||
double res2 = CrossProduct(seg1b, seg2a, seg2b);
|
||||
if (res1 * res2 > 0) return false;
|
||||
double res3 = CrossProduct(seg2a, seg1a, seg1b);
|
||||
double res4 = CrossProduct(seg2b, seg1a, seg1b);
|
||||
if (res3 * res4 > 0) return false;
|
||||
return (res1 || res2 || res3 || res4); // ensures not collinear
|
||||
//result **includes** segments that touch at an end point
|
||||
double t = ((seg1a.x - seg2a.x) * dy2 - (seg1a.y - seg2a.y) * dx2);
|
||||
if (t == 0) return true;
|
||||
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 true;
|
||||
if (t > 0) return (cp > 0 && t <= cp);
|
||||
else return (cp < 0 && t >= cp); // true when t less neg. than cp
|
||||
}
|
||||
else {
|
||||
return (GetSign(CrossProduct(seg1a, seg2a, seg2b)) *
|
||||
GetSign(CrossProduct(seg1b, seg2a, seg2b)) < 0) &&
|
||||
(GetSign(CrossProduct(seg2a, seg1a, seg1b)) *
|
||||
GetSign(CrossProduct(seg2b, seg1a, seg1b)) < 0);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1051,7 +1133,7 @@ namespace Clipper2Lib {
|
||||
val = 1 - val; // toggle val
|
||||
else
|
||||
{
|
||||
double d = CrossProduct(*prev, *curr, pt);
|
||||
int d = CrossProductSign(*prev, *curr, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
@@ -1065,7 +1147,7 @@ namespace Clipper2Lib {
|
||||
if (curr == cend) curr = cbegin;
|
||||
if (curr == cbegin) prev = cend - 1;
|
||||
else prev = curr - 1;
|
||||
double d = CrossProduct(*prev, *curr, pt);
|
||||
int d = CrossProductSign(*prev, *curr, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
#include <functional>
|
||||
#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
|
||||
namespace Clipper2Lib_Z {
|
||||
#else
|
||||
@@ -50,6 +57,7 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
Point64 pt;
|
||||
Vertex* next = nullptr;
|
||||
Vertex* prev = nullptr;
|
||||
@@ -57,6 +65,7 @@ namespace Clipper2Lib {
|
||||
};
|
||||
|
||||
struct OutPt {
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
Point64 pt;
|
||||
OutPt* next = nullptr;
|
||||
OutPt* prev = nullptr;
|
||||
@@ -81,6 +90,7 @@ namespace Clipper2Lib {
|
||||
//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.
|
||||
struct OutRec {
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
size_t idx = 0;
|
||||
OutRec* owner = nullptr;
|
||||
Active* front_edge = nullptr;
|
||||
@@ -106,6 +116,7 @@ namespace Clipper2Lib {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Active {
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
Point64 bot;
|
||||
Point64 top;
|
||||
int64_t curr_x = 0; //current (updated at every new scanline)
|
||||
@@ -133,6 +144,7 @@ namespace Clipper2Lib {
|
||||
};
|
||||
|
||||
struct LocalMinima {
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
Vertex* vertex;
|
||||
PathType polytype;
|
||||
bool is_open;
|
||||
@@ -303,6 +315,7 @@ namespace Clipper2Lib {
|
||||
protected:
|
||||
PolyPath* parent_;
|
||||
public:
|
||||
CLIPPER2_NODE_ALLOCATOR
|
||||
PolyPath(PolyPath* parent = nullptr): parent_(parent){}
|
||||
virtual ~PolyPath() {};
|
||||
//https://en.cppreference.com/w/cpp/language/rule_of_three
|
||||
@@ -330,15 +343,16 @@ namespace Clipper2Lib {
|
||||
//Even levels except level 0
|
||||
return lvl && !(lvl & 1);
|
||||
}
|
||||
template<typename T>
|
||||
static double Clipper2LibArea(const Path<T> &poly)
|
||||
{
|
||||
// Area() of the namespace this header is compiled into (Clipper2Lib or Clipper2Lib_Z).
|
||||
template<typename T>
|
||||
static double Clipper2LibArea(const Path<T> &poly)
|
||||
{
|
||||
#ifdef USINGZ
|
||||
return Clipper2Lib_Z::Area<T>(poly);
|
||||
return Clipper2Lib_Z::Area<T>(poly);
|
||||
#else
|
||||
return Clipper2Lib::Area<T>(poly);
|
||||
return Clipper2Lib::Area<T>(poly);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename std::vector<std::unique_ptr<PolyPath64>> PolyPath64List;
|
||||
@@ -388,7 +402,8 @@ namespace Clipper2Lib {
|
||||
|
||||
double Area() const
|
||||
{
|
||||
return std::accumulate(childs_.cbegin(), childs_.cend(), Clipper2LibArea<int64_t>(polygon_),
|
||||
return std::accumulate(childs_.cbegin(), childs_.cend(),
|
||||
Clipper2LibArea<int64_t>(polygon_),
|
||||
[](double a, const auto& child) {return a + child->Area(); });
|
||||
}
|
||||
|
||||
@@ -462,7 +477,8 @@ namespace Clipper2Lib {
|
||||
|
||||
double Area() const
|
||||
{
|
||||
return std::accumulate(childs_.begin(), childs_.end(), Clipper2LibArea<double>(polygon_),
|
||||
return std::accumulate(childs_.begin(), childs_.end(),
|
||||
Clipper2LibArea<double>(polygon_),
|
||||
[](double a, const auto& child) {return a + child->Area(); });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,17 +19,17 @@
|
||||
|
||||
The path structures used extensively in other parts of this library are all
|
||||
based on std::vector classes. Since C++ classes can't be accessed by other
|
||||
languages, these paths are exported here as very simple array structures
|
||||
(either of int64_t or double) that can be parsed by just about any
|
||||
languages, these paths are exported here as very simple array structures
|
||||
(either of int64_t or double) that can be parsed by just about any
|
||||
programming language.
|
||||
|
||||
These 2D paths are defined by series of x and y coordinates together with an
|
||||
optional user-defined 'z' value (see Z-values below). Hence, a vertex refers
|
||||
to a single x and y coordinate (+/- a user-defined value). Data structures
|
||||
have names with suffixes that indicate the array type (either int64_t or
|
||||
double). For example, the data structure CPath64 contains an array of int64_t
|
||||
values, whereas the data structure CPathD contains an array of double.
|
||||
Where documentation omits the type suffix (eg CPath), it is referring to an
|
||||
to a single x and y coordinate (+/- a user-defined value). Data structures
|
||||
have names with suffixes that indicate the array type (either int64_t or
|
||||
double). For example, the data structure CPath64 contains an array of int64_t
|
||||
values, whereas the data structure CPathD contains an array of double.
|
||||
Where documentation omits the type suffix (eg CPath), it is referring to an
|
||||
array whose data type could be either int64_t or double.
|
||||
|
||||
For conciseness, the following letters are used in the diagrams below:
|
||||
@@ -39,10 +39,10 @@ A: Number of elements in an array
|
||||
|
||||
|
||||
CPath64 and CPathD:
|
||||
These are arrays of either int64_t or double values. Apart from
|
||||
the first two elements, these arrays are a series of vertices
|
||||
that together define a path. The very first element contains the
|
||||
number of vertices (N) in the path, while second element should
|
||||
These are arrays of either int64_t or double values. Apart from
|
||||
the first two elements, these arrays are a series of vertices
|
||||
that together define a path. The very first element contains the
|
||||
number of vertices (N) in the path, while second element should
|
||||
contain a 0 value.
|
||||
_______________________________________________________________
|
||||
| counters | vertex1 | vertex2 | ... | vertexN |
|
||||
@@ -52,9 +52,9 @@ _______________________________________________________________
|
||||
|
||||
CPaths64 and CPathsD:
|
||||
These are also arrays of either int64_t or double values that
|
||||
contain any number of consecutive CPath structures. However,
|
||||
contain any number of consecutive CPath structures. However,
|
||||
preceding the first path is a pair of values. The first value
|
||||
contains the length of the entire array structure (A), and the
|
||||
contains the length of the entire array structure (A), and the
|
||||
second contains the number (ie count) of contained paths (C).
|
||||
Memory allocation for CPaths64 = A * sizeof(int64_t)
|
||||
Memory allocation for CPathsD = A * sizeof(double)
|
||||
@@ -65,12 +65,12 @@ __________________________________________
|
||||
|
||||
|
||||
CPolytree64 and CPolytreeD:
|
||||
The entire polytree structure is an array of int64_t or double. The
|
||||
first element in the array indicates the array's total length (A).
|
||||
The second element indicates the number (C) of CPolyPath structures
|
||||
The entire polytree structure is an array of int64_t or double. The
|
||||
first element in the array indicates the array's total length (A).
|
||||
The second element indicates the number (C) of CPolyPath structures
|
||||
that are the TOP LEVEL CPolyPath in the polytree, and these top
|
||||
level CPolyPath immediately follow these first two array elements.
|
||||
These top level CPolyPath structures may, in turn, contain nested
|
||||
level CPolyPath immediately follow these first two array elements.
|
||||
These top level CPolyPath structures may, in turn, contain nested
|
||||
CPolyPath children, and these collectively make a tree structure.
|
||||
_________________________________________________________
|
||||
| counters | CPolyPath1 | CPolyPath2 | ... | CPolyPathC |
|
||||
@@ -116,13 +116,10 @@ the four vertices that define the two segments that are intersecting.
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.offset.h"
|
||||
#include "clipper2/clipper.rectclip.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef USINGZ
|
||||
namespace Clipper2Lib_Z {
|
||||
#else
|
||||
namespace Clipper2Lib {
|
||||
#endif
|
||||
|
||||
typedef int64_t* CPath64;
|
||||
typedef int64_t* CPaths64;
|
||||
@@ -254,9 +251,9 @@ ZCallback64 dllCallback64 = nullptr;
|
||||
ZCallbackD dllCallbackD = nullptr;
|
||||
|
||||
constexpr int EXPORT_VERTEX_DIMENSIONALITY = 3;
|
||||
#else
|
||||
#else
|
||||
constexpr int EXPORT_VERTEX_DIMENSIONALITY = 2;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
static void GetPathCountAndCPathsArrayLen(const Paths<T>& paths,
|
||||
@@ -396,7 +393,7 @@ static Path<T> ConvertCPathToPathT(T* path)
|
||||
#ifdef USINGZ
|
||||
z_type z = Reinterpret<z_type>(*v++);
|
||||
result.emplace_back(x, y, z);
|
||||
#else
|
||||
#else
|
||||
result.emplace_back(x, y);
|
||||
#endif
|
||||
}
|
||||
@@ -414,7 +411,7 @@ static Paths<T> ConvertCPathsToPathsT(T* paths)
|
||||
for (size_t i = 0; i < cnt; ++i)
|
||||
{
|
||||
size_t cnt2 = static_cast<size_t>(*v);
|
||||
v += 2;
|
||||
v += 2;
|
||||
Path<T> path;
|
||||
path.reserve(cnt2);
|
||||
for (size_t j = 0; j < cnt2; ++j)
|
||||
@@ -447,7 +444,7 @@ static Path64 ConvertCPathDToPath64WithScale(const CPathD path, double scale)
|
||||
#ifdef USINGZ
|
||||
z_type z = Reinterpret<z_type>(*v++);
|
||||
result.emplace_back(x, y, z);
|
||||
#else
|
||||
#else
|
||||
result.emplace_back(x, y);
|
||||
#endif
|
||||
}
|
||||
@@ -492,7 +489,7 @@ static void CreateCPolyPath64(const PolyPath64* pp, int64_t*& v)
|
||||
{
|
||||
*v++ = pt.x;
|
||||
*v++ = pt.y;
|
||||
#ifdef USINGZ
|
||||
#ifdef USINGZ
|
||||
* v++ = Reinterpret<int64_t>(pt.z); // raw memory copy
|
||||
#endif
|
||||
}
|
||||
@@ -508,7 +505,7 @@ static void CreateCPolyPathD(const PolyPathD* pp, double*& v)
|
||||
{
|
||||
*v++ = pt.x;
|
||||
*v++ = pt.y;
|
||||
#ifdef USINGZ
|
||||
#ifdef USINGZ
|
||||
* v++ = Reinterpret<double>(pt.z); // raw memory copy
|
||||
#endif
|
||||
}
|
||||
@@ -816,6 +813,24 @@ EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath6
|
||||
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
|
||||
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);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 27 April 2024 *
|
||||
* Date : 5 March 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : This module provides a simple interface to the Clipper Library *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -13,14 +13,15 @@
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.offset.h"
|
||||
#include "clipper2/clipper.minkowski.h"
|
||||
#include "clipper2/clipper.rectclip.h"
|
||||
#include "clipper2/clipper.minkowski.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef USINGZ
|
||||
namespace Clipper2Lib_Z {
|
||||
namespace Clipper2Lib_Z {
|
||||
#else
|
||||
namespace Clipper2Lib {
|
||||
namespace Clipper2Lib {
|
||||
#endif
|
||||
|
||||
inline Paths64 BooleanOp(ClipType cliptype, FillRule fillrule,
|
||||
@@ -154,14 +155,14 @@
|
||||
if (!delta) return paths;
|
||||
if (error_code) return PathsD();
|
||||
const double scale = std::pow(10, precision);
|
||||
ClipperOffset clip_offset(miter_limit, arc_tolerance);
|
||||
ClipperOffset clip_offset(miter_limit, arc_tolerance * scale);
|
||||
clip_offset.AddPaths(ScalePaths<int64_t,double>(paths, scale, error_code), jt, et);
|
||||
if (error_code) return PathsD();
|
||||
Paths64 solution;
|
||||
clip_offset.Execute(delta * scale, solution);
|
||||
return ScalePaths<double, int64_t>(solution, 1 / scale, error_code);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline Path<T> TranslatePath(const Path<T>& path, T dx, T dy)
|
||||
{
|
||||
@@ -355,6 +356,29 @@
|
||||
#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
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
|
||||
@@ -615,29 +639,6 @@
|
||||
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>
|
||||
inline Path<T> SimplifyPath(const Path<T> &path,
|
||||
double epsilon, bool isClosedPath = true)
|
||||
@@ -669,13 +670,13 @@
|
||||
start = curr;
|
||||
do
|
||||
{
|
||||
curr = GetNext(curr, high, flags);
|
||||
curr = details::GetNext(curr, high, flags);
|
||||
} while (curr != start && distSqr[curr] > epsSqr);
|
||||
if (curr == start) break;
|
||||
}
|
||||
|
||||
prior = GetPrior(curr, high, flags);
|
||||
next = GetNext(curr, high, flags);
|
||||
prior = details::GetPrior(curr, high, flags);
|
||||
next = details::GetNext(curr, high, flags);
|
||||
if (next == prior) break;
|
||||
|
||||
// flag for removal the smaller of adjacent 'distances'
|
||||
@@ -684,14 +685,14 @@
|
||||
prior2 = prior;
|
||||
prior = curr;
|
||||
curr = next;
|
||||
next = GetNext(next, high, flags);
|
||||
next = details::GetNext(next, high, flags);
|
||||
}
|
||||
else
|
||||
prior2 = GetPrior(prior, high, flags);
|
||||
prior2 = details::GetPrior(prior, high, flags);
|
||||
|
||||
flags[curr] = true;
|
||||
curr = next;
|
||||
next = GetNext(next, high, flags);
|
||||
next = details::GetNext(next, high, flags);
|
||||
|
||||
if (isClosedPath || ((curr != high) && (curr != 0)))
|
||||
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
|
||||
@@ -716,6 +717,35 @@
|
||||
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>
|
||||
inline void RDP(const Path<T> path, std::size_t begin,
|
||||
std::size_t end, double epsSqrd, std::vector<bool>& flags)
|
||||
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
class Group {
|
||||
public:
|
||||
Paths64 paths_in;
|
||||
std::optional<size_t> lowest_path_idx{};
|
||||
std::optional<size_t> lowest_path_idx{};
|
||||
bool is_reversed = false;
|
||||
JoinType join_type;
|
||||
EndType end_type;
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
void AddPath(const Path64& path, JoinType jt_, EndType et_);
|
||||
void AddPaths(const Paths64& paths, JoinType jt_, EndType et_);
|
||||
void Clear() { groups_.clear(); norms.clear(); };
|
||||
|
||||
|
||||
void Execute(double delta, Paths64& sols_64);
|
||||
void Execute(double delta, PolyTree64& polytree);
|
||||
void Execute(DeltaCallback64 delta_cb, Paths64& paths);
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
|
||||
bool PreserveCollinear() const { return preserve_collinear_; }
|
||||
void PreserveCollinear(bool preserve_collinear){preserve_collinear_ = preserve_collinear;}
|
||||
|
||||
|
||||
bool ReverseSolution() const { return reverse_solution_; }
|
||||
void ReverseSolution(bool reverse_solution) {reverse_solution_ = reverse_solution;}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* 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
|
||||
#define CLIPPER_VERSION_H
|
||||
|
||||
constexpr auto CLIPPER2_VERSION = "1.5.2";
|
||||
constexpr auto CLIPPER2_VERSION = "2.0.1";
|
||||
|
||||
#endif // CLIPPER_VERSION_H
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 17 September 2024 *
|
||||
* Date : 5 November 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : This is the main polygon clipping module *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.h"
|
||||
#include <stdexcept>
|
||||
#include <new>
|
||||
#include <oneapi/tbb/scalable_allocator.h>
|
||||
|
||||
// https://github.com/AngusJohnson/Clipper2/discussions/334
|
||||
// #discussioncomment-4248602
|
||||
@@ -27,10 +29,30 @@ namespace Clipper2Lib_Z {
|
||||
namespace Clipper2Lib {
|
||||
#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);
|
||||
|
||||
// Every closed path (ie polygon) is made up of a series of vertices forming edge
|
||||
// 'bounds' that alternate between ascending bounds (containing edges going up
|
||||
// Every closed path (ie polygon) is made up of a series of vertices forming edge
|
||||
// 'bounds' that alternate between ascending bounds (containing edges going up
|
||||
// relative to the Y-axis) and descending bounds. 'Local Minima' refers to
|
||||
// vertices where ascending and descending bounds join at the bottom, and
|
||||
// 'Local Maxima' are where ascending and descending bounds join at the top.
|
||||
@@ -482,8 +504,7 @@ namespace Clipper2Lib {
|
||||
inline void SetOwner(OutRec* outrec, OutRec* new_owner)
|
||||
{
|
||||
//precondition1: new_owner is never null
|
||||
while (new_owner->owner && !new_owner->owner->pts)
|
||||
new_owner->owner = new_owner->owner->owner;
|
||||
new_owner->owner = GetRealOutRec(new_owner->owner);
|
||||
OutRec* tmp = new_owner;
|
||||
while (tmp && tmp != outrec) tmp = tmp->owner;
|
||||
if (tmp) new_owner->owner = outrec->owner;
|
||||
@@ -536,9 +557,9 @@ namespace Clipper2Lib {
|
||||
val = 1 - val; // toggle val
|
||||
else
|
||||
{
|
||||
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
||||
if (i == 0) return PointInPolygonResult::IsOn;
|
||||
if ((i < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
is_above = !is_above;
|
||||
op2 = op2->next;
|
||||
@@ -546,9 +567,9 @@ namespace Clipper2Lib {
|
||||
|
||||
if (is_above != starting_above)
|
||||
{
|
||||
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
||||
if (i == 0) return PointInPolygonResult::IsOn;
|
||||
if ((i < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
|
||||
if (val == 0) return PointInPolygonResult::IsOutside;
|
||||
@@ -578,30 +599,31 @@ namespace Clipper2Lib {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool Path1InsidePath2(OutPt* op1, OutPt* op2)
|
||||
inline bool Path2ContainsPath1(OutPt* op1, OutPt* op2)
|
||||
{
|
||||
// we need to make some accommodation for rounding errors
|
||||
// so we won't jump if the first vertex is found outside
|
||||
PointInPolygonResult result;
|
||||
int outside_cnt = 0;
|
||||
// this function accommodates rounding errors that
|
||||
// can cause path micro intersections
|
||||
PointInPolygonResult pip = PointInPolygonResult::IsOn;
|
||||
OutPt* op = op1;
|
||||
do
|
||||
{
|
||||
result = PointInOpPolygon(op->pt, op2);
|
||||
if (result == PointInPolygonResult::IsOutside) ++outside_cnt;
|
||||
else if (result == PointInPolygonResult::IsInside) --outside_cnt;
|
||||
do {
|
||||
switch (PointInOpPolygon(op->pt, op2))
|
||||
{
|
||||
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;
|
||||
}
|
||||
op = op->next;
|
||||
} while (op != op1 && std::abs(outside_cnt) < 2);
|
||||
if (std::abs(outside_cnt) > 1) return (outside_cnt < 0);
|
||||
// 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;
|
||||
} while (op != op1);
|
||||
// result unclear, so try again using cleaned paths
|
||||
return Path2ContainsPath1(GetCleanPath(op1), GetCleanPath(op2)); // (#973)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void AddLocMin(LocalMinimaList& list,
|
||||
Vertex& vert, PathType polytype, bool is_open)
|
||||
{
|
||||
@@ -1126,21 +1148,19 @@ namespace Clipper2Lib {
|
||||
return newcomer.curr_x > resident.curr_x;
|
||||
|
||||
//get the turning direction a1.top, a2.bot, a2.top
|
||||
double d = CrossProduct(resident.top, newcomer.bot, newcomer.top);
|
||||
if (d != 0) return d < 0;
|
||||
int i = CrossProductSign(resident.top, newcomer.bot, newcomer.top);
|
||||
if (i != 0) return i < 0;
|
||||
|
||||
//edges must be collinear to get here
|
||||
//for starting open paths, place them according to
|
||||
//the direction they're about to turn
|
||||
if (!IsMaxima(resident) && (resident.top.y > newcomer.top.y))
|
||||
{
|
||||
return CrossProduct(newcomer.bot,
|
||||
resident.top, NextVertex(resident)->pt) <= 0;
|
||||
return (CrossProductSign(newcomer.bot, resident.top, NextVertex(resident)->pt) <= 0);
|
||||
}
|
||||
else if (!IsMaxima(newcomer) && (newcomer.top.y > resident.top.y))
|
||||
{
|
||||
return CrossProduct(newcomer.bot,
|
||||
newcomer.top, NextVertex(newcomer)->pt) >= 0;
|
||||
return (CrossProductSign(newcomer.bot, newcomer.top, NextVertex(newcomer)->pt) >= 0);
|
||||
}
|
||||
|
||||
int64_t y = newcomer.bot.y;
|
||||
@@ -1155,7 +1175,7 @@ namespace Clipper2Lib {
|
||||
resident.bot, resident.top)) return true;
|
||||
else
|
||||
//compare turning direction of the alternate bound
|
||||
return (CrossProduct(PrevPrevVertex(resident)->pt,
|
||||
return (CrossProductSign(PrevPrevVertex(resident)->pt,
|
||||
newcomer.bot, PrevPrevVertex(newcomer)->pt) > 0) == newcomerIsLeft;
|
||||
}
|
||||
|
||||
@@ -1565,7 +1585,7 @@ namespace Clipper2Lib {
|
||||
FixSelfIntersects(outrec);
|
||||
}
|
||||
|
||||
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
|
||||
void ClipperBase::DoSplitOp (OutRec* outrec, OutPt* splitOp)
|
||||
{
|
||||
// splitOp.prev -> splitOp &&
|
||||
// splitOp.next -> splitOp.next.next are intersecting
|
||||
@@ -1574,7 +1594,7 @@ namespace Clipper2Lib {
|
||||
outrec->pts = prevOp;
|
||||
|
||||
Point64 ip;
|
||||
GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
|
||||
GetLineIntersectPt(prevOp->pt, splitOp->pt,
|
||||
splitOp->next->pt, nextNextOp->pt, ip);
|
||||
|
||||
#ifdef USINGZ
|
||||
@@ -1630,7 +1650,7 @@ namespace Clipper2Lib {
|
||||
|
||||
if (using_polytree_)
|
||||
{
|
||||
if (Path1InsidePath2(prevOp, newOp))
|
||||
if (Path2ContainsPath1(prevOp, newOp))
|
||||
{
|
||||
newOr->splits = new OutRecList();
|
||||
newOr->splits->emplace_back(outrec);
|
||||
@@ -1652,19 +1672,32 @@ namespace Clipper2Lib {
|
||||
void ClipperBase::FixSelfIntersects(OutRec* outrec)
|
||||
{
|
||||
OutPt* op2 = outrec->pts;
|
||||
if (op2->prev == op2->next->next)
|
||||
return; // because triangles can't self-intersect
|
||||
for (; ; )
|
||||
{
|
||||
// triangles can't self-intersect
|
||||
if (op2->prev == op2->next->next) break;
|
||||
if (SegmentsIntersect(op2->prev->pt,
|
||||
op2->pt, op2->next->pt, op2->next->next->pt))
|
||||
{
|
||||
if (op2 == outrec->pts || op2->next == outrec->pts)
|
||||
outrec->pts = outrec->pts->prev;
|
||||
DoSplitOp(outrec, op2);
|
||||
if (!outrec->pts) break;
|
||||
op2 = outrec->pts;
|
||||
continue;
|
||||
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)
|
||||
outrec->pts = outrec->pts->prev;
|
||||
DoSplitOp(outrec, op2);
|
||||
if (!outrec->pts) break;
|
||||
op2 = outrec->pts;
|
||||
if (op2->prev == op2->next->next)
|
||||
break; // again, because triangles can't self-intersect
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
op2 = op2->next;
|
||||
@@ -1805,14 +1838,14 @@ namespace Clipper2Lib {
|
||||
|
||||
switch (fillrule_)
|
||||
{
|
||||
case FillRule::Positive:
|
||||
if (edge_c->wind_cnt != 1) return;
|
||||
case FillRule::Positive:
|
||||
if (edge_c->wind_cnt != 1) return;
|
||||
break;
|
||||
case FillRule::Negative:
|
||||
if (edge_c->wind_cnt != -1) return;
|
||||
case FillRule::Negative:
|
||||
if (edge_c->wind_cnt != -1) return;
|
||||
break;
|
||||
default:
|
||||
if (std::abs(edge_c->wind_cnt) != 1) return;
|
||||
default:
|
||||
if (std::abs(edge_c->wind_cnt) != 1) return;
|
||||
}
|
||||
|
||||
#ifdef USINGZ
|
||||
@@ -1933,7 +1966,7 @@ namespace Clipper2Lib {
|
||||
const bool e1_windcnt_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
|
||||
const bool e2_windcnt_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
|
||||
|
||||
if ((!IsHotEdge(e1) && !e1_windcnt_in_01) ||
|
||||
if ((!IsHotEdge(e1) && !e1_windcnt_in_01) ||
|
||||
(!IsHotEdge(e2) && !e2_windcnt_in_01))
|
||||
return;
|
||||
|
||||
@@ -2112,10 +2145,9 @@ namespace Clipper2Lib {
|
||||
e->prev_in_sel = e->prev_in_ael;
|
||||
e->next_in_sel = e->next_in_ael;
|
||||
e->jump = e->next_in_sel;
|
||||
if (e->join_with == JoinWith::Left)
|
||||
e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
|
||||
else
|
||||
e->curr_x = TopX(*e, top_y);
|
||||
// it is safe to ignore 'joined' edges here because
|
||||
// if necessary they will be split in IntersectEdges()
|
||||
e->curr_x = TopX(*e, top_y);
|
||||
e = e->next_in_ael;
|
||||
}
|
||||
}
|
||||
@@ -2262,15 +2294,14 @@ namespace Clipper2Lib {
|
||||
|
||||
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
||||
{
|
||||
if (!fromOr->splits) return;
|
||||
if (!toOr->splits) toOr->splits = new OutRecList();
|
||||
OutRecList::iterator orIter = fromOr->splits->begin();
|
||||
for (; orIter != fromOr->splits->end(); ++orIter)
|
||||
toOr->splits->emplace_back(*orIter);
|
||||
if (toOr != *orIter) // #987
|
||||
toOr->splits->emplace_back(*orIter);
|
||||
fromOr->splits->clear();
|
||||
}
|
||||
|
||||
|
||||
void ClipperBase::ProcessHorzJoins()
|
||||
{
|
||||
for (const HorzJoin& j : horz_join_list_)
|
||||
@@ -2299,8 +2330,8 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
if (using_polytree_) //#498, #520, #584, D#576, #618
|
||||
{
|
||||
if (Path1InsidePath2(or1->pts, or2->pts))
|
||||
{
|
||||
if (Path2ContainsPath1(or1->pts, or2->pts))
|
||||
{
|
||||
//swap or1's & or2's pts
|
||||
OutPt* tmp = or1->pts;
|
||||
@@ -2311,7 +2342,7 @@ namespace Clipper2Lib {
|
||||
//or2 is now inside or1
|
||||
or2->owner = or1;
|
||||
}
|
||||
else if (Path1InsidePath2(or2->pts, or1->pts))
|
||||
else if (Path2ContainsPath1(or2->pts, or1->pts))
|
||||
{
|
||||
or2->owner = or1;
|
||||
}
|
||||
@@ -2324,13 +2355,14 @@ namespace Clipper2Lib {
|
||||
else
|
||||
or2->owner = or1;
|
||||
}
|
||||
else
|
||||
else // joining, not splitting
|
||||
{
|
||||
or2->pts = nullptr;
|
||||
if (using_polytree_)
|
||||
{
|
||||
SetOwner(or2, or1);
|
||||
MoveSplits(or2, or1); //#618
|
||||
if (or2->splits)
|
||||
MoveSplits(or2, or1); //#618
|
||||
}
|
||||
else
|
||||
or2->owner = or1;
|
||||
@@ -2350,7 +2382,7 @@ namespace Clipper2Lib {
|
||||
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
||||
{
|
||||
Point64 ip;
|
||||
if (!GetSegmentIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
||||
if (!GetLineIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
||||
ip = Point64(e1.curr_x, top_y); //parallel edges
|
||||
|
||||
//rounding errors can occasionally place the calculated intersection
|
||||
@@ -2934,22 +2966,28 @@ namespace Clipper2Lib {
|
||||
|
||||
bool ClipperBase::CheckSplitOwner(OutRec* outrec, OutRecList* splits)
|
||||
{
|
||||
for (auto split : *splits)
|
||||
// nb: use indexing (not an iterator) in case 'splits' is modified inside this loop (#1029)
|
||||
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);
|
||||
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
|
||||
|
||||
if (split->splits && CheckSplitOwner(outrec, split->splits))
|
||||
return true;
|
||||
else if (CheckBounds(split) &&
|
||||
IsValidOwner(outrec, split) &&
|
||||
split->bounds.Contains(outrec->bounds) &&
|
||||
Path1InsidePath2(outrec->pts, split->pts))
|
||||
{
|
||||
outrec->owner = split; //found in split
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!CheckBounds(split) || !split->bounds.Contains(outrec->bounds) ||
|
||||
!Path2ContainsPath1(outrec->pts, split->pts)) continue;
|
||||
|
||||
if (!IsValidOwner(outrec, split)) // split is owned by outrec! (#957)
|
||||
split->owner = outrec->owner;
|
||||
|
||||
outrec->owner = split;
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2960,13 +2998,12 @@ namespace Clipper2Lib {
|
||||
// post-condition: if a valid path, outrec will have a polypath
|
||||
|
||||
if (outrec->polypath || outrec->bounds.IsEmpty()) return;
|
||||
|
||||
while (outrec->owner)
|
||||
{
|
||||
if (outrec->owner->splits && CheckSplitOwner(outrec, outrec->owner->splits)) break;
|
||||
if (outrec->owner->pts && CheckBounds(outrec->owner) &&
|
||||
outrec->owner->bounds.Contains(outrec->bounds) &&
|
||||
Path1InsidePath2(outrec->pts, outrec->owner->pts)) break;
|
||||
Path2ContainsPath1(outrec->pts, outrec->owner->pts)) break;
|
||||
outrec->owner = outrec->owner->owner;
|
||||
}
|
||||
|
||||
@@ -3029,6 +3066,7 @@ namespace Clipper2Lib {
|
||||
{
|
||||
OutRec* outrec = outrec_list_[i];
|
||||
if (!outrec || !outrec->pts) continue;
|
||||
|
||||
if (outrec->is_open)
|
||||
{
|
||||
Path64 path;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 22 January 2025 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Path Offset (Inflate/Shrink) *
|
||||
@@ -37,29 +37,35 @@ const double arc_const = 0.002; // <-- 1/500
|
||||
// Miscellaneous methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::optional<size_t> GetLowestClosedPathIdx(const Paths64& paths)
|
||||
void GetLowestClosedPathInfo(const Paths64& paths, std::optional<size_t>& idx, bool& is_neg_area)
|
||||
{
|
||||
std::optional<size_t> result;
|
||||
idx.reset();
|
||||
Point64 botPt = Point64(INT64_MAX, INT64_MIN);
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
double a = MAX_DBL;
|
||||
for (const Point64& pt : paths[i])
|
||||
{
|
||||
if ((pt.y < botPt.y) ||
|
||||
((pt.y == botPt.y) && (pt.x >= botPt.x))) continue;
|
||||
result = i;
|
||||
if (a == MAX_DBL)
|
||||
{
|
||||
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.y = pt.y;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double Hypot(double x, double y)
|
||||
{
|
||||
// given that this is an internal function, and given the x and y parameters
|
||||
// will always be coordinate values (or the difference between coordinate values),
|
||||
// x and y should always be within INT64_MIN to INT64_MAX. Consequently,
|
||||
// x and y should always be within INT64_MIN to INT64_MAX. Consequently,
|
||||
// there should be no risk that the following computation will overflow
|
||||
// see https://stackoverflow.com/a/32436148/359538
|
||||
return std::sqrt(x * x + y * y);
|
||||
@@ -145,15 +151,16 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
|
||||
|
||||
if (end_type == EndType::Polygon)
|
||||
{
|
||||
lowest_path_idx = GetLowestClosedPathIdx(paths_in);
|
||||
bool is_neg_area;
|
||||
GetLowestClosedPathInfo(paths_in, lowest_path_idx, is_neg_area);
|
||||
// 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.)
|
||||
// as this is much more efficient than reversing every path.
|
||||
is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
|
||||
is_reversed = lowest_path_idx.has_value() && is_neg_area;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowest_path_idx = std::nullopt;
|
||||
lowest_path_idx.reset();
|
||||
is_reversed = false;
|
||||
}
|
||||
}
|
||||
@@ -236,7 +243,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 pt = ptQ;
|
||||
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
//get the second intersect point through reflecion
|
||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||
path_out.emplace_back(pt);
|
||||
@@ -245,7 +252,7 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
|
||||
{
|
||||
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
|
||||
PointD pt = ptQ;
|
||||
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
path_out.emplace_back(pt);
|
||||
//get the second intersect point through reflecion
|
||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||
@@ -291,7 +298,8 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle
|
||||
#else
|
||||
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y);
|
||||
#endif
|
||||
int steps = static_cast<int>(std::ceil(steps_per_rad_ * std::abs(angle))); // #448, #456
|
||||
// Orca: round the step count like Clipper1 did, so round offsets keep their vertices.
|
||||
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
|
||||
{
|
||||
offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y,
|
||||
@@ -333,9 +341,9 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
|
||||
if (cos_a > -0.999 && (sin_a * group_delta_ < 0)) // test for concavity first (#593)
|
||||
{
|
||||
// is concave
|
||||
// by far the simplest way to construct concave joins, especially those joining very
|
||||
// short segments, is to insert 3 points that produce negative regions. These regions
|
||||
// will be removed later by the finishing union operation. This is also the best way
|
||||
// by far the simplest way to construct concave joins, especially those joining very
|
||||
// short segments, is to insert 3 points that produce negative regions. These regions
|
||||
// will be removed later by the finishing union operation. This is also the best way
|
||||
// to ensure that path reversals (ie over-shrunk paths) are removed.
|
||||
#ifdef USINGZ
|
||||
path_out.emplace_back(GetPerpendic(path[j], norms[k], group_delta_), path[j].z);
|
||||
@@ -366,11 +374,31 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
|
||||
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)
|
||||
{
|
||||
path_out.clear();
|
||||
for (Path64::size_type j = 0, k = path.size() - 1; j < path.size(); k = j, ++j)
|
||||
OffsetPoint(group, path, j, k);
|
||||
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);
|
||||
solution->emplace_back(path_out);
|
||||
}
|
||||
|
||||
@@ -380,7 +408,7 @@ void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path)
|
||||
Path64 reverse_path(path);
|
||||
std::reverse(reverse_path.begin(), reverse_path.end());
|
||||
|
||||
//rebuild normals
|
||||
//rebuild normals
|
||||
std::reverse(norms.begin(), norms.end());
|
||||
norms.emplace_back(norms[0]);
|
||||
norms.erase(norms.begin());
|
||||
@@ -601,10 +629,10 @@ void ClipperOffset::ExecuteInternal(double delta)
|
||||
|
||||
if (!solution->size()) return;
|
||||
|
||||
bool paths_reversed = CheckReverseOrientation();
|
||||
bool paths_reversed = CheckReverseOrientation();
|
||||
//clean up self-intersections ...
|
||||
Clipper64 c;
|
||||
c.PreserveCollinear(false);
|
||||
c.PreserveCollinear(preserve_collinear_);
|
||||
//the solution should retain the orientation of the input
|
||||
c.ReverseSolution(reverse_solution_ != paths_reversed);
|
||||
#ifdef USINGZ
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 5 July 2024 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : FAST rectangular clipping *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -77,8 +77,8 @@ namespace Clipper2Lib {
|
||||
bool GetSegmentIntersection(const Point64& p1,
|
||||
const Point64& p2, const Point64& p3, const Point64& p4, Point64& ip)
|
||||
{
|
||||
double res1 = CrossProduct(p1, p3, p4);
|
||||
double res2 = CrossProduct(p2, p3, p4);
|
||||
int res1 = CrossProductSign(p1, p3, p4);
|
||||
int res2 = CrossProductSign(p2, p3, p4);
|
||||
if (res1 == 0)
|
||||
{
|
||||
ip = p1;
|
||||
@@ -97,8 +97,8 @@ namespace Clipper2Lib {
|
||||
}
|
||||
if ((res1 > 0) == (res2 > 0)) return false;
|
||||
|
||||
double res3 = CrossProduct(p3, p1, p2);
|
||||
double res4 = CrossProduct(p4, p1, p2);
|
||||
int res3 = CrossProductSign(p3, p1, p2);
|
||||
int res4 = CrossProductSign(p4, p1, p2);
|
||||
if (res3 == 0)
|
||||
{
|
||||
ip = p3;
|
||||
@@ -116,7 +116,7 @@ namespace Clipper2Lib {
|
||||
if ((res3 > 0) == (res4 > 0)) return false;
|
||||
|
||||
// segments must intersect to get here
|
||||
return GetSegmentIntersectPt(p1, p2, p3, p4, ip);
|
||||
return GetLineIntersectPt(p1, p2, p3, p4, ip);
|
||||
}
|
||||
|
||||
inline bool GetIntersection(const Path64& rectPath,
|
||||
@@ -227,7 +227,7 @@ namespace Clipper2Lib {
|
||||
const Point64& prev_pt, const Point64& curr_pt, const Point64& rect_mp)
|
||||
{
|
||||
if (AreOpposites(prev, curr))
|
||||
return CrossProduct(prev_pt, rect_mp, curr_pt) < 0;
|
||||
return CrossProductSign(prev_pt, rect_mp, curr_pt) < 0;
|
||||
else
|
||||
return HeadingClockwise(prev, curr);
|
||||
}
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
#include "clipper.engine.cpp"
|
||||
#include "clipper.offset.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&)
|
||||
{
|
||||
#define DISABLE_BOOST_OFFSET
|
||||
auto res = Slic3r::offset_ex(sh, distance, Slic3r::ClipperLib::jtSquare);
|
||||
auto res = Slic3r::offset_ex(sh, distance, Slic3r::jtSquare);
|
||||
if (!res.empty()) sh = res.front();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void offset(Slic3r::Polygon& sh, coord_t distance, const PathTag&)
|
||||
{
|
||||
auto res = Slic3r::offset(sh, distance, Slic3r::ClipperLib::jtSquare);
|
||||
auto res = Slic3r::offset(sh, distance, Slic3r::jtSquare);
|
||||
if (!res.empty()) sh = res.front();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,7 @@ if(Qhull_FOUND)
|
||||
message(STATUS "Using qhull from system.")
|
||||
if(SLIC3R_STATIC)
|
||||
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)
|
||||
endif()
|
||||
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r)
|
||||
else()
|
||||
slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release)
|
||||
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# 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.
|
||||
|
||||
### 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`.
|
||||
@@ -0,0 +1,93 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,105 @@
|
||||
# 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,6 +180,7 @@ src/slic3r/GUI/PrivacyUpdateDialog.cpp
|
||||
src/slic3r/GUI/PublishDialog.cpp
|
||||
src/slic3r/GUI/PublishSettingsDialog.cpp
|
||||
src/slic3r/GUI/SavePresetDialog.cpp
|
||||
src/slic3r/GUI/SceneBenchmark.cpp
|
||||
src/slic3r/GUI/Search.cpp
|
||||
src/slic3r/GUI/SettingsIndex.cpp
|
||||
src/slic3r/GUI/SpeedDialDialog.cpp
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Snapmaker",
|
||||
"version": "02.04.00.16",
|
||||
"version": "02.04.00.17",
|
||||
"force_update": "0",
|
||||
"description": "Snapmaker configurations",
|
||||
"machine_model_list": [
|
||||
@@ -1448,6 +1448,10 @@
|
||||
"name": "Snapmaker PETG HF @U1 0.2 nozzle",
|
||||
"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",
|
||||
"sub_path": "filament/Snapmaker PETG HF @U1 0.6 nozzle.json"
|
||||
@@ -1920,6 +1924,122 @@
|
||||
"name": "Snapmaker Breakaway Support For PLA @U1 0.8 nozzle",
|
||||
"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",
|
||||
"sub_path": "filament/Polymaker/PolyTerra J1 PLA.json"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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,15 +10,18 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"enable_pressure_advance": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Polymaker"
|
||||
],
|
||||
"nozzle_temperature_range_high": [
|
||||
"230",
|
||||
"230"
|
||||
],
|
||||
"temperature_vitrification": [
|
||||
@@ -29,5 +32,21 @@
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"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,12 +16,15 @@
|
||||
"Polymaker"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"230",
|
||||
"230"
|
||||
],
|
||||
"nozzle_temperature_initial_layer": [
|
||||
"230",
|
||||
"230"
|
||||
],
|
||||
"nozzle_temperature_range_high": [
|
||||
"230",
|
||||
"230"
|
||||
],
|
||||
"textured_plate_temp": [
|
||||
@@ -29,5 +32,21 @@
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"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,6 +13,7 @@
|
||||
"1.23"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"0.96",
|
||||
"0.96"
|
||||
],
|
||||
"filament_vendor": [
|
||||
@@ -29,5 +30,21 @@
|
||||
],
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"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,9 +9,27 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"pressure_advance": [
|
||||
"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,18 +9,35 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"1.0",
|
||||
"1.0"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.0",
|
||||
"0.0"
|
||||
],
|
||||
"enable_pressure_advance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"pressure_advance": [
|
||||
"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,18 +9,35 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"1.0",
|
||||
"1.0"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.0",
|
||||
"0.0"
|
||||
],
|
||||
"enable_pressure_advance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"pressure_advance": [
|
||||
"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,16 +9,32 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"filament_retraction_length": [
|
||||
"1.0",
|
||||
"1.0"
|
||||
],
|
||||
"filament_z_hop": [
|
||||
"0.0",
|
||||
"0.0"
|
||||
],
|
||||
"description": " ",
|
||||
"enable_pressure_advance": [
|
||||
"1",
|
||||
"1"
|
||||
],
|
||||
"filament_extruder_variant": [
|
||||
"Direct Drive Standard",
|
||||
"Direct Drive High Flow"
|
||||
],
|
||||
"fan_min_speed": [
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"fan_max_speed": [
|
||||
"10",
|
||||
"10"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"supertack_plate_temp": [
|
||||
@@ -18,6 +19,19 @@
|
||||
"70"
|
||||
],
|
||||
"pressure_advance": [
|
||||
"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,7 +9,24 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,9 +10,27 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"filament_wipe": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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,18 +10,30 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"fan_max_speed": [
|
||||
"100",
|
||||
"100"
|
||||
],
|
||||
"fan_min_speed": [
|
||||
"100",
|
||||
"100"
|
||||
],
|
||||
"filament_flow_ratio": [
|
||||
"0.98",
|
||||
"0.98"
|
||||
],
|
||||
"filament_max_volumetric_speed": [
|
||||
"15",
|
||||
"15"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"4"
|
||||
],
|
||||
"filament_extruder_variant": [
|
||||
"Direct Drive Standard",
|
||||
"Direct Drive High Flow"
|
||||
],
|
||||
"additional_cooling_fan_speed": [
|
||||
"70",
|
||||
"70"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,6 +10,23 @@
|
||||
"Snapmaker U1 (0.4 nozzle)"
|
||||
],
|
||||
"filament_minimal_purge_on_wipe_tower": [
|
||||
"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"
|
||||
]
|
||||
}
|
||||
|
||||