diff --git a/.clang-tidy b/.clang-tidy index a670e9e1b1..3f0aaa8bde 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,9 +7,17 @@ CheckOptions: 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 + # GTK or pthread one), library internals and forward declarations (MSVC's STL + # __msvc_* and the Windows UCRT's corecrt_* included), CPython's headers behind + # Python.h (python3.x/ on Linux and macOS, libpython/include/ on Windows), + # curl's behind curl.h, oneTBB's behind tbb/, and # admesh's stl.h, which the include path also exposes without its directory. + # Clipper's own clipper.hpp is only included through libslic3r/clipper.hpp or + # clipper_z.hpp, which configure it first, and Boost.Polygon's headers only + # work through boost/polygon/polygon.hpp or voronoi.hpp. Clipper2's headers + # are included through clipper2/clipper.h, or clipper2_z.hpp, which defines + # USINGZ first. minilzo's config + # headers are internal to minilzo.h. # 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, @@ -23,7 +31,11 @@ CheckOptions: .*[/\\]impl[/\\].*; .*_fwd\.hpp; python3\.[0-9]+[/\\].*; + libpython[/\\]include[/\\].*; bits[/\\].*; + corecrt_.*\.h; + __msvc_.*\.hpp; + boost[/\\]multiprecision[/\\]fwd\.hpp; imconfig\.h; expat_external\.h; admesh[/\\]stl\.h; @@ -44,4 +56,10 @@ CheckOptions: fcntl\.h; termios\.h; [/\\](um|shared)[/\\].*; - sal\.h + sal\.h; + clipper[/\\]clipper\.hpp; + png(lib)?conf\.h; + mcut[/\\]platform\.h; + boost[/\\]polygon[/\\].*; + clipper2[/\\]clipper\.(core|engine|offset|minkowski|rectclip|export|triangulation|version)\.h; + lzo(conf|defs)\.h diff --git a/.claude/skills/orca-wxwidgets/SKILL.md b/.claude/skills/orca-wxwidgets/SKILL.md index 263d2e390f..0e39ce9d24 100644 --- a/.claude/skills/orca-wxwidgets/SKILL.md +++ b/.claude/skills/orca-wxwidgets/SKILL.md @@ -30,8 +30,9 @@ how you read the wx docs: Look things up in the source the app is built from — it beats memory, and 3.3 changed real behaviour: ```bash -WX=$(find deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets' | head -1) -# macOS: deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets Linux: deps/build/dep_wxWidgets-prefix/... +WX=$(find -L deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets' 2>/dev/null | head -1) +# macOS: deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets Linux, Windows: deps//dep_wxWidgets-prefix/... +# -L follows a worktree's deps/ symlinked to the main checkout. Not a glob: zsh aborts on one that matches nothing. # If deps are not built: git clone --depth 1 -b v3.3.2 https://github.com/SoftFever/Orca-deps-wxWidgets grep -n "CaptureMouse" -A 30 $WX/interface/wx/window.h # documented contract (doxygen source) grep -rn "@onlyfor\|not implemented" $WX/interface/wx/popupwin.h # documented platform limits @@ -40,6 +41,13 @@ grep -n "IsDark" $WX/docs/changes.txt # what changed in grep -n "NotifyCaptureLost" -r $WX/src/osx $WX/src/gtk $WX/src/msw # what each port actually does ``` +On Windows these lookups are bash: run them from Git Bash. PowerShell has no `grep`, and its `find` is +Windows' text-search `find.exe`. To locate the wx tree from PowerShell: + +```powershell +$WX = Resolve-Path deps\*\dep_wxWidgets-prefix\src\dep_wxWidgets, deps\*\*\dep_wxWidgets-prefix\src\dep_wxWidgets -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Path +``` + `interface/wx/.h` is the documentation; `src/common` holds shared behaviour and `src/{msw,osx,gtk,unix,generic}` the per-port implementation. When the docs and the source disagree, the source is what runs — the references mark such facts **[source]**. Orca-side design docs live in diff --git a/.claude/skills/orca-wxwidgets/references/controls-dataview.md b/.claude/skills/orca-wxwidgets/references/controls-dataview.md index 0789f47d79..3671e05991 100644 --- a/.claude/skills/orca-wxwidgets/references/controls-dataview.md +++ b/.claude/skills/orca-wxwidgets/references/controls-dataview.md @@ -331,6 +331,10 @@ OrcaSlicer: integer spinners are `::SpinInput` ([below](#spininput)); progress b Contract: - A page must be created with the book as its parent and added once; the book owns and deletes it (`interface/wx/bookctrl.h:253-254, 273`). `RemovePage` detaches without deleting, and you then own it (`:324-330`). +- Removing the selected page selects the page before it (the new first page if it was first) through `SetSelection`, + so that page is shown and PAGE_CHANGING/CHANGED are sent; removing a page before the selection only shifts the + index. This is `wxBookCtrlBase::DoSetSelectionAfterRemoval` (`src/common/bookctrl.cpp:477-495` **[source]**), + called from `DoRemovePage` by `wxSimplebook`, `wxChoicebook`, `wxListbook`, `wxToolbook` and Orca's `Notebook`. - `GetSelection()` inside a `PAGE_CHANGED` handler may return the old or the new page depending on the platform; use `event.GetSelection()` (`interface/wx/bookctrl.h:160-166`). - `wxSimplebook` has no UI; switch with `ChangeSelection()`. `SetSelection()` sends PAGE_CHANGING/CHANGED diff --git a/.claude/skills/orca-wxwidgets/references/mouse-keyboard-focus.md b/.claude/skills/orca-wxwidgets/references/mouse-keyboard-focus.md index 0ccb5e4b70..48646134d8 100644 --- a/.claude/skills/orca-wxwidgets/references/mouse-keyboard-focus.md +++ b/.claude/skills/orca-wxwidgets/references/mouse-keyboard-focus.md @@ -10,7 +10,7 @@ wx asserts are compiled out in Orca (`wxDEBUG_LEVEL=0`), so every misuse below t an assert fails silently. "GTK" means wxGTK3, Orca's Linux default (X11 and Wayland); GTK2 is only an opt-out build (`-DDEP_WX_GTK3=OFF`), noted where it differs. Paths starting `interface/`, `include/`, `src/`, `docs/` are in the wx tree -(`find deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets'`); Orca paths are +(located as in `SKILL.md` §Ground truth); Orca paths are relative to `src/slic3r/GUI/`. Contents: [Rules](#rules) · [Mouse capture](#mouse-capture) · [Mouse events](#mouse-events) · diff --git a/.claude/skills/orca-wxwidgets/references/orca-architecture.md b/.claude/skills/orca-wxwidgets/references/orca-architecture.md index 801494d802..6c23122910 100644 --- a/.claude/skills/orca-wxwidgets/references/orca-architecture.md +++ b/.claude/skills/orca-wxwidgets/references/orca-architecture.md @@ -332,7 +332,9 @@ indices: pages come and go per printer and per feature flag. pages depending on the printer and on `use_printer_agents`; a removed page stays registered but is not prebuilt (its `LazyPage::in_book()` is false). - Plugin pages are appended by `PluginPages::initialize` (`plugin/host/PluginPages.hpp`) with - namespaced ids (`plugin..`) that cannot collide with `TAB_ID_*`. + namespaced ids (`plugin..`) that cannot collide with `TAB_ID_*`. Each is a + `LazyPage` with order −1, destroyed when its capability goes away. + → [Deferred construction](#deferred-construction-lazy-lazypage-stagedbuild-idlescheduler) ### Preset tabs @@ -529,6 +531,32 @@ the main frame does nothing to a panel after creating it. m_idle.add(m_diff_dialog); ``` Cite: `IdleScheduler::tick`, `docs/HLSD/deferred-page-construction.md`. +- **Rule:** A lazy page that can be destroyed while the main frame lives takes a negative order and + stays out of `m_lazy_pages`. + **Why:** `m_lazy_pages` and `PrebuildQueue` hold raw `LazyBase*` and nothing removes one + (`PrebuildQueue` has only `add` and `clear`). The queue calls `pending()` on every task each slice, + and `prebuild_pages_when_idle` reads every entry of `m_lazy_pages`, so a page destroyed while still + listed can be read after it is freed. A page only taken out of the book is fine: it stays registered + and its `pending()` is false (`MainFrame::show_device`). + ```cpp + // Right (PluginPages::create_page): order -1, and no m_lazy_pages.push_back + auto* page = new GUI::LazyPage(m_parent, name, -1, [capability](wxWindow* parent) { + return new PluginPage(parent, capability); + }); + ``` + Cite: `PluginPages::create_page`, `PluginPages::remove_page`. +- **Rule:** Remove several lazy pages from a book left to right. + **Why:** removing the selected page selects and shows the page before it + (`references/controls-dataview.md` §Book controls), and showing an unbuilt `LazyPage` while the frame + is shown builds it. In any other order the page before the selected one can be one removed next, + built only to be destroyed; left to right it is one that stays (unless the selected page is the + book's first). + ```cpp + // Right (PluginPages::shutdown): m_order is the tabs' left-to-right order + for (const PluginCapabilityId& id : std::vector(m_order)) + remove_page(id); + ``` + Cite: `PluginPages::shutdown`, `PluginPages::relayout`, `PluginPages::on_plugin_deregister`. ## Plater and Sidebar diff --git a/.claude/skills/orca-wxwidgets/references/painting-custom-widgets.md b/.claude/skills/orca-wxwidgets/references/painting-custom-widgets.md index 905ff97d99..4f047042c3 100644 --- a/.claude/skills/orca-wxwidgets/references/painting-custom-widgets.md +++ b/.claude/skills/orca-wxwidgets/references/painting-custom-widgets.md @@ -6,7 +6,7 @@ to write a custom control on the wx side and how to author an Orca widget on the `StaticBox`/`StateHandler` foundation. Read it before writing or reviewing any `wxEVT_PAINT` handler, `render`/`doRender` method, `messureSize`, or a new class under `src/slic3r/GUI/Widgets/`. -wx cites are relative to the pinned wx 3.3.2 tree (`deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets`). +wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every wx assert below is compiled out and `wxCHECK*` returns silently, so paint misuse shows up only as wrong, missing or stale pixels, never as an assert dialog. diff --git a/.claude/skills/orca-wxwidgets/references/platforms.md b/.claude/skills/orca-wxwidgets/references/platforms.md index 13ed32314a..f100b02269 100644 --- a/.claude/skills/orca-wxwidgets/references/platforms.md +++ b/.claude/skills/orca-wxwidgets/references/platforms.md @@ -78,8 +78,9 @@ Contents: [Rules](#rules) · [The wx build Orca uses](#the-wx-build-orca-uses) `references/colours-dark-mode.md`. - The checked-out source is the tree that every wx citation in this skill refers to: `deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets` on macOS and - `deps/build/dep_wxWidgets-prefix/src/dep_wxWidgets` on Linux. Find it with - `find deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets'`. On macOS its + `deps//dep_wxWidgets-prefix/src/dep_wxWidgets` on Linux and Windows (`deps/build` for a + release build; `build_win.bat` names the others). Locate it with the bash or PowerShell lookup in + `SKILL.md` §Ground truth. On macOS its `src/osx/cocoa/colour.mm` already has the patch applied. - **Flatpak builds wx separately.** `deps/CMakeLists.txt` leaves `dep_wxWidgets` out of the deps target when `FLATPAK` is set. Instead, `scripts/flatpak/com.orcaslicer.OrcaSlicer.yml` has its own diff --git a/.claude/skills/orca-wxwidgets/references/popups-menus.md b/.claude/skills/orca-wxwidgets/references/popups-menus.md index be1abb69a8..3fab369436 100644 --- a/.claude/skills/orca-wxwidgets/references/popups-menus.md +++ b/.claude/skills/orca-wxwidgets/references/popups-menus.md @@ -5,7 +5,7 @@ How wx 3.3.2 popups and menus behave on each port, and the Orca wrappers built o `append_menu_item`, `Plater::PopupMenu` and the macOS menubar versus `BBLTopbar`. Read it before you add or change anything that opens over other UI and must close by itself, or any context menu or menubar item. -wx cites are relative to the wx tree root (`deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets`). +wx cites are relative to the wx tree root (located as in `SKILL.md` §Ground truth). **[source]** marks behaviour derived from the implementation that the wx docs do not state or contradict. Orca builds wx with `wxBUILD_DEBUG_LEVEL=0`, so every "asserts" below means "fails silently in Orca". "GTK" means wxGTK3 (X11 and Wayland), the default Linux build; GTK2 is only an opt-out (`-DDEP_WX_GTK3=OFF`). diff --git a/.claude/skills/orca-wxwidgets/references/threads-timers-app.md b/.claude/skills/orca-wxwidgets/references/threads-timers-app.md index 8c8367c999..269c228a35 100644 --- a/.claude/skills/orca-wxwidgets/references/threads-timers-app.md +++ b/.claude/skills/orca-wxwidgets/references/threads-timers-app.md @@ -7,7 +7,7 @@ yields and nested event loops, progress dialogs, startup, shutdown and exception screen, and the access rules for `wxGetApp()` and `app_config`. Read it whenever code runs off the main thread, defers work, starts a timer, yields, shows progress, or runs during startup or shutdown. -wx cites are relative to the pinned wx 3.3.2 tree (`deps/build//dep_wxWidgets-prefix/src/dep_wxWidgets`). +wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`, so `wxASSERT` is compiled out and `wxCHECK*` returns silently: a timer started off the main thread never fires on macOS, `Exit()` on a loop that is not the active one is ignored, `Start(0)` on macOS fails — all without diff --git a/.claude/skills/orca-wxwidgets/references/windows-dialogs.md b/.claude/skills/orca-wxwidgets/references/windows-dialogs.md index 1c5be5af4c..ff8a858e24 100644 --- a/.claude/skills/orca-wxwidgets/references/windows-dialogs.md +++ b/.claude/skills/orca-wxwidgets/references/windows-dialogs.md @@ -6,10 +6,9 @@ port; what Orca's `DPIDialog`/`DPIFrame` add; the Orca dialog recipe; and the `M Read it before writing or reviewing any dialog, frame, close handler, `Destroy()`/`delete`, or code that keeps a pointer to a window across an event, a `CallAfter` or a modal loop. -wx cites are relative to the pinned wx 3.3.2 tree (`find deps -maxdepth 5 -type d -path -'*dep_wxWidgets-prefix/src/dep_wxWidgets'`). wx is built with `wxBUILD_DEBUG_LEVEL=0` and -`libslic3r_gui` with `wxDEBUG_LEVEL=0`: every wx assert quoted below is compiled out, so misuse -fails silently (dropped call, stuck loop, freed memory), never with an assert dialog. "GTK" below +wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). wx is +built with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every wx assert +quoted below is compiled out, so misuse fails silently (dropped call, stuck loop, freed memory), never with an assert dialog. "GTK" below means wxGTK as Orca builds it on Linux: GTK3 by default (X11 or Wayland); GTK2 is only an opt-out. Contents: [Rules](#rules) · [1 Creating and parenting](#1-creating-and-parenting-windows) · diff --git a/.claude/skills/orca-wxwidgets/references/wx-33-changes.md b/.claude/skills/orca-wxwidgets/references/wx-33-changes.md index c2075ea2fb..4a292d89af 100644 --- a/.claude/skills/orca-wxwidgets/references/wx-33-changes.md +++ b/.claude/skills/orca-wxwidgets/references/wx-33-changes.md @@ -14,7 +14,7 @@ Contents: [Rules](#rules) · [1 Reading the change logs](#1-reading-the-change-l [8 Migration done in Orca](#8-migration-already-done-in-orca) All `docs/`, `interface/`, `include/`, `src/`, `build/` cites are relative to the pinned wx tree -(`find deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets'`), except paths +(located as in `SKILL.md` §Ground truth), except paths explicitly called Orca's (`deps/…`, Orca's `src/CMakeLists.txt`) and bare Orca file + symbol cites. ## Rules diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index 8c7674f4d7..98f0d66032 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -259,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 }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 821d7e40c2..c431bff558 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -823,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}) diff --git a/deps_src/CMakeLists.txt b/deps_src/CMakeLists.txt index a4d71c6f27..d044cedfe5 100644 --- a/deps_src/CMakeLists.txt +++ b/deps_src/CMakeLists.txt @@ -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) diff --git a/deps_src/clipper/CMakeLists.txt b/deps_src/clipper/CMakeLists.txt deleted file mode 100644 index 074cbdf4ff..0000000000 --- a/deps_src/clipper/CMakeLists.txt +++ /dev/null @@ -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 -) diff --git a/deps_src/clipper/clipper.cpp b/deps_src/clipper/clipper.cpp deleted file mode 100644 index 1f16446ac8..0000000000 --- a/deps_src/clipper/clipper.cpp +++ /dev/null @@ -1,4213 +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 * -* * -*******************************************************************************/ - -/******************************************************************************* -* * -* This is a translation of the Delphi Clipper library and the naming style * -* used has retained a Delphi flavour. * -* * -*******************************************************************************/ - -#include "clipper.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CLIPPERLIB_NAMESPACE_PREFIX -namespace CLIPPERLIB_NAMESPACE_PREFIX { -#endif // CLIPPERLIB_NAMESPACE_PREFIX - -#ifdef CLIPPERLIB_USE_XYZ -namespace ClipperLib_Z { -#else /* CLIPPERLIB_USE_XYZ */ -namespace ClipperLib { -#endif /* CLIPPERLIB_USE_XYZ */ - -static double const pi = 3.141592653589793238; -static double const two_pi = pi *2; -static double const def_arc_tolerance = 0.25; - -enum Direction { dRightToLeft, dLeftToRight }; - -static int const Unassigned = -1; //edge not currently 'owning' a solution -static int const Skip = -2; //edge that would otherwise close a path - -#define HORIZONTAL (-1.0E+40) -#define TOLERANCE (1.0e-20) -#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) - -//------------------------------------------------------------------------------ - -inline IntPoint IntPoint2d(cInt x, cInt y) -{ - return IntPoint(x, y -#ifdef CLIPPERLIB_USE_XYZ - , 0 -#endif // CLIPPERLIB_USE_XYZ - ); -} - -// Fast rounding upwards. -inline double FRound(double a) -{ - // Why does Java Math.round(0.49999999999999994) return 1? - // https://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1 - return a == 0.49999999999999994 ? 0 : floor(a + 0.5); -} - -template -inline IType Round(double val) -{ - double v = FRound(val); -#if defined(CLIPPERLIB_INT32) && ! defined(NDEBUG) - static_assert(sizeof(IType) == 4 || sizeof(IType) == 8, "IType must be int32 or int64"); - static constexpr const double hi = 65536. * 16383. * (sizeof(IType) == 4 ? 1 : 65536. * 65536.); - if (v > hi || -v > hi) - throw clipperException("Coordinate outside allowed range"); -#endif - return static_cast(v); -} - -// Overriding the Eigen operators because we don't want to compare Z coordinate if IntPoint is 3 dimensional. -inline bool operator==(const IntPoint &l, const IntPoint &r) { return l.x() == r.x() && l.y() == r.y(); } -inline bool operator!=(const IntPoint &l, const IntPoint &r) { return l.x() != r.x() || l.y() != r.y(); } - -//------------------------------------------------------------------------------ -// PolyTree methods ... -//------------------------------------------------------------------------------ - -int PolyTree::Total() const -{ - int result = (int)AllNodes.size(); - //with negative offsets, ignore the hidden outer polygon ... - if (result > 0 && Childs.front() != &AllNodes.front()) result--; - return result; -} - -//------------------------------------------------------------------------------ -// PolyNode methods ... -//------------------------------------------------------------------------------ - -void PolyNode::AddChild(PolyNode& child) -{ - unsigned cnt = (unsigned)Childs.size(); - Childs.emplace_back(&child); - child.Parent = this; - child.Index = cnt; -} -//------------------------------------------------------------------------------ - -// Edge delimits a hole if it has an odd number of parent loops. -bool PolyNode::IsHole() const -{ - bool result = true; - PolyNode* node = Parent; - while (node) - { - result = !result; - node = node->Parent; - } - return result; -} - -void PolyTree::RemoveOutermostPolygon() -{ - if (this->ChildCount() == 1 && this->Childs[0]->ChildCount() > 0) { - PolyNode *outerNode = this->Childs[0]; - this->Childs.reserve(outerNode->ChildCount()); - this->Childs[0] = outerNode->Childs[0]; - this->Childs[0]->Parent = outerNode->Parent; - for (int i = 1; i < outerNode->ChildCount(); ++i) - this->AddChild(*outerNode->Childs[i]); - } else - this->Clear(); -} - -//------------------------------------------------------------------------------ -// Miscellaneous global functions -//------------------------------------------------------------------------------ - -double Area(const Path &poly) -{ - int size = (int)poly.size(); - if (size < 3) return 0; - - double a = 0; - for (int i = 0, j = size -1; i < size; ++i) - { - a += ((double)poly[j].x() + poly[i].x()) * ((double)poly[j].y() - poly[i].y()); - j = i; - } - return -a * 0.5; -} -//------------------------------------------------------------------------------ - -double Area(const OutPt *op) -{ - const OutPt *startOp = op; - if (!op) return 0; - double a = 0; - do { - a += (double)(op->Prev->Pt.x() + op->Pt.x()) * (double)(op->Prev->Pt.y() - op->Pt.y()); - op = op->Next; - } while (op != startOp); - return a * 0.5; -} -//------------------------------------------------------------------------------ - -double Area(const OutRec &outRec) -{ - return Area(outRec.Pts); -} -//------------------------------------------------------------------------------ - -bool PointIsVertex(const IntPoint &Pt, OutPt *pp) -{ - OutPt *pp2 = pp; - do - { - if (pp2->Pt == Pt) return true; - pp2 = pp2->Next; - } - while (pp2 != pp); - return false; -} -//------------------------------------------------------------------------------ - -//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos -//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf -int PointInPolygon(const IntPoint &pt, const Path &path) -{ - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - size_t cnt = path.size(); - if (cnt < 3) return 0; - IntPoint ip = path[0]; - for(size_t i = 1; i <= cnt; ++i) - { - IntPoint ipNext = (i == cnt ? path[0] : path[i]); - if (ipNext.y() == pt.y() && ((ipNext.x() == pt.x()) || (ip.y() == pt.y() && ((ipNext.x() > pt.x()) == (ip.x() < pt.x()))))) - return -1; - if ((ip.y() < pt.y()) != (ipNext.y() < pt.y())) - { - if (ip.x() >= pt.x()) - { - if (ipNext.x() > pt.x()) result = 1 - result; - else - { - auto d = CrossProductType(ip.x() - pt.x()) * CrossProductType(ipNext.y() - pt.y()) - CrossProductType(ipNext.x() - pt.x()) * CrossProductType(ip.y() - pt.y()); - if (!d) return -1; - if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result; - } - } else - { - if (ipNext.x() > pt.x()) - { - auto d = CrossProductType(ip.x() - pt.x()) * CrossProductType(ipNext.y() - pt.y()) - CrossProductType(ipNext.x() - pt.x()) * CrossProductType(ip.y() - pt.y()); - if (!d) return -1; - if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result; - } - } - } - ip = ipNext; - } - return result; -} -//------------------------------------------------------------------------------ - -// Called by Poly2ContainsPoly1() -int PointInPolygon(const IntPoint &pt, OutPt *op) -{ - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - OutPt* startOp = op; - do - { - if (op->Next->Pt.y() == pt.y()) - { - if ((op->Next->Pt.x() == pt.x()) || (op->Pt.y() == pt.y() && - ((op->Next->Pt.x() > pt.x()) == (op->Pt.x() < pt.x())))) return -1; - } - if ((op->Pt.y() < pt.y()) != (op->Next->Pt.y() < pt.y())) - { - if (op->Pt.x() >= pt.x()) - { - if (op->Next->Pt.x() > pt.x()) result = 1 - result; - else - { - auto d = CrossProductType(op->Pt.x() - pt.x()) * CrossProductType(op->Next->Pt.y() - pt.y()) - CrossProductType(op->Next->Pt.x() - pt.x()) * CrossProductType(op->Pt.y() - pt.y()); - if (!d) return -1; - if ((d > 0) == (op->Next->Pt.y() > op->Pt.y())) result = 1 - result; - } - } else - { - if (op->Next->Pt.x() > pt.x()) - { - auto d = CrossProductType(op->Pt.x() - pt.x()) * CrossProductType(op->Next->Pt.y() - pt.y()) - CrossProductType(op->Next->Pt.x() - pt.x()) * CrossProductType(op->Pt.y() - pt.y()); - if (!d) return -1; - if ((d > 0) == (op->Next->Pt.y() > op->Pt.y())) result = 1 - result; - } - } - } - op = op->Next; - } while (startOp != op); - return result; -} -//------------------------------------------------------------------------------ - -// This is potentially very expensive! O(n^2)! -bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) -{ - OutPt* op = OutPt1; - do - { - //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon - int res = PointInPolygon(op->Pt, OutPt2); - if (res >= 0) return res > 0; - op = op->Next; - } - while (op != OutPt1); - return true; -} -//---------------------------------------------------------------------- - -#ifdef CLIPPERLIB_INT32 -inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool /* UseFullInt64Range */) { - return int64_t(dy1) * int64_t(dx2) == int64_t(dx1) * int64_t(dy2); -} -#else -inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool UseFullInt64Range) { - return (UseFullInt64Range) ? - // |dx1| < 2^63, |dx2| < 2^63 etc, - Int128::sign_determinant_2x2_filtered(dx1, dy1, dx2, dy2) == 0 : -// Int128::sign_determinant_2x2(dx1, dy1, dx2, dy2) == 0 : - // |dx1| < 2^31, |dx2| < 2^31 etc, - // therefore the following computation could be done with 64bit arithmetics. - dy1 * dx2 == dx1 * dy2; -} -#endif - -inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) - { return SlopesEqual(e1.Top.x() - e1.Bot.x(), e1.Top.y() - e1.Bot.y(), e2.Top.x() - e2.Bot.x(), e2.Top.y() - e2.Bot.y(), UseFullInt64Range); } -inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, bool UseFullInt64Range) - { return SlopesEqual(pt1.x()-pt2.x(), pt1.y()-pt2.y(), pt2.x()-pt3.x(), pt2.y()-pt3.y(), UseFullInt64Range); } -inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, const IntPoint &pt4, bool UseFullInt64Range) - { return SlopesEqual(pt1.x()-pt2.x(), pt1.y()-pt2.y(), pt3.x()-pt4.x(), pt3.y()-pt4.y(), UseFullInt64Range); } - -//------------------------------------------------------------------------------ - -inline bool IsHorizontal(TEdge &e) -{ - return e.Dx == HORIZONTAL; -} -//------------------------------------------------------------------------------ - -inline double GetDx(const IntPoint &pt1, const IntPoint &pt2) -{ - return (pt1.y() == pt2.y()) ? - HORIZONTAL : (double)(pt2.x() - pt1.x()) / (pt2.y() - pt1.y()); -} -//--------------------------------------------------------------------------- - -inline cInt TopX(TEdge &edge, const cInt currentY) -{ - return (currentY == edge.Top.y()) ? - edge.Top.x() : - edge.Bot.x() + Round(edge.Dx *(currentY - edge.Bot.y())); -} -//------------------------------------------------------------------------------ - -void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) -{ -#ifdef CLIPPERLIB_USE_XYZ - ip.z() = 0; -#endif - - if (Edge1.Dx == Edge2.Dx) - { - ip.y() = Edge1.Curr.y(); - ip.x() = TopX(Edge1, ip.y()); - return; - } - - int64_t y; - if (Edge1.Dx == 0) - { - ip.x() = Edge1.Bot.x(); - y = IsHorizontal(Edge2) ? - Edge2.Bot.y() : - Round(ip.x() / Edge2.Dx + Edge2.Bot.y() - (Edge2.Bot.x() / Edge2.Dx)); - - } - else if (Edge2.Dx == 0) - { - ip.x() = Edge2.Bot.x(); - y = IsHorizontal(Edge1) ? - Edge1.Bot.y() : - Round(ip.x() / Edge1.Dx + Edge1.Bot.y() - (Edge1.Bot.x() / Edge1.Dx)); - } - else - { - double b1 = double(Edge1.Bot.x()) - double(Edge1.Bot.y()) * Edge1.Dx; - double b2 = double(Edge2.Bot.x()) - double(Edge2.Bot.y()) * Edge2.Dx; - double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); - y = Round(q); - ip.x() = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ? - Round(Edge1.Dx * q + b1) : - Round(Edge2.Dx * q + b2); - } - - ip.y() = cInt(y); - if (y < Edge1.Top.y() || y < Edge2.Top.y()) - { - ip.y() = (Edge1.Top.y() > Edge2.Top.y() ? Edge1 : Edge2).Top.y(); - y = ip.y(); - ip.x() = TopX(std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx) ? Edge1 : Edge2, ip.y()); - } - //finally, don't allow 'ip' to be BELOW curr.y() (ie bottom of scanbeam) ... - if (y > Edge1.Curr.y()) - { - ip.y() = Edge1.Curr.y(); - //use the more vertical edge to derive X ... - ip.x() = TopX(std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx) ? Edge2 : Edge1, ip.y()); - } -} -//------------------------------------------------------------------------------ - -// Reverse a linked loop of points representing a closed polygon. -// This has a time complexity of O(n) -void ReversePolyPtLinks(OutPt *pp) -{ - if (!pp) return; - OutPt *pp1 = pp; - do { - OutPt *pp2 = pp1->Next; - pp1->Next = pp1->Prev; - pp1->Prev = pp2; - pp1 = pp2; - } while( pp1 != pp ); -} -//------------------------------------------------------------------------------ - -inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) -{ - std::memset(e, 0, sizeof(TEdge)); - e->Next = eNext; - e->Prev = ePrev; - e->Curr = Pt; - e->OutIdx = Unassigned; -} -//------------------------------------------------------------------------------ - -void InitEdge2(TEdge& e, PolyType Pt) -{ - if (e.Curr.y() >= e.Next->Curr.y()) - { - e.Bot = e.Curr; - e.Top = e.Next->Curr; - } else - { - e.Top = e.Curr; - e.Bot = e.Next->Curr; - } - - cInt dy = (e.Top.y() - e.Bot.y()); - if (dy == 0) e.Dx = HORIZONTAL; - else e.Dx = (double)(e.Top.x() - e.Bot.x()) / dy; - - e.PolyTyp = Pt; -} -//------------------------------------------------------------------------------ - -// Called from ClipperBase::AddPathInternal() to remove collinear and duplicate points. -inline TEdge* RemoveEdge(TEdge* e) -{ - //removes e from double_linked_list (but without removing from memory) - e->Prev->Next = e->Next; - e->Next->Prev = e->Prev; - TEdge* result = e->Next; - e->Prev = 0; //flag as removed (see ClipperBase.Clear) - return result; -} -//------------------------------------------------------------------------------ - -inline void ReverseHorizontal(TEdge &e) -{ - //swap horizontal edges' Top and Bottom x's so they follow the natural - //progression of the bounds - ie so their xbots will align with the - //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] - std::swap(e.Top.x(), e.Bot.x()); -#ifdef CLIPPERLIB_USE_XYZ - std::swap(e.Top.z(), e.Bot.z()); -#endif -} -//------------------------------------------------------------------------------ - -bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, - IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) -{ - //precondition: segments are Collinear. - if (std::abs(pt1a.x() - pt1b.x()) > std::abs(pt1a.y() - pt1b.y())) - { - if (pt1a.x() > pt1b.x()) std::swap(pt1a, pt1b); - if (pt2a.x() > pt2b.x()) std::swap(pt2a, pt2b); - if (pt1a.x() > pt2a.x()) pt1 = pt1a; else pt1 = pt2a; - if (pt1b.x() < pt2b.x()) pt2 = pt1b; else pt2 = pt2b; - return pt1.x() < pt2.x(); - } else - { - if (pt1a.y() < pt1b.y()) std::swap(pt1a, pt1b); - if (pt2a.y() < pt2b.y()) std::swap(pt2a, pt2b); - if (pt1a.y() < pt2a.y()) pt1 = pt1a; else pt1 = pt2a; - if (pt1b.y() > pt2b.y()) pt2 = pt1b; else pt2 = pt2b; - return pt1.y() > pt2.y(); - } -} -//------------------------------------------------------------------------------ - -bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) -{ - OutPt *p = btmPt1->Prev; - while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; - double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); - p = btmPt1->Next; - while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; - double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); - - p = btmPt2->Prev; - while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; - double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); - p = btmPt2->Next; - while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; - double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); - - if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) && - std::min(dx1p, dx1n) == std::min(dx2p, dx2n)) - return Area(btmPt1) > 0; //if otherwise identical use orientation - else - return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); -} -//------------------------------------------------------------------------------ - -// Called by GetLowermostRec() -OutPt* GetBottomPt(OutPt *pp) -{ - OutPt* dups = nullptr; - OutPt* p = pp->Next; - while (p != pp) - { - if (p->Pt.y() > pp->Pt.y()) - { - pp = p; - dups = nullptr; - } - else if (p->Pt.y() == pp->Pt.y() && p->Pt.x() <= pp->Pt.x()) - { - if (p->Pt.x() < pp->Pt.x()) - { - dups = nullptr; - pp = p; - } else - { - if (p->Next != pp && p->Prev != pp) dups = p; - } - } - p = p->Next; - } - if (dups) - { - //there appears to be at least 2 vertices at BottomPt so ... - while (dups != p) - { - if (!FirstIsBottomPt(p, dups)) pp = dups; - dups = dups->Next; - while (dups->Pt != pp->Pt) dups = dups->Next; - } - } - return pp; -} - -//------------------------------------------------------------------------------ - -bool Pt2IsBetweenPt1AndPt3(const IntPoint &pt1, - const IntPoint &pt2, const IntPoint &pt3) -{ - if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) - return false; - else if (pt1.x() != pt3.x()) - return (pt2.x() > pt1.x()) == (pt2.x() < pt3.x()); - else - return (pt2.y() > pt1.y()) == (pt2.y() < pt3.y()); -} -//------------------------------------------------------------------------------ - -bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) -{ - if (seg1a > seg1b) std::swap(seg1a, seg1b); - if (seg2a > seg2b) std::swap(seg2a, seg2b); - return (seg1a < seg2b) && (seg2a < seg1b); -} - -//------------------------------------------------------------------------------ -// ClipperBase class methods ... -//------------------------------------------------------------------------------ - -#ifdef CLIPPERLIB_INT32 -static inline void RangeTest(const IntPoint &pt) -{ -#ifndef NDEBUG - static constexpr const int32_t hi = 65536 * 16383; - if (pt.x() > hi || pt.y() > hi || -pt.x() > hi || -pt.y() > hi) - throw clipperException("Coordinate outside allowed range"); -#endif // NDEBUG -} -#else // CLIPPERLIB_INT32 -// Called from ClipperBase::AddPath() to verify the scale of the input polygon coordinates. -static inline void RangeTest(const IntPoint& Pt, bool& useFullRange) -{ - if (useFullRange) - { - if (Pt.x() > hiRange || Pt.y() > hiRange || -Pt.x() > hiRange || -Pt.y() > hiRange) - throw clipperException("Coordinate outside allowed range"); - } - else if (Pt.x() > loRange|| Pt.y() > loRange || -Pt.x() > loRange || -Pt.y() > loRange) - { - useFullRange = true; - RangeTest(Pt, useFullRange); - } -} -#endif // CLIPPERLIB_INT32 -//------------------------------------------------------------------------------ - -// Called from ClipperBase::AddPath() to construct the Local Minima List. -// Find a local minimum edge on the path starting with E. -inline TEdge* FindNextLocMin(TEdge* E) -{ - for (;;) - { - while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; - if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; - while (IsHorizontal(*E->Prev)) E = E->Prev; - TEdge* E2 = E; - while (IsHorizontal(*E)) E = E->Next; - if (E->Top.y() == E->Prev->Bot.y()) continue; //ie just an intermediate horz. - if (E2->Prev->Bot.x() < E->Bot.x()) E = E2; - break; - } - return E; -} -//------------------------------------------------------------------------------ - -// Called from ClipperBase::AddPath(). -TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward) -{ - TEdge *Result = E; - TEdge *Horz = 0; - - if (E->OutIdx == Skip) - { - //if edges still remain in the current bound beyond the skip edge then - //create another LocMin and call ProcessBound once more - if (NextIsForward) - { - while (E->Top.y() == E->Next->Bot.y()) E = E->Next; - //don't include top horizontals when parsing a bound a second time, - //they will be contained in the opposite bound ... - while (E != Result && IsHorizontal(*E)) E = E->Prev; - } - else - { - while (E->Top.y() == E->Prev->Bot.y()) E = E->Prev; - while (E != Result && IsHorizontal(*E)) E = E->Next; - } - - if (E == Result) - { - if (NextIsForward) Result = E->Next; - else Result = E->Prev; - } - else - { - //there are more edges in the bound beyond result starting with E - if (NextIsForward) - E = Result->Next; - else - E = Result->Prev; - LocalMinimum locMin; - locMin.Y = E->Bot.y(); - locMin.LeftBound = 0; - locMin.RightBound = E; - E->WindDelta = 0; - Result = ProcessBound(E, NextIsForward); - m_MinimaList.emplace_back(locMin); - } - return Result; - } - - TEdge *EStart; - - if (IsHorizontal(*E)) - { - //We need to be careful with open paths because this may not be a - //true local minima (ie E may be following a skip edge). - //Also, consecutive horz. edges may start heading left before going right. - if (NextIsForward) - EStart = E->Prev; - else - EStart = E->Next; - if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge - { - if (EStart->Bot.x() != E->Bot.x() && EStart->Top.x() != E->Bot.x()) - ReverseHorizontal(*E); - } - else if (EStart->Bot.x() != E->Bot.x()) - ReverseHorizontal(*E); - } - - EStart = E; - if (NextIsForward) - { - while (Result->Top.y() == Result->Next->Bot.y() && Result->Next->OutIdx != Skip) - Result = Result->Next; - if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) - { - //nb: at the top of a bound, horizontals are added to the bound - //only when the preceding edge attaches to the horizontal's left vertex - //unless a Skip edge is encountered when that becomes the top divide - Horz = Result; - while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; - if (Horz->Prev->Top.x() > Result->Next->Top.x()) Result = Horz->Prev; - } - while (E != Result) - { - E->NextInLML = E->Next; - if (IsHorizontal(*E) && E != EStart && - E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E); - E = E->Next; - } - if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Prev->Top.x()) - ReverseHorizontal(*E); - Result = Result->Next; //move to the edge just beyond current bound - } else - { - while (Result->Top.y() == Result->Prev->Bot.y() && Result->Prev->OutIdx != Skip) - Result = Result->Prev; - if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) - { - Horz = Result; - while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; - if (Horz->Next->Top.x() == Result->Prev->Top.x() || - Horz->Next->Top.x() > Result->Prev->Top.x()) Result = Horz->Next; - } - - while (E != Result) - { - E->NextInLML = E->Prev; - if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x()) - ReverseHorizontal(*E); - E = E->Prev; - } - if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x()) - ReverseHorizontal(*E); - Result = Result->Prev; //move to the edge just beyond current bound - } - - return Result; -} -//------------------------------------------------------------------------------ - -bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) -{ - // 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)) - return false; - - // Allocate a new edge array. - Edges edges(highI + 1); - // Fill in the edge array. - bool result = AddPathInternal(pg, highI, PolyTyp, Closed, edges.data()); - if (result) - // Success, remember the edge array. - m_edges.emplace_back(std::move(edges)); - return result; -} - -bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge* edges) -{ -#ifdef use_lines - if (!Closed && PolyTyp == ptClip) - throw clipperException("AddPath: Open paths must be subject."); -#else - if (!Closed) - throw clipperException("AddPath: Open paths have been disabled."); -#endif - - assert(highI >= 0 && highI < pg.size()); - - //1. Basic (first) edge initialization ... - try - { - edges[1].Curr = pg[1]; -#ifdef CLIPPERLIB_INT32 - RangeTest(pg[0]); - RangeTest(pg[highI]); -#else - RangeTest(pg[0], m_UseFullRange); - RangeTest(pg[highI], m_UseFullRange); -#endif // CLIPPERLIB_INT32 - InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); - InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); - for (int i = highI - 1; i >= 1; --i) - { -#ifdef CLIPPERLIB_INT32 - RangeTest(pg[i]); -#else - RangeTest(pg[i], m_UseFullRange); -#endif // CLIPPERLIB_INT32 - InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); - } - } - catch(...) - { - throw; //range test fails - } - TEdge *eStart = &edges[0]; - - //2. Remove duplicate vertices, and (when closed) collinear edges ... - TEdge *E = eStart, *eLoopStop = eStart; - for (;;) - { - //nb: allows matching start and end points when not Closed ... - if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart)) - { - if (E == E->Next) break; - if (E == eStart) eStart = E->Next; - E = RemoveEdge(E); - eLoopStop = E; - continue; - } - if (E->Prev == E->Next) - break; //only two vertices - else if (Closed && - SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && - (!m_PreserveCollinear || - !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) - { - //Collinear edges are allowed for open paths but in closed paths - //the default is to merge adjacent collinear edges into a single edge. - //However, if the PreserveCollinear property is enabled, only overlapping - //collinear edges (ie spikes) will be removed from closed paths. - if (E == eStart) eStart = E->Next; - E = RemoveEdge(E); - E = E->Prev; - eLoopStop = E; - continue; - } - E = E->Next; - if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break; - } - - if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) - { - return false; - } - - if (!Closed) - { - m_HasOpenPaths = true; - eStart->Prev->OutIdx = Skip; - } - - //3. Do second stage of edge initialization ... - // IsFlat means all vertices have the same Y coordinate. - bool IsFlat = true; - E = eStart; - do - { - InitEdge2(*E, PolyTyp); - E = E->Next; - if (IsFlat && E->Curr.y() != eStart->Curr.y()) IsFlat = false; - } - while (E != eStart); - - //4. Finally, add edge bounds to LocalMinima list ... - - //Totally flat paths must be handled differently when adding them - //to LocalMinima list to avoid endless loops etc ... - if (IsFlat) - { - if (Closed) - { - return false; - } - E->Prev->OutIdx = Skip; - LocalMinimum locMin; - locMin.Y = E->Bot.y(); - locMin.LeftBound = 0; - locMin.RightBound = E; - locMin.RightBound->Side = esRight; - locMin.RightBound->WindDelta = 0; - for (;;) - { - if (E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E); - if (E->Next->OutIdx == Skip) break; - E->NextInLML = E->Next; - E = E->Next; - } - m_MinimaList.emplace_back(locMin); - return true; - } - - bool leftBoundIsForward; - TEdge* EMin = 0; - - //workaround to avoid an endless loop in the while loop below when - //open paths have matching start and end points ... - if (E->Prev->Bot == E->Prev->Top) E = E->Next; - - // Find local minima and store them into a Local Minima List. - // Multiple Local Minima could be created for a single path. - for (;;) - { - E = FindNextLocMin(E); - if (E == EMin) break; - else if (!EMin) EMin = E; - - //E and E.Prev now share a local minima (left aligned if horizontal). - //Compare their slopes to find which starts which bound ... - LocalMinimum locMin; - locMin.Y = E->Bot.y(); - if (E->Dx < E->Prev->Dx) - { - locMin.LeftBound = E->Prev; - locMin.RightBound = E; - leftBoundIsForward = false; //Q.nextInLML = Q.prev - } else - { - locMin.LeftBound = E; - locMin.RightBound = E->Prev; - leftBoundIsForward = true; //Q.nextInLML = Q.next - } - - if (!Closed) locMin.LeftBound->WindDelta = 0; - else if (locMin.LeftBound->Next == locMin.RightBound) - locMin.LeftBound->WindDelta = -1; - else locMin.LeftBound->WindDelta = 1; - locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta; - - E = ProcessBound(locMin.LeftBound, leftBoundIsForward); - if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); - - TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward); - if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward); - - if (locMin.LeftBound->OutIdx == Skip) - locMin.LeftBound = 0; - else if (locMin.RightBound->OutIdx == Skip) - locMin.RightBound = 0; - m_MinimaList.emplace_back(locMin); - if (!leftBoundIsForward) E = E2; - } - return true; -} -//------------------------------------------------------------------------------ - -void ClipperBase::Clear() -{ - m_MinimaList.clear(); - m_edges.clear(); -#ifndef CLIPPERLIB_INT32 - m_UseFullRange = false; -#endif // CLIPPERLIB_INT32 - m_HasOpenPaths = false; -} -//------------------------------------------------------------------------------ - -// Initialize the Local Minima List: -// Sort the LML entries, initialize the left / right bound edges of each Local Minima. -void ClipperBase::Reset() -{ - if (m_MinimaList.empty()) return; //ie nothing to process - std::sort(m_MinimaList.begin(), m_MinimaList.end(), [](const LocalMinimum& lm1, const LocalMinimum& lm2){ return lm1.Y < lm2.Y; }); - - //reset all edges ... - for (LocalMinimum &lm : m_MinimaList) { - TEdge* e = lm.LeftBound; - if (e) - { - e->Curr = e->Bot; - e->Side = esLeft; - e->OutIdx = Unassigned; - } - - e = lm.RightBound; - if (e) - { - e->Curr = e->Bot; - e->Side = esRight; - e->OutIdx = Unassigned; - } - } -} -//------------------------------------------------------------------------------ - -// Get bounds of the edges referenced by the Local Minima List. -// Returns (0,0,0,0) for an empty rectangle. -IntRect ClipperBase::GetBounds() -{ - IntRect result; - auto lm = m_MinimaList.begin(); - if (lm == m_MinimaList.end()) - { - result.left = result.top = result.right = result.bottom = 0; - return result; - } - result.left = lm->LeftBound->Bot.x(); - result.top = lm->LeftBound->Bot.y(); - result.right = lm->LeftBound->Bot.x(); - result.bottom = lm->LeftBound->Bot.y(); - while (lm != m_MinimaList.end()) - { - result.bottom = std::max(result.bottom, lm->LeftBound->Bot.y()); - TEdge* e = lm->LeftBound; - for (;;) { - TEdge* bottomE = e; - while (e->NextInLML) - { - if (e->Bot.x() < result.left) result.left = e->Bot.x(); - if (e->Bot.x() > result.right) result.right = e->Bot.x(); - e = e->NextInLML; - } - result.left = std::min(result.left, e->Bot.x()); - result.right = std::max(result.right, e->Bot.x()); - result.left = std::min(result.left, e->Top.x()); - result.right = std::max(result.right, e->Top.x()); - result.top = std::min(result.top, e->Top.y()); - if (bottomE == lm->LeftBound) e = lm->RightBound; - else break; - } - ++lm; - } - return result; -} - -//------------------------------------------------------------------------------ -// TClipper methods ... -//------------------------------------------------------------------------------ - -Clipper::Clipper(int initOptions) : - ClipperBase(), - m_OutPtsFree(nullptr), - m_OutPtsChunkLast(m_OutPtsChunkSize), - m_ActiveEdges(nullptr), - m_SortedEdges(nullptr) -{ - m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); - m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); - m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); - m_HasOpenPaths = false; -#ifdef CLIPPERLIB_USE_XYZ - m_ZFill = 0; -#endif -} -//------------------------------------------------------------------------------ - -void Clipper::Reset() -{ - ClipperBase::Reset(); - m_Scanbeam = std::priority_queue{}; - m_Maxima.clear(); - m_ActiveEdges = 0; - m_SortedEdges = 0; - for (auto lm = m_MinimaList.rbegin(); lm != m_MinimaList.rend(); ++lm) - m_Scanbeam.push(lm->Y); -} - -//------------------------------------------------------------------------------ - -bool Clipper::Execute(ClipType clipType, Paths &solution, - PolyFillType subjFillType, PolyFillType clipFillType) -{ - if (m_HasOpenPaths) - throw clipperException("Error: PolyTree struct is needed for open path clipping."); - solution.clear(); - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = false; - bool succeeded = ExecuteInternal(); - if (succeeded) BuildResult(solution); - DisposeAllOutRecs(); - return succeeded; -} -//------------------------------------------------------------------------------ - -bool Clipper::Execute(ClipType clipType, PolyTree& polytree, - PolyFillType subjFillType, PolyFillType clipFillType) -{ - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = true; - bool succeeded = ExecuteInternal(); - if (succeeded) BuildResult2(polytree); - DisposeAllOutRecs(); - return succeeded; -} -//------------------------------------------------------------------------------ - -bool Clipper::ExecuteInternal() -{ - bool succeeded = true; - try { - Reset(); - if (m_MinimaList.empty()) return true; - cInt botY = m_Scanbeam.top(); - do { m_Scanbeam.pop(); } while (! m_Scanbeam.empty() && botY == m_Scanbeam.top()); - do { - InsertLocalMinimaIntoAEL(botY); - ProcessHorizontals(); - m_GhostJoins.clear(); - if (m_Scanbeam.empty()) break; - cInt topY = m_Scanbeam.top(); - do { m_Scanbeam.pop(); } while (! m_Scanbeam.empty() && topY == m_Scanbeam.top()); - succeeded = ProcessIntersections(topY); - if (!succeeded) break; - ProcessEdgesAtTopOfScanbeam(topY); - botY = topY; - } while (!m_Scanbeam.empty() || !m_MinimaList.empty()); - } - catch(...) - { - succeeded = false; - } - - if (succeeded) - { - - //fix orientations ... - //FIXME Vojtech: Does it not invalidate the loop hierarchy maintained as OutRec::FirstLeft pointers? - //FIXME Vojtech: The area is calculated with floats, it may not be numerically stable! - { - for (OutRec &outRec : m_PolyOuts) - if (outRec.Pts && !outRec.IsOpen && (outRec.IsHole ^ m_ReverseOutput) == (Area(outRec) > 0)) - ReversePolyPtLinks(outRec.Pts); - } - - JoinCommonEdges(); - - //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() - { - for (OutRec &outRec : m_PolyOuts) - if (outRec.Pts) { - if (outRec.IsOpen) - // Removes duplicate points. - FixupOutPolyline(outRec); - else - // Removes duplicate points and simplifies consecutive parallel edges by removing the middle vertex. - FixupOutPolygon(outRec); - } - } - // For each polygon, search for exactly duplicate non-successive points. - // If such a point is found, the loop is split into two pieces. - // Search for the duplicate points is O(n^2)! - // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Properties/StrictlySimple.htm - if (m_StrictSimple) DoSimplePolygons(); - } - - m_Joins.clear(); - m_GhostJoins.clear(); - return succeeded; -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::AllocateOutPt() -{ - OutPt *pt; - if (m_OutPtsFree) { - // Recycle some of the already released points. - pt = m_OutPtsFree; - m_OutPtsFree = pt->Next; - } else if (m_OutPtsChunkLast < m_OutPtsChunkSize) { - // Get a point from the last chunk. - pt = &m_OutPts.back()[m_OutPtsChunkLast ++]; - } else { - // The last chunk is full. Allocate a new one. - m_OutPts.emplace_back(); - m_OutPtsChunkLast = 1; - pt = &m_OutPts.back().front(); - } - return pt; -} - -void Clipper::DisposeAllOutRecs() -{ - m_OutPts.clear(); - m_OutPtsFree = nullptr; - m_OutPtsChunkLast = m_OutPtsChunkSize; - m_PolyOuts.clear(); -} -//------------------------------------------------------------------------------ - -void Clipper::SetWindingCount(TEdge &edge) const -{ - TEdge *e = edge.PrevInAEL; - //find the edge of the same polytype that immediately preceeds 'edge' in AEL - while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; - if (!e) - { - if (edge.WindDelta == 0) - { - PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType); - edge.WindCnt = (pft == pftNegative ? -1 : 1); - } - else - edge.WindCnt = edge.WindDelta; - edge.WindCnt2 = 0; - e = m_ActiveEdges; //ie get ready to calc WindCnt2 - } - else if (edge.WindDelta == 0 && m_ClipType != ctUnion) - { - edge.WindCnt = 1; - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - else if (IsEvenOddFillType(edge)) - { - //EvenOdd filling ... - if (edge.WindDelta == 0) - { - //are we inside a subj polygon ... - bool Inside = true; - TEdge *e2 = e->PrevInAEL; - while (e2) - { - if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) - Inside = !Inside; - e2 = e2->PrevInAEL; - } - edge.WindCnt = (Inside ? 0 : 1); - } - else - { - edge.WindCnt = edge.WindDelta; - } - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - else - { - //nonZero, Positive or Negative filling ... - if (e->WindCnt * e->WindDelta < 0) - { - //prev edge is 'decreasing' WindCount (WC) toward zero - //so we're outside the previous polygon ... - if (std::abs(e->WindCnt) > 1) - { - //outside prev poly but still inside another. - //when reversing direction of prev poly use the same WC - if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; - //otherwise continue to 'decrease' WC ... - else edge.WindCnt = e->WindCnt + edge.WindDelta; - } - else - //now outside all polys of same polytype so set own WC ... - edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); - } else - { - //prev edge is 'increasing' WindCount (WC) away from zero - //so we're inside the previous polygon ... - if (edge.WindDelta == 0) - edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); - //if wind direction is reversing prev then use same WC - else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; - //otherwise add to WC ... - else edge.WindCnt = e->WindCnt + edge.WindDelta; - } - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - - //update WindCnt2 ... - if (IsEvenOddAltFillType(edge)) - { - //EvenOdd filling ... - while (e != &edge) - { - if (e->WindDelta != 0) - edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); - e = e->NextInAEL; - } - } else - { - //nonZero, Positive or Negative filling ... - while ( e != &edge ) - { - edge.WindCnt2 += e->WindDelta; - e = e->NextInAEL; - } - } -} -//------------------------------------------------------------------------------ - -bool Clipper::IsContributing(const TEdge& edge) const -{ - PolyFillType pft, pft2; - if (edge.PolyTyp == ptSubject) - { - pft = m_SubjFillType; - pft2 = m_ClipFillType; - } else - { - pft = m_ClipFillType; - pft2 = m_SubjFillType; - } - - switch(pft) - { - case pftEvenOdd: - //return false if a subj line has been flagged as inside a subj polygon - if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; - break; - case pftNonZero: - if (std::abs(edge.WindCnt) != 1) return false; - break; - case pftPositive: - if (edge.WindCnt != 1) return false; - break; - default: //pftNegative - if (edge.WindCnt != -1) return false; - } - - switch(m_ClipType) - { - case ctIntersection: - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 != 0); - case pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - break; - case ctUnion: - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - break; - case ctDifference: - if (edge.PolyTyp == ptSubject) - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 != 0); - case pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - break; - case ctXor: - if (edge.WindDelta == 0) //XOr always contributing unless open - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - return true; - break; - default: - return true; - } -} -//------------------------------------------------------------------------------ - -// Called from Clipper::InsertLocalMinimaIntoAEL() and Clipper::IntersectEdges(). -OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) -{ - OutPt* result; - TEdge *e, *prevE; - if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) - { - result = AddOutPt(e1, Pt); - e2->OutIdx = e1->OutIdx; - e1->Side = esLeft; - e2->Side = esRight; - e = e1; - if (e->PrevInAEL == e2) - prevE = e2->PrevInAEL; - else - prevE = e->PrevInAEL; - } else - { - result = AddOutPt(e2, Pt); - e1->OutIdx = e2->OutIdx; - e1->Side = esRight; - e2->Side = esLeft; - e = e2; - if (e->PrevInAEL == e1) - prevE = e1->PrevInAEL; - else - prevE = e->PrevInAEL; - } - - if (prevE && prevE->OutIdx >= 0 && prevE->Top.y() < Pt.y() && e->Top.y() < Pt.y()) - { - cInt xPrev = TopX(*prevE, Pt.y()); - cInt xE = TopX(*e, Pt.y()); - if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) && - SlopesEqual(IntPoint2d(xPrev, Pt.y()), prevE->Top, IntPoint2d(xE, Pt.y()), e->Top, m_UseFullRange)) - { - OutPt* outPt = AddOutPt(prevE, Pt); - m_Joins.emplace_back(Join(result, outPt, e->Top)); - } - } - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) -{ - AddOutPt( e1, Pt ); - if (e2->WindDelta == 0) AddOutPt(e2, Pt); - if( e1->OutIdx == e2->OutIdx ) - { - e1->OutIdx = Unassigned; - e2->OutIdx = Unassigned; - } - else if (e1->OutIdx < e2->OutIdx) - AppendPolygon(e1, e2); - else - AppendPolygon(e2, e1); -} -//------------------------------------------------------------------------------ - -void Clipper::AddEdgeToSEL(TEdge *edge) -{ - //SEL pointers in PEdge are reused to build a list of horizontal edges. - //However, we don't need to worry about order with horizontal edge processing. - if( !m_SortedEdges ) - { - m_SortedEdges = edge; - edge->PrevInSEL = 0; - edge->NextInSEL = 0; - } - else - { - edge->NextInSEL = m_SortedEdges; - edge->PrevInSEL = 0; - m_SortedEdges->PrevInSEL = edge; - m_SortedEdges = edge; - } -} -//------------------------------------------------------------------------------ - -void Clipper::CopyAELToSEL() -{ - TEdge* e = m_ActiveEdges; - m_SortedEdges = e; - while ( e ) - { - e->PrevInSEL = e->PrevInAEL; - e->NextInSEL = e->NextInAEL; - e = e->NextInAEL; - } -} - -//------------------------------------------------------------------------------ - -// Called from Clipper::ExecuteInternal() -void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) -{ - while (!m_MinimaList.empty() && m_MinimaList.back().Y == botY) - { - TEdge* lb = m_MinimaList.back().LeftBound; - TEdge* rb = m_MinimaList.back().RightBound; - m_MinimaList.pop_back(); - - OutPt *Op1 = 0; - if (!lb) - { - //nb: don't insert LB into either AEL or SEL - InsertEdgeIntoAEL(rb, 0); - SetWindingCount(*rb); - if (IsContributing(*rb)) - Op1 = AddOutPt(rb, rb->Bot); - } - else if (!rb) - { - InsertEdgeIntoAEL(lb, 0); - SetWindingCount(*lb); - if (IsContributing(*lb)) - Op1 = AddOutPt(lb, lb->Bot); - m_Scanbeam.push(lb->Top.y()); - } - else - { - InsertEdgeIntoAEL(lb, 0); - InsertEdgeIntoAEL(rb, lb); - SetWindingCount( *lb ); - rb->WindCnt = lb->WindCnt; - rb->WindCnt2 = lb->WindCnt2; - if (IsContributing(*lb)) - Op1 = AddLocalMinPoly(lb, rb, lb->Bot); - m_Scanbeam.push(lb->Top.y()); - } - - if (rb) - { - if (IsHorizontal(*rb)) - { - AddEdgeToSEL(rb); - if (rb->NextInLML) - m_Scanbeam.push(rb->NextInLML->Top.y()); - } - else m_Scanbeam.push(rb->Top.y()); - } - - if (!lb || !rb) continue; - - //if any output polygons share an edge, they'll need joining later ... - if (Op1 && IsHorizontal(*rb) && - m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) - { - for (Join &jr : m_GhostJoins) - //if the horizontal Rb and a 'ghost' horizontal overlap, then convert - //the 'ghost' join to a real join ready for later ... - if (HorzSegmentsOverlap(jr.OutPt1->Pt.x(), jr.OffPt.x(), rb->Bot.x(), rb->Top.x())) - m_Joins.emplace_back(Join(jr.OutPt1, Op1, jr.OffPt)); - } - - if (lb->OutIdx >= 0 && lb->PrevInAEL && - lb->PrevInAEL->Curr.x() == lb->Bot.x() && - lb->PrevInAEL->OutIdx >= 0 && - SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) && - (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) - { - OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); - m_Joins.emplace_back(Join(Op1, Op2, lb->Top)); - } - - if(lb->NextInAEL != rb) - { - - if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && - SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) && - (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) - { - OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); - m_Joins.emplace_back(Join(Op1, Op2, rb->Top)); - } - - TEdge* e = lb->NextInAEL; - if (e) - { - while( e != rb ) - { - //nb: For calculating winding counts etc, IntersectEdges() assumes - //that param1 will be to the Right of param2 ABOVE the intersection ... - IntersectEdges(rb , e , lb->Curr); //order important here - e = e->NextInAEL; - } - } - } - - } -} -//------------------------------------------------------------------------------ - -void Clipper::DeleteFromAEL(TEdge *e) -{ - TEdge* AelPrev = e->PrevInAEL; - TEdge* AelNext = e->NextInAEL; - if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted - if( AelPrev ) AelPrev->NextInAEL = AelNext; - else m_ActiveEdges = AelNext; - if( AelNext ) AelNext->PrevInAEL = AelPrev; - e->NextInAEL = 0; - e->PrevInAEL = 0; -} -//------------------------------------------------------------------------------ - -void Clipper::DeleteFromSEL(TEdge *e) -{ - TEdge* SelPrev = e->PrevInSEL; - TEdge* SelNext = e->NextInSEL; - if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted - if( SelPrev ) SelPrev->NextInSEL = SelNext; - else m_SortedEdges = SelNext; - if( SelNext ) SelNext->PrevInSEL = SelPrev; - e->NextInSEL = 0; - e->PrevInSEL = 0; -} -//------------------------------------------------------------------------------ - -#ifdef CLIPPERLIB_USE_XYZ -void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2) -{ - if (pt.z() != 0 || !m_ZFill) return; - else if (pt == e1.Bot) pt.z() = e1.Bot.z(); - else if (pt == e1.Top) pt.z() = e1.Top.z(); - else if (pt == e2.Bot) pt.z() = e2.Bot.z(); - else if (pt == e2.Top) pt.z() = e2.Top.z(); - else m_ZFill(e1.Bot, e1.Top, e2.Bot, e2.Top, pt); -} -//------------------------------------------------------------------------------ -#endif - -void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt) -{ - bool e1Contributing = ( e1->OutIdx >= 0 ); - bool e2Contributing = ( e2->OutIdx >= 0 ); - -#ifdef CLIPPERLIB_USE_XYZ - SetZ(Pt, *e1, *e2); -#endif - -#ifdef use_lines - //if either edge is on an OPEN path ... - if (e1->WindDelta == 0 || e2->WindDelta == 0) - { - //ignore subject-subject open path intersections UNLESS they - //are both open paths, AND they are both 'contributing maximas' ... - if (e1->WindDelta == 0 && e2->WindDelta == 0) return; - - //if intersecting a subj line with a subj poly ... - else if (e1->PolyTyp == e2->PolyTyp && - e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) - { - if (e1->WindDelta == 0) - { - if (e2Contributing) - { - AddOutPt(e1, Pt); - if (e1Contributing) e1->OutIdx = Unassigned; - } - } - else - { - if (e1Contributing) - { - AddOutPt(e2, Pt); - if (e2Contributing) e2->OutIdx = Unassigned; - } - } - } - else if (e1->PolyTyp != e2->PolyTyp) - { - //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... - if ((e1->WindDelta == 0) && std::abs(e2->WindCnt) == 1 && - (m_ClipType != ctUnion || e2->WindCnt2 == 0)) - { - AddOutPt(e1, Pt); - if (e1Contributing) e1->OutIdx = Unassigned; - } - else if ((e2->WindDelta == 0) && (std::abs(e1->WindCnt) == 1) && - (m_ClipType != ctUnion || e1->WindCnt2 == 0)) - { - AddOutPt(e2, Pt); - if (e2Contributing) e2->OutIdx = Unassigned; - } - } - return; - } -#endif - - //update winding counts... - //assumes that e1 will be to the Right of e2 ABOVE the intersection - if ( e1->PolyTyp == e2->PolyTyp ) - { - if ( IsEvenOddFillType( *e1) ) - { - int oldE1WindCnt = e1->WindCnt; - e1->WindCnt = e2->WindCnt; - e2->WindCnt = oldE1WindCnt; - } else - { - if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; - else e1->WindCnt += e2->WindDelta; - if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; - else e2->WindCnt -= e1->WindDelta; - } - } else - { - if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; - else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; - if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; - else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; - } - - PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; - if (e1->PolyTyp == ptSubject) - { - e1FillType = m_SubjFillType; - e1FillType2 = m_ClipFillType; - } else - { - e1FillType = m_ClipFillType; - e1FillType2 = m_SubjFillType; - } - if (e2->PolyTyp == ptSubject) - { - e2FillType = m_SubjFillType; - e2FillType2 = m_ClipFillType; - } else - { - e2FillType = m_ClipFillType; - e2FillType2 = m_SubjFillType; - } - - cInt e1Wc, e2Wc; - switch (e1FillType) - { - case pftPositive: e1Wc = e1->WindCnt; break; - case pftNegative: e1Wc = -e1->WindCnt; break; - default: e1Wc = std::abs(e1->WindCnt); - } - switch(e2FillType) - { - case pftPositive: e2Wc = e2->WindCnt; break; - case pftNegative: e2Wc = -e2->WindCnt; break; - default: e2Wc = std::abs(e2->WindCnt); - } - - if ( e1Contributing && e2Contributing ) - { - if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || - (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) - { - AddLocalMaxPoly(e1, e2, Pt); - } - else - { - AddOutPt(e1, Pt); - AddOutPt(e2, Pt); - std::swap(e1->Side, e2->Side); - std::swap(e1->OutIdx, e2->OutIdx); - } - } - else if ( e1Contributing ) - { - if (e2Wc == 0 || e2Wc == 1) - { - AddOutPt(e1, Pt); - std::swap(e1->Side, e2->Side); - std::swap(e1->OutIdx, e2->OutIdx); - } - } - else if ( e2Contributing ) - { - if (e1Wc == 0 || e1Wc == 1) - { - AddOutPt(e2, Pt); - std::swap(e1->Side, e2->Side); - std::swap(e1->OutIdx, e2->OutIdx); - } - } - else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) - { - //neither edge is currently contributing ... - - cInt e1Wc2, e2Wc2; - switch (e1FillType2) - { - case pftPositive: e1Wc2 = e1->WindCnt2; break; - case pftNegative : e1Wc2 = -e1->WindCnt2; break; - default: e1Wc2 = std::abs(e1->WindCnt2); - } - switch (e2FillType2) - { - case pftPositive: e2Wc2 = e2->WindCnt2; break; - case pftNegative: e2Wc2 = -e2->WindCnt2; break; - default: e2Wc2 = std::abs(e2->WindCnt2); - } - - if (e1->PolyTyp != e2->PolyTyp) - { - AddLocalMinPoly(e1, e2, Pt); - } - else if (e1Wc == 1 && e2Wc == 1) - switch( m_ClipType ) { - case ctIntersection: - if (e1Wc2 > 0 && e2Wc2 > 0) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctUnion: - if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctDifference: - if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || - ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctXor: - AddLocalMinPoly(e1, e2, Pt); - } - else - std::swap(e1->Side, e2->Side); - } -} -//------------------------------------------------------------------------------ - -void Clipper::SetHoleState(TEdge *e, OutRec *outrec) -{ - TEdge *e2 = e->PrevInAEL; - TEdge *eTmp = 0; - while (e2) - { - if (e2->OutIdx >= 0 && e2->WindDelta != 0) - { - if (!eTmp) eTmp = e2; - else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0; - } - e2 = e2->PrevInAEL; - } - if (!eTmp) - { - outrec->FirstLeft = 0; - outrec->IsHole = false; - } - else - { - outrec->FirstLeft = &m_PolyOuts[eTmp->OutIdx]; - outrec->IsHole = !outrec->FirstLeft->IsHole; - } -} -//------------------------------------------------------------------------------ - -OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) -{ - //work out which polygon fragment has the correct hole state ... - if (!outRec1->BottomPt) - outRec1->BottomPt = GetBottomPt(outRec1->Pts); - if (!outRec2->BottomPt) - outRec2->BottomPt = GetBottomPt(outRec2->Pts); - OutPt *OutPt1 = outRec1->BottomPt; - OutPt *OutPt2 = outRec2->BottomPt; - if (OutPt1->Pt.y() > OutPt2->Pt.y()) return outRec1; - else if (OutPt1->Pt.y() < OutPt2->Pt.y()) return outRec2; - else if (OutPt1->Pt.x() < OutPt2->Pt.x()) return outRec1; - else if (OutPt1->Pt.x() > OutPt2->Pt.x()) return outRec2; - else if (OutPt1->Next == OutPt1) return outRec2; - else if (OutPt2->Next == OutPt2) return outRec1; - else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; - else return outRec2; -} -//------------------------------------------------------------------------------ - -bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2) -{ - do - { - outRec1 = outRec1->FirstLeft; - if (outRec1 == outRec2) return true; - } while (outRec1); - return false; -} -//------------------------------------------------------------------------------ - -OutRec* Clipper::GetOutRec(int Idx) -{ - OutRec* outrec = &m_PolyOuts[Idx]; - while (outrec != &m_PolyOuts[outrec->Idx]) - outrec = &m_PolyOuts[outrec->Idx]; - return outrec; -} -//------------------------------------------------------------------------------ - -void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) -{ - //get the start and ends of both output polygons ... - OutRec *outRec1 = &m_PolyOuts[e1->OutIdx]; - OutRec *outRec2 = &m_PolyOuts[e2->OutIdx]; - - OutRec *holeStateRec; - if (OutRec1RightOfOutRec2(outRec1, outRec2)) - holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) - holeStateRec = outRec1; - else - holeStateRec = GetLowermostRec(outRec1, outRec2); - - //get the start and ends of both output polygons and - //join e2 poly onto e1 poly and delete pointers to e2 ... - - OutPt* p1_lft = outRec1->Pts; - OutPt* p1_rt = p1_lft->Prev; - OutPt* p2_lft = outRec2->Pts; - OutPt* p2_rt = p2_lft->Prev; - - //join e2 poly onto e1 poly and delete pointers to e2 ... - if( e1->Side == esLeft ) - { - if( e2->Side == esLeft ) - { - //z y x a b c - ReversePolyPtLinks(p2_lft); - p2_lft->Next = p1_lft; - p1_lft->Prev = p2_lft; - p1_rt->Next = p2_rt; - p2_rt->Prev = p1_rt; - outRec1->Pts = p2_rt; - } else - { - //x y z a b c - p2_rt->Next = p1_lft; - p1_lft->Prev = p2_rt; - p2_lft->Prev = p1_rt; - p1_rt->Next = p2_lft; - outRec1->Pts = p2_lft; - } - } else - { - if( e2->Side == esRight ) - { - //a b c z y x - ReversePolyPtLinks(p2_lft); - p1_rt->Next = p2_rt; - p2_rt->Prev = p1_rt; - p2_lft->Next = p1_lft; - p1_lft->Prev = p2_lft; - } else - { - //a b c x y z - p1_rt->Next = p2_lft; - p2_lft->Prev = p1_rt; - p1_lft->Prev = p2_rt; - p2_rt->Next = p1_lft; - } - } - - outRec1->BottomPt = 0; - if (holeStateRec == outRec2) - { - if (outRec2->FirstLeft != outRec1) - outRec1->FirstLeft = outRec2->FirstLeft; - outRec1->IsHole = outRec2->IsHole; - } - outRec2->Pts = 0; - outRec2->BottomPt = 0; - outRec2->FirstLeft = outRec1; - - int OKIdx = e1->OutIdx; - int ObsoleteIdx = e2->OutIdx; - - e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly - e2->OutIdx = Unassigned; - - TEdge* e = m_ActiveEdges; - while( e ) - { - if( e->OutIdx == ObsoleteIdx ) - { - e->OutIdx = OKIdx; - e->Side = e1->Side; - break; - } - e = e->NextInAEL; - } - - outRec2->Idx = outRec1->Idx; -} -//------------------------------------------------------------------------------ - -OutRec* Clipper::CreateOutRec() -{ - m_PolyOuts.emplace_back(); - OutRec &result = m_PolyOuts.back(); - result.IsHole = false; - result.IsOpen = false; - result.FirstLeft = 0; - result.Pts = 0; - result.BottomPt = 0; - result.PolyNd = 0; - result.Idx = (int)m_PolyOuts.size()-1; - return &result; -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) -{ - if( e->OutIdx < 0 ) - { - OutRec *outRec = CreateOutRec(); - outRec->IsOpen = (e->WindDelta == 0); - OutPt* newOp = this->AllocateOutPt(); - outRec->Pts = newOp; - newOp->Idx = outRec->Idx; - newOp->Pt = pt; - newOp->Next = newOp; - newOp->Prev = newOp; - if (!outRec->IsOpen) - SetHoleState(e, outRec); - e->OutIdx = outRec->Idx; - return newOp; - } else - { - OutRec *outRec = &m_PolyOuts[e->OutIdx]; - //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' - OutPt* op = outRec->Pts; - - bool ToFront = (e->Side == esLeft); - if (ToFront && (pt == op->Pt)) return op; - else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; - - OutPt* newOp = this->AllocateOutPt(); - newOp->Idx = outRec->Idx; - newOp->Pt = pt; - newOp->Next = op; - newOp->Prev = op->Prev; - newOp->Prev->Next = newOp; - op->Prev = newOp; - if (ToFront) outRec->Pts = newOp; - return newOp; - } -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::GetLastOutPt(TEdge *e) -{ - OutRec *outRec = &m_PolyOuts[e->OutIdx]; - if (e->Side == esLeft) - return outRec->Pts; - else - return outRec->Pts->Prev; -} -//------------------------------------------------------------------------------ - -void Clipper::ProcessHorizontals() -{ - TEdge* horzEdge = m_SortedEdges; - while(horzEdge) - { - DeleteFromSEL(horzEdge); - ProcessHorizontal(horzEdge); - horzEdge = m_SortedEdges; - } -} -//------------------------------------------------------------------------------ - -inline bool IsMaxima(TEdge *e, const cInt Y) -{ - return e && e->Top.y() == Y && !e->NextInLML; -} -//------------------------------------------------------------------------------ - -inline bool IsIntermediate(TEdge *e, const cInt Y) -{ - return e->Top.y() == Y && e->NextInLML; -} -//------------------------------------------------------------------------------ - -inline TEdge *GetMaximaPair(TEdge *e) -{ - if ((e->Next->Top == e->Top) && !e->Next->NextInLML) - return e->Next; - else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) - return e->Prev; - else return 0; -} -//------------------------------------------------------------------------------ - -inline TEdge *GetMaximaPairEx(TEdge *e) -{ - //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal) - TEdge* result = GetMaximaPair(e); - if (result && (result->OutIdx == Skip || - (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0; - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) -{ - //check that one or other edge hasn't already been removed from AEL ... - if (Edge1->NextInAEL == Edge1->PrevInAEL || - Edge2->NextInAEL == Edge2->PrevInAEL) return; - - if( Edge1->NextInAEL == Edge2 ) - { - TEdge* Next = Edge2->NextInAEL; - if( Next ) Next->PrevInAEL = Edge1; - TEdge* Prev = Edge1->PrevInAEL; - if( Prev ) Prev->NextInAEL = Edge2; - Edge2->PrevInAEL = Prev; - Edge2->NextInAEL = Edge1; - Edge1->PrevInAEL = Edge2; - Edge1->NextInAEL = Next; - } - else if( Edge2->NextInAEL == Edge1 ) - { - TEdge* Next = Edge1->NextInAEL; - if( Next ) Next->PrevInAEL = Edge2; - TEdge* Prev = Edge2->PrevInAEL; - if( Prev ) Prev->NextInAEL = Edge1; - Edge1->PrevInAEL = Prev; - Edge1->NextInAEL = Edge2; - Edge2->PrevInAEL = Edge1; - Edge2->NextInAEL = Next; - } - else - { - TEdge* Next = Edge1->NextInAEL; - TEdge* Prev = Edge1->PrevInAEL; - Edge1->NextInAEL = Edge2->NextInAEL; - if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1; - Edge1->PrevInAEL = Edge2->PrevInAEL; - if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1; - Edge2->NextInAEL = Next; - if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2; - Edge2->PrevInAEL = Prev; - if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2; - } - - if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1; - else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2; -} -//------------------------------------------------------------------------------ - -void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) -{ - if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; - if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; - - if( Edge1->NextInSEL == Edge2 ) - { - TEdge* Next = Edge2->NextInSEL; - if( Next ) Next->PrevInSEL = Edge1; - TEdge* Prev = Edge1->PrevInSEL; - if( Prev ) Prev->NextInSEL = Edge2; - Edge2->PrevInSEL = Prev; - Edge2->NextInSEL = Edge1; - Edge1->PrevInSEL = Edge2; - Edge1->NextInSEL = Next; - } - else if( Edge2->NextInSEL == Edge1 ) - { - TEdge* Next = Edge1->NextInSEL; - if( Next ) Next->PrevInSEL = Edge2; - TEdge* Prev = Edge2->PrevInSEL; - if( Prev ) Prev->NextInSEL = Edge1; - Edge1->PrevInSEL = Prev; - Edge1->NextInSEL = Edge2; - Edge2->PrevInSEL = Edge1; - Edge2->NextInSEL = Next; - } - else - { - TEdge* Next = Edge1->NextInSEL; - TEdge* Prev = Edge1->PrevInSEL; - Edge1->NextInSEL = Edge2->NextInSEL; - if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; - Edge1->PrevInSEL = Edge2->PrevInSEL; - if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; - Edge2->NextInSEL = Next; - if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; - Edge2->PrevInSEL = Prev; - if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; - } - - if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; - else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; -} -//------------------------------------------------------------------------------ - -inline void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) -{ - if (HorzEdge.Bot.x() < HorzEdge.Top.x()) - { - Left = HorzEdge.Bot.x(); - Right = HorzEdge.Top.x(); - Dir = dLeftToRight; - } else - { - Left = HorzEdge.Top.x(); - Right = HorzEdge.Bot.x(); - Dir = dRightToLeft; - } -} -//------------------------------------------------------------------------ - -/******************************************************************************* -* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * -* Bottom of a scanbeam) are processed as if layered. The order in which HEs * -* are processed doesn't matter. HEs intersect with other HE Bot.x()s only [#] * -* (or they could intersect with Top.x()s only, ie EITHER Bot.x()s OR Top.x()s), * -* and with other non-horizontal edges [*]. Once these intersections are * -* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * -* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * -*******************************************************************************/ - -void Clipper::ProcessHorizontal(TEdge *horzEdge) -{ - Direction dir; - cInt horzLeft, horzRight; - bool IsOpen = (horzEdge->WindDelta == 0); - - GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); - - TEdge* eLastHorz = horzEdge, *eMaxPair = 0; - while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) - eLastHorz = eLastHorz->NextInLML; - if (!eLastHorz->NextInLML) - eMaxPair = GetMaximaPair(eLastHorz); - - cInts::const_iterator maxIt; - cInts::const_reverse_iterator maxRit; - if (!m_Maxima.empty()) - { - //get the first maxima in range (X) ... - if (dir == dLeftToRight) - { - maxIt = m_Maxima.begin(); - while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.x()) ++maxIt; - if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.x()) - maxIt = m_Maxima.end(); - } - else - { - maxRit = m_Maxima.rbegin(); - while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.x()) ++maxRit; - if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.x()) - maxRit = m_Maxima.rend(); - } - } - - OutPt* op1 = 0; - - for (;;) //loop through consec. horizontal edges - { - - bool IsLastHorz = (horzEdge == eLastHorz); - TEdge* e = (dir == dLeftToRight) ? horzEdge->NextInAEL : horzEdge->PrevInAEL; - while(e) - { - - //this code block inserts extra coords into horizontal edges (in output - //polygons) whereever maxima touch these horizontal edges. This helps - //'simplifying' polygons (ie if the Simplify property is set). - if (!m_Maxima.empty()) - { - if (dir == dLeftToRight) - { - while (maxIt != m_Maxima.end() && *maxIt < e->Curr.x()) - { - if (horzEdge->OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, IntPoint2d(*maxIt, horzEdge->Bot.y())); - ++maxIt; - } - } - else - { - while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.x()) - { - if (horzEdge->OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, IntPoint2d(*maxRit, horzEdge->Bot.y())); - ++maxRit; - } - } - }; - - if ((dir == dLeftToRight && e->Curr.x() > horzRight) || - (dir == dRightToLeft && e->Curr.x() < horzLeft)) break; - - //Also break if we've got to the end of an intermediate horizontal edge ... - //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. - if (e->Curr.x() == horzEdge->Top.x() && horzEdge->NextInLML && - e->Dx < horzEdge->NextInLML->Dx) break; - - if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times - { -#ifdef CLIPPERLIB_USE_XYZ - if (dir == dLeftToRight) - SetZ(e->Curr, *horzEdge, *e); - else - SetZ(e->Curr, *e, *horzEdge); -#endif - op1 = AddOutPt(horzEdge, e->Curr); - TEdge* eNextHorz = m_SortedEdges; - while (eNextHorz) - { - if (eNextHorz->OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge->Bot.x(), - horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x())) - { - OutPt* op2 = GetLastOutPt(eNextHorz); - m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top)); - } - eNextHorz = eNextHorz->NextInSEL; - } - m_GhostJoins.emplace_back(Join(op1, 0, horzEdge->Bot)); - } - - //OK, so far we're still in range of the horizontal Edge but make sure - //we're at the last of consec. horizontals when matching with eMaxPair - if(e == eMaxPair && IsLastHorz) - { - if (horzEdge->OutIdx >= 0) - AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top); - DeleteFromAEL(horzEdge); - DeleteFromAEL(eMaxPair); - return; - } - - if(dir == dLeftToRight) - { - IntPoint Pt = IntPoint2d(e->Curr.x(), horzEdge->Curr.y()); - IntersectEdges(horzEdge, e, Pt); - } - else - { - IntPoint Pt = IntPoint2d(e->Curr.x(), horzEdge->Curr.y()); - IntersectEdges( e, horzEdge, Pt); - } - TEdge* eNext = (dir == dLeftToRight) ? e->NextInAEL : e->PrevInAEL; - SwapPositionsInAEL( horzEdge, e ); - e = eNext; - } //end while(e) - - //Break out of loop if HorzEdge.NextInLML is not also horizontal ... - if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break; - - UpdateEdgeIntoAEL(horzEdge); - if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); - GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); - - } //end for (;;) - - if (horzEdge->OutIdx >= 0 && !op1) - { - op1 = GetLastOutPt(horzEdge); - TEdge* eNextHorz = m_SortedEdges; - while (eNextHorz) - { - if (eNextHorz->OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge->Bot.x(), - horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x())) - { - OutPt* op2 = GetLastOutPt(eNextHorz); - m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top)); - } - eNextHorz = eNextHorz->NextInSEL; - } - m_GhostJoins.emplace_back(Join(op1, 0, horzEdge->Top)); - } - - if (horzEdge->NextInLML) - { - if(horzEdge->OutIdx >= 0) - { - op1 = AddOutPt( horzEdge, horzEdge->Top); - UpdateEdgeIntoAEL(horzEdge); - if (horzEdge->WindDelta == 0) return; - //nb: HorzEdge is no longer horizontal here - TEdge* ePrev = horzEdge->PrevInAEL; - TEdge* eNext = horzEdge->NextInAEL; - if (ePrev && ePrev->Curr.x() == horzEdge->Bot.x() && - ePrev->Curr.y() == horzEdge->Bot.y() && ePrev->WindDelta != 0 && - (ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() && - SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) - { - OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); - m_Joins.emplace_back(Join(op1, op2, horzEdge->Top)); - } - else if (eNext && eNext->Curr.x() == horzEdge->Bot.x() && - eNext->Curr.y() == horzEdge->Bot.y() && eNext->WindDelta != 0 && - eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() && - SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) - { - OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); - m_Joins.emplace_back(Join(op1, op2, horzEdge->Top)); - } - } - else - UpdateEdgeIntoAEL(horzEdge); - } - else - { - if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); - DeleteFromAEL(horzEdge); - } -} -//------------------------------------------------------------------------------ - -void Clipper::UpdateEdgeIntoAEL(TEdge *&e) -{ - if( !e->NextInLML ) - throw clipperException("UpdateEdgeIntoAEL: invalid call"); - - e->NextInLML->OutIdx = e->OutIdx; - TEdge* AelPrev = e->PrevInAEL; - TEdge* AelNext = e->NextInAEL; - if (AelPrev) AelPrev->NextInAEL = e->NextInLML; - else m_ActiveEdges = e->NextInLML; - if (AelNext) AelNext->PrevInAEL = e->NextInLML; - e->NextInLML->Side = e->Side; - e->NextInLML->WindDelta = e->WindDelta; - e->NextInLML->WindCnt = e->WindCnt; - e->NextInLML->WindCnt2 = e->WindCnt2; - e = e->NextInLML; - e->Curr = e->Bot; - e->PrevInAEL = AelPrev; - e->NextInAEL = AelNext; - if (!IsHorizontal(*e)) - m_Scanbeam.push(e->Top.y()); -} -//------------------------------------------------------------------------------ - -bool Clipper::ProcessIntersections(const cInt topY) -{ - if( !m_ActiveEdges ) return true; - try { - BuildIntersectList(topY); - size_t IlSize = m_IntersectList.size(); - if (IlSize == 0) return true; - if (IlSize == 1 || FixupIntersectionOrder()) { - for (IntersectNode &iNode : m_IntersectList) { - IntersectEdges( iNode.Edge1, iNode.Edge2, iNode.Pt); - SwapPositionsInAEL( iNode.Edge1 , iNode.Edge2 ); - } - m_IntersectList.clear(); - } - else return false; - } - catch(...) - { - m_SortedEdges = 0; - m_IntersectList.clear(); - throw clipperException("ProcessIntersections error"); - } - m_SortedEdges = 0; - return true; -} -//------------------------------------------------------------------------------ - -void Clipper::BuildIntersectList(const cInt topY) -{ - if ( !m_ActiveEdges ) return; - - //prepare for sorting ... - TEdge* e = m_ActiveEdges; - m_SortedEdges = e; - while( e ) - { - e->PrevInSEL = e->PrevInAEL; - e->NextInSEL = e->NextInAEL; - e->Curr.x() = TopX( *e, topY ); - e = e->NextInAEL; - } - - //bubblesort ... - bool isModified; - do - { - isModified = false; - e = m_SortedEdges; - while( e->NextInSEL ) - { - TEdge *eNext = e->NextInSEL; - IntPoint Pt; - if(e->Curr.x() > eNext->Curr.x()) - { - IntersectPoint(*e, *eNext, Pt); - - if (Pt.y() < topY) Pt = IntPoint2d(TopX(*e, topY), topY); - m_IntersectList.emplace_back(IntersectNode(e, eNext, Pt)); - SwapPositionsInSEL(e, eNext); - isModified = true; - } - else - e = eNext; - } - if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; - else break; - } - while ( isModified ); - m_SortedEdges = 0; //important -} -//------------------------------------------------------------------------------ - - -inline bool EdgesAdjacent(const IntersectNode &inode) -{ - return (inode.Edge1->NextInSEL == inode.Edge2) || - (inode.Edge1->PrevInSEL == inode.Edge2); -} -//------------------------------------------------------------------------------ - -bool Clipper::FixupIntersectionOrder() -{ - //pre-condition: intersections are sorted Bottom-most first. - //Now it's crucial that intersections are made only between adjacent edges, - //so to ensure this the order of intersections may need adjusting ... - CopyAELToSEL(); - std::sort(m_IntersectList.begin(), m_IntersectList.end(), [](const IntersectNode &node1, const IntersectNode &node2) { return node2.Pt.y() < node1.Pt.y(); }); - - size_t cnt = m_IntersectList.size(); - for (size_t i = 0; i < cnt; ++i) - { - if (!EdgesAdjacent(m_IntersectList[i])) - { - size_t j = i + 1; - while (j < cnt && !EdgesAdjacent(m_IntersectList[j])) j++; - if (j == cnt) return false; - std::swap(m_IntersectList[i], m_IntersectList[j]); - } - SwapPositionsInSEL(m_IntersectList[i].Edge1, m_IntersectList[i].Edge2); - } - return true; -} -//------------------------------------------------------------------------------ - -void Clipper::DoMaxima(TEdge *e) -{ - TEdge* eMaxPair = GetMaximaPairEx(e); - if (!eMaxPair) - { - if (e->OutIdx >= 0) - AddOutPt(e, e->Top); - DeleteFromAEL(e); - return; - } - - TEdge* eNext = e->NextInAEL; - while(eNext && eNext != eMaxPair) - { - IntersectEdges(e, eNext, e->Top); - SwapPositionsInAEL(e, eNext); - eNext = e->NextInAEL; - } - - if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) - { - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } - else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) - { - if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top); - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } -#ifdef use_lines - else if (e->WindDelta == 0) - { - if (e->OutIdx >= 0) - { - AddOutPt(e, e->Top); - e->OutIdx = Unassigned; - } - DeleteFromAEL(e); - - if (eMaxPair->OutIdx >= 0) - { - AddOutPt(eMaxPair, e->Top); - eMaxPair->OutIdx = Unassigned; - } - DeleteFromAEL(eMaxPair); - } -#endif - else throw clipperException("DoMaxima error"); -} -//------------------------------------------------------------------------------ - -void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) -{ - TEdge* e = m_ActiveEdges; - while( e ) - { - //1. process maxima, treating them as if they're 'bent' horizontal edges, - // but exclude maxima with horizontal edges. nb: e can't be a horizontal. - bool IsMaximaEdge = IsMaxima(e, topY); - - if(IsMaximaEdge) - { - TEdge* eMaxPair = GetMaximaPairEx(e); - IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); - } - - if(IsMaximaEdge) - { - if (m_StrictSimple) m_Maxima.emplace_back(e->Top.x()); - TEdge* ePrev = e->PrevInAEL; - DoMaxima(e); - if( !ePrev ) e = m_ActiveEdges; - else e = ePrev->NextInAEL; - } - else - { - //2. promote horizontal edges, otherwise update Curr.x() and Curr.y() ... - if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) - { - UpdateEdgeIntoAEL(e); - if (e->OutIdx >= 0) - AddOutPt(e, e->Bot); - AddEdgeToSEL(e); - } - else - { - e->Curr.x() = TopX( *e, topY ); - e->Curr.y() = topY; -#ifdef CLIPPERLIB_USE_XYZ - e->Curr.z() = topY == e->Top.y() ? e->Top.z() : (topY == e->Bot.y() ? e->Bot.z() : 0); -#endif - } - - //When StrictlySimple and 'e' is being touched by another edge, then - //make sure both edges have a vertex here ... - if (m_StrictSimple) - { - TEdge* ePrev = e->PrevInAEL; - if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && - (ePrev->Curr.x() == e->Curr.x()) && (ePrev->WindDelta != 0)) - { - IntPoint pt = e->Curr; -#ifdef CLIPPERLIB_USE_XYZ - SetZ(pt, *ePrev, *e); -#endif - OutPt* op = AddOutPt(ePrev, pt); - OutPt* op2 = AddOutPt(e, pt); - m_Joins.emplace_back(Join(op, op2, pt)); //StrictlySimple (type-3) join - } - } - - e = e->NextInAEL; - } - } - - //3. Process horizontals at the Top of the scanbeam ... - std::sort(m_Maxima.begin(), m_Maxima.end()); - ProcessHorizontals(); - m_Maxima.clear(); - - //4. Promote intermediate vertices ... - e = m_ActiveEdges; - while(e) - { - if(IsIntermediate(e, topY)) - { - OutPt* op = 0; - if( e->OutIdx >= 0 ) - op = AddOutPt(e, e->Top); - UpdateEdgeIntoAEL(e); - - //if output polygons share an edge, they'll need joining later ... - TEdge* ePrev = e->PrevInAEL; - TEdge* eNext = e->NextInAEL; - if (ePrev && ePrev->Curr.x() == e->Bot.x() && - ePrev->Curr.y() == e->Bot.y() && op && - ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() && - SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) && - (e->WindDelta != 0) && (ePrev->WindDelta != 0)) - { - OutPt* op2 = AddOutPt(ePrev, e->Bot); - m_Joins.emplace_back(Join(op, op2, e->Top)); - } - else if (eNext && eNext->Curr.x() == e->Bot.x() && - eNext->Curr.y() == e->Bot.y() && op && - eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() && - SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) && - (e->WindDelta != 0) && (eNext->WindDelta != 0)) - { - OutPt* op2 = AddOutPt(eNext, e->Bot); - m_Joins.emplace_back(Join(op, op2, e->Top)); - } - } - e = e->NextInAEL; - } -} -//------------------------------------------------------------------------------ - -void Clipper::FixupOutPolyline(OutRec &outrec) -{ - OutPt *pp = outrec.Pts; - OutPt *lastPP = pp->Prev; - while (pp != lastPP) - { - pp = pp->Next; - if (pp->Pt == pp->Prev->Pt) - { - if (pp == lastPP) lastPP = pp->Prev; - OutPt *tmpPP = pp->Prev; - tmpPP->Next = pp->Next; - pp->Next->Prev = tmpPP; - this->DisposeOutPt(pp); - pp = tmpPP; - } - } - - if (pp == pp->Prev) - { - this->DisposeOutPts(pp); - outrec.Pts = 0; - return; - } -} -//------------------------------------------------------------------------------ - -void Clipper::FixupOutPolygon(OutRec &outrec) -{ - //FixupOutPolygon() - removes duplicate points and simplifies consecutive - //parallel edges by removing the middle vertex. - OutPt *lastOK = nullptr; - outrec.BottomPt = nullptr; - OutPt *pp = outrec.Pts; - bool preserveCol = m_PreserveCollinear || m_StrictSimple; - - for (;;) - { - if (pp->Prev == pp || pp->Prev == pp->Next) - { - // Empty loop or a stick. Release the polygon. - this->DisposeOutPts(pp); - outrec.Pts = nullptr; - return; - } - - //test for duplicate points and collinear edges ... - if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || - (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && - (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) - { - lastOK = nullptr; - OutPt *tmp = pp; - pp->Prev->Next = pp->Next; - pp->Next->Prev = pp->Prev; - pp = pp->Prev; - this->DisposeOutPt(tmp); - } - else if (pp == lastOK) break; - else - { - if (!lastOK) lastOK = pp; - pp = pp->Next; - } - } - outrec.Pts = pp; -} -//------------------------------------------------------------------------------ - -// Count the number of points in a closed linked loop starting with Pts. -int PointCount(OutPt *Pts) -{ - if (!Pts) return 0; - int result = 0; - OutPt* p = Pts; - do - { - result++; - p = p->Next; - } - while (p != Pts); - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::BuildResult(Paths &polys) -{ - polys.reserve(m_PolyOuts.size()); - for (OutRec &outRec : m_PolyOuts) - { - assert(! outRec.IsOpen); - if (!outRec.Pts) continue; - Path pg; - OutPt* p = outRec.Pts->Prev; - int cnt = PointCount(p); - if (cnt < 2) continue; - pg.reserve(cnt); - for (int i = 0; i < cnt; ++i) - { - pg.emplace_back(p->Pt); - p = p->Prev; - } - polys.emplace_back(std::move(pg)); - } -} -//------------------------------------------------------------------------------ - -void Clipper::BuildResult2(PolyTree& polytree) -{ - polytree.Clear(); - polytree.AllNodes.reserve(m_PolyOuts.size()); - //add each output polygon/contour to polytree ... - for (OutRec &outRec : m_PolyOuts) - { - int cnt = PointCount(outRec.Pts); - if ((outRec.IsOpen && cnt < 2) || (!outRec.IsOpen && cnt < 3)) - // Ignore an invalid output loop or a polyline. - continue; - - //skip OutRecs that (a) contain outermost polygons or - //(b) already have the correct owner/child linkage ... - if (outRec.FirstLeft && - (outRec.IsHole == outRec.FirstLeft->IsHole || ! outRec.FirstLeft->Pts)) { - OutRec* orfl = outRec.FirstLeft; - while (orfl && ((orfl->IsHole == outRec.IsHole) || !orfl->Pts)) - orfl = orfl->FirstLeft; - outRec.FirstLeft = orfl; - } - - //nb: polytree takes ownership of all the PolyNodes - polytree.AllNodes.emplace_back(PolyNode()); - PolyNode* pn = &polytree.AllNodes.back(); - outRec.PolyNd = pn; - pn->Parent = 0; - pn->Index = 0; - pn->Contour.reserve(cnt); - OutPt *op = outRec.Pts->Prev; - for (int j = 0; j < cnt; j++) - { - pn->Contour.emplace_back(op->Pt); - op = op->Prev; - } - } - - //fixup PolyNode links etc ... - polytree.Childs.reserve(m_PolyOuts.size()); - for (OutRec &outRec : m_PolyOuts) - { - if (!outRec.PolyNd) continue; - if (outRec.IsOpen) - { - outRec.PolyNd->m_IsOpen = true; - polytree.AddChild(*outRec.PolyNd); - } - else if (outRec.FirstLeft && outRec.FirstLeft->PolyNd) - outRec.FirstLeft->PolyNd->AddChild(*outRec.PolyNd); - else - polytree.AddChild(*outRec.PolyNd); - } -} -//------------------------------------------------------------------------------ - -inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) -{ - if (e2.Curr.x() == e1.Curr.x()) - { - if (e2.Top.y() > e1.Top.y()) - return e2.Top.x() < TopX(e1, e2.Top.y()); - else return e1.Top.x() > TopX(e2, e1.Top.y()); - } - else return e2.Curr.x() < e1.Curr.x(); -} -//------------------------------------------------------------------------------ - -bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, - cInt& Left, cInt& Right) -{ - if (a1 < a2) - { - if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} - else {Left = std::max(a1,b2); Right = std::min(a2,b1);} - } - else - { - if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} - else {Left = std::max(a2,b2); Right = std::min(a1,b1);} - } - return Left < Right; -} -//------------------------------------------------------------------------------ - -// Make all points of outrec point to outrec.Idx -inline void UpdateOutPtIdxs(OutRec& outrec) -{ - OutPt* op = outrec.Pts; - do - { - op->Idx = outrec.Idx; - op = op->Prev; - } - while(op != outrec.Pts); -} -//------------------------------------------------------------------------------ - -void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) -{ - if(!m_ActiveEdges) - { - edge->PrevInAEL = 0; - edge->NextInAEL = 0; - m_ActiveEdges = edge; - } - else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) - { - edge->PrevInAEL = 0; - edge->NextInAEL = m_ActiveEdges; - m_ActiveEdges->PrevInAEL = edge; - m_ActiveEdges = edge; - } - else - { - if(!startEdge) startEdge = m_ActiveEdges; - while(startEdge->NextInAEL && - !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) - startEdge = startEdge->NextInAEL; - edge->NextInAEL = startEdge->NextInAEL; - if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; - edge->PrevInAEL = startEdge; - startEdge->NextInAEL = edge; - } -} -//---------------------------------------------------------------------- - -OutPt* Clipper::DupOutPt(OutPt* outPt, bool InsertAfter) -{ - OutPt* result = this->AllocateOutPt(); - result->Pt = outPt->Pt; - result->Idx = outPt->Idx; - if (InsertAfter) - { - result->Next = outPt->Next; - result->Prev = outPt; - outPt->Next->Prev = result; - outPt->Next = result; - } - else - { - result->Prev = outPt->Prev; - result->Next = outPt; - outPt->Prev->Next = result; - outPt->Prev = result; - } - return result; -} -//------------------------------------------------------------------------------ - -bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, - const IntPoint &Pt, bool DiscardLeft) -{ - Direction Dir1 = (op1->Pt.x() > op1b->Pt.x() ? dRightToLeft : dLeftToRight); - Direction Dir2 = (op2->Pt.x() > op2b->Pt.x() ? dRightToLeft : dLeftToRight); - if (Dir1 == Dir2) return false; - - //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we - //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) - //So, to facilitate this while inserting Op1b and Op2b ... - //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, - //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) - if (Dir1 == dLeftToRight) - { - while (op1->Next->Pt.x() <= Pt.x() && - op1->Next->Pt.x() >= op1->Pt.x() && op1->Next->Pt.y() == Pt.y()) - op1 = op1->Next; - if (DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next; - op1b = this->DupOutPt(op1, !DiscardLeft); - if (op1b->Pt != Pt) - { - op1 = op1b; - op1->Pt = Pt; - op1b = this->DupOutPt(op1, !DiscardLeft); - } - } - else - { - while (op1->Next->Pt.x() >= Pt.x() && - op1->Next->Pt.x() <= op1->Pt.x() && op1->Next->Pt.y() == Pt.y()) - op1 = op1->Next; - if (!DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next; - op1b = this->DupOutPt(op1, DiscardLeft); - if (op1b->Pt != Pt) - { - op1 = op1b; - op1->Pt = Pt; - op1b = this->DupOutPt(op1, DiscardLeft); - } - } - - if (Dir2 == dLeftToRight) - { - while (op2->Next->Pt.x() <= Pt.x() && - op2->Next->Pt.x() >= op2->Pt.x() && op2->Next->Pt.y() == Pt.y()) - op2 = op2->Next; - if (DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next; - op2b = this->DupOutPt(op2, !DiscardLeft); - if (op2b->Pt != Pt) - { - op2 = op2b; - op2->Pt = Pt; - op2b = this->DupOutPt(op2, !DiscardLeft); - }; - } else - { - while (op2->Next->Pt.x() >= Pt.x() && - op2->Next->Pt.x() <= op2->Pt.x() && op2->Next->Pt.y() == Pt.y()) - op2 = op2->Next; - if (!DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next; - op2b = this->DupOutPt(op2, DiscardLeft); - if (op2b->Pt != Pt) - { - op2 = op2b; - op2->Pt = Pt; - op2b = this->DupOutPt(op2, DiscardLeft); - }; - }; - - if ((Dir1 == dLeftToRight) == DiscardLeft) - { - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - } - else - { - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - } - return true; -} -//------------------------------------------------------------------------------ - -bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) -{ - OutPt *op1 = j->OutPt1, *op1b; - OutPt *op2 = j->OutPt2, *op2b; - - //There are 3 kinds of joins for output polygons ... - //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere - //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). - //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same - //location at the Bottom of the overlapping segment (& Join.OffPt is above). - //3. StrictSimple joins where edges touch but are not collinear and where - //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. - bool isHorizontal = (j->OutPt1->Pt.y() == j->OffPt.y()); - - if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && - (j->OffPt == j->OutPt2->Pt)) - { - //Strictly Simple join ... - if (outRec1 != outRec2) return false; - op1b = j->OutPt1->Next; - while (op1b != op1 && (op1b->Pt == j->OffPt)) - op1b = op1b->Next; - bool reverse1 = (op1b->Pt.y() > j->OffPt.y()); - op2b = j->OutPt2->Next; - while (op2b != op2 && (op2b->Pt == j->OffPt)) - op2b = op2b->Next; - bool reverse2 = (op2b->Pt.y() > j->OffPt.y()); - if (reverse1 == reverse2) return false; - if (reverse1) - { - op1b = this->DupOutPt(op1, false); - op2b = this->DupOutPt(op2, true); - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } else - { - op1b = this->DupOutPt(op1, true); - op2b = this->DupOutPt(op2, false); - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } - } - else if (isHorizontal) - { - //treat horizontal joins differently to non-horizontal joins since with - //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt - //may be anywhere along the horizontal edge. - op1b = op1; - while (op1->Prev->Pt.y() == op1->Pt.y() && op1->Prev != op1b && op1->Prev != op2) - op1 = op1->Prev; - while (op1b->Next->Pt.y() == op1b->Pt.y() && op1b->Next != op1 && op1b->Next != op2) - op1b = op1b->Next; - if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' - - op2b = op2; - while (op2->Prev->Pt.y() == op2->Pt.y() && op2->Prev != op2b && op2->Prev != op1b) - op2 = op2->Prev; - while (op2b->Next->Pt.y() == op2b->Pt.y() && op2b->Next != op2 && op2b->Next != op1) - op2b = op2b->Next; - if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' - - cInt Left, Right; - //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges - if (!GetOverlap(op1->Pt.x(), op1b->Pt.x(), op2->Pt.x(), op2b->Pt.x(), Left, Right)) - return false; - - //DiscardLeftSide: when overlapping edges are joined, a spike will created - //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up - //on the discard Side as either may still be needed for other joins ... - IntPoint Pt; - bool DiscardLeftSide; - if (op1->Pt.x() >= Left && op1->Pt.x() <= Right) - { - Pt = op1->Pt; DiscardLeftSide = (op1->Pt.x() > op1b->Pt.x()); - } - else if (op2->Pt.x() >= Left&& op2->Pt.x() <= Right) - { - Pt = op2->Pt; DiscardLeftSide = (op2->Pt.x() > op2b->Pt.x()); - } - else if (op1b->Pt.x() >= Left && op1b->Pt.x() <= Right) - { - Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.x() > op1->Pt.x(); - } - else - { - Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.x() > op2->Pt.x()); - } - j->OutPt1 = op1; j->OutPt2 = op2; - return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); - } else - { - //nb: For non-horizontal joins ... - // 1. Jr.OutPt1.Pt.y() == Jr.OutPt2.Pt.y() - // 2. Jr.OutPt1.Pt > Jr.OffPt.y() - - //make sure the polygons are correctly oriented ... - op1b = op1->Next; - while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; - bool Reverse1 = ((op1b->Pt.y() > op1->Pt.y()) || - !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); - if (Reverse1) - { - op1b = op1->Prev; - while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; - if ((op1b->Pt.y() > op1->Pt.y()) || - !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; - }; - op2b = op2->Next; - while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; - bool Reverse2 = ((op2b->Pt.y() > op2->Pt.y()) || - !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); - if (Reverse2) - { - op2b = op2->Prev; - while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; - if ((op2b->Pt.y() > op2->Pt.y()) || - !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; - } - - if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || - ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; - - if (Reverse1) - { - op1b = this->DupOutPt(op1, false); - op2b = this->DupOutPt(op2, true); - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } else - { - op1b = this->DupOutPt(op1, true); - op2b = this->DupOutPt(op2, false); - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } - } -} -//---------------------------------------------------------------------- - -inline OutRec* ParseFirstLeft(OutRec* FirstLeft) -{ - while (FirstLeft && !FirstLeft->Pts) - FirstLeft = FirstLeft->FirstLeft; - return FirstLeft; -} -//------------------------------------------------------------------------------ - -// This is potentially very expensive! O(n^3)! -void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) -{ - //tests if NewOutRec contains the polygon before reassigning FirstLeft - for (OutRec &outRec : m_PolyOuts) - { - OutRec* firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts && firstLeft == OldOutRec && Poly2ContainsPoly1(outRec.Pts, NewOutRec->Pts)) - outRec.FirstLeft = NewOutRec; - } -} -//---------------------------------------------------------------------- - -void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec) -{ - //A polygon has split into two such that one is now the inner of the other. - //It's possible that these polygons now wrap around other polygons, so check - //every polygon that's also contained by OuterOutRec's FirstLeft container - //(including 0) to see if they've become inner to the new inner polygon ... - OutRec* orfl = OuterOutRec->FirstLeft; - for (OutRec &outRec : m_PolyOuts) - { - if (!outRec.Pts || &outRec == OuterOutRec || &outRec == InnerOutRec) - continue; - OutRec* firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec) - continue; - if (Poly2ContainsPoly1(outRec.Pts, InnerOutRec->Pts)) - outRec.FirstLeft = InnerOutRec; - else if (Poly2ContainsPoly1(outRec.Pts, OuterOutRec->Pts)) - outRec.FirstLeft = OuterOutRec; - else if (outRec.FirstLeft == InnerOutRec || outRec.FirstLeft == OuterOutRec) - outRec.FirstLeft = orfl; - } -} -//---------------------------------------------------------------------- -void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec) -{ - //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon - for (OutRec &outRec : m_PolyOuts) - { - OutRec* firstLeft = ParseFirstLeft(outRec.FirstLeft); - if (outRec.Pts && firstLeft == OldOutRec) - outRec.FirstLeft = NewOutRec; - } -} -//---------------------------------------------------------------------- - -void Clipper::JoinCommonEdges() -{ - for (Join &join : m_Joins) - { - OutRec *outRec1 = GetOutRec(join.OutPt1->Idx); - OutRec *outRec2 = GetOutRec(join.OutPt2->Idx); - - if (!outRec1->Pts || !outRec2->Pts) continue; - if (outRec1->IsOpen || outRec2->IsOpen) continue; - - //get the polygon fragment with the correct hole state (FirstLeft) - //before calling JoinPoints() ... - OutRec *holeStateRec; - if (outRec1 == outRec2) holeStateRec = outRec1; - else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1; - else holeStateRec = GetLowermostRec(outRec1, outRec2); - - if (!JoinPoints(&join, outRec1, outRec2)) continue; - - if (outRec1 == outRec2) - { - //instead of joining two polygons, we've just created a new one by - //splitting one polygon into two. - outRec1->Pts = join.OutPt1; - outRec1->BottomPt = 0; - outRec2 = CreateOutRec(); - outRec2->Pts = join.OutPt2; - - //update all OutRec2.Pts Idx's ... - UpdateOutPtIdxs(*outRec2); - - if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) - { - //outRec1 contains outRec2 ... - outRec2->IsHole = !outRec1->IsHole; - outRec2->FirstLeft = outRec1; - - // For each m_PolyOuts, replace FirstLeft from outRec2 to outRec1. - if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); - - if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) - ReversePolyPtLinks(outRec2->Pts); - - } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) - { - //outRec2 contains outRec1 ... - outRec2->IsHole = outRec1->IsHole; - outRec1->IsHole = !outRec2->IsHole; - outRec2->FirstLeft = outRec1->FirstLeft; - outRec1->FirstLeft = outRec2; - - // For each m_PolyOuts, replace FirstLeft from outRec1 to outRec2. - if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); - - if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) - ReversePolyPtLinks(outRec1->Pts); - } - else - { - //the 2 polygons are completely separate ... - outRec2->IsHole = outRec1->IsHole; - outRec2->FirstLeft = outRec1->FirstLeft; - - //fixup FirstLeft pointers that may need reassigning to OutRec2 - // For each polygon of m_PolyOuts, replace FirstLeft from outRec1 to outRec2 if the polygon is inside outRec2. - //FIXME This is potentially very expensive! O(n^3)! - if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); - } - - } else - { - //joined 2 polygons together ... - - outRec2->Pts = 0; - outRec2->BottomPt = 0; - outRec2->Idx = outRec1->Idx; - - outRec1->IsHole = holeStateRec->IsHole; - if (holeStateRec == outRec2) - outRec1->FirstLeft = outRec2->FirstLeft; - outRec2->FirstLeft = outRec1; - - // For each m_PolyOuts, replace FirstLeft from outRec2 to outRec1. - if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1); - } - } -} - -//------------------------------------------------------------------------------ -// ClipperOffset support functions ... -//------------------------------------------------------------------------------ - -DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) -{ - if(pt2.x() == pt1.x() && pt2.y() == pt1.y()) - return DoublePoint(0, 0); - - double Dx = double(pt2.x() - pt1.x()); - double dy = double(pt2.y() - pt1.y()); - double f = 1.0 / std::sqrt( Dx*Dx + dy*dy ); - Dx *= f; - dy *= f; - return DoublePoint(dy, -Dx); -} - -//------------------------------------------------------------------------------ -// ClipperOffset class -//------------------------------------------------------------------------------ - -void ClipperOffset::Clear() -{ - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - delete m_polyNodes.Childs[i]; - m_polyNodes.Childs.clear(); - m_lowest.x() = -1; -} -//------------------------------------------------------------------------------ - -void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) -{ - int highI = (int)path.size() - 1; - if (highI < 0) return; - PolyNode* newNode = new PolyNode(); - newNode->m_jointype = joinType; - newNode->m_endtype = endType; - - //strip duplicate points from path and also get index to the lowest point ... - bool has_shortest_edge_length = ShortestEdgeLength > 0.; - double shortest_edge_length2 = has_shortest_edge_length ? ShortestEdgeLength * ShortestEdgeLength : 0.; - if (endType == etClosedLine || endType == etClosedPolygon) - for (; highI > 0; -- highI) { - bool same = false; - if (has_shortest_edge_length) { - double dx = double(path[highI].x() - path[0].x()); - double dy = double(path[highI].y() - path[0].y()); - same = dx*dx + dy*dy < shortest_edge_length2; - } else - same = path[0] == path[highI]; - if (! same) - break; - } - newNode->Contour.reserve(highI + 1); - newNode->Contour.emplace_back(path[0]); - int j = 0, k = 0; - for (int i = 1; i <= highI; i++) { - bool same = false; - if (has_shortest_edge_length) { - double dx = double(path[i].x() - newNode->Contour[j].x()); - double dy = double(path[i].y() - newNode->Contour[j].y()); - same = dx*dx + dy*dy < shortest_edge_length2; - } else - same = newNode->Contour[j] == path[i]; - if (same) - continue; - j++; - newNode->Contour.emplace_back(path[i]); - if (path[i].y() > newNode->Contour[k].y() || - (path[i].y() == newNode->Contour[k].y() && - path[i].x() < newNode->Contour[k].x())) k = j; - } - if (endType == etClosedPolygon && j < 2) - { - delete newNode; - return; - } - m_polyNodes.AddChild(*newNode); - - //if this path's lowest pt is lower than all the others then update m_lowest - if (endType != etClosedPolygon) return; - if (m_lowest.x() < 0) - m_lowest = IntPoint2d(m_polyNodes.ChildCount() - 1, k); - else - { - IntPoint ip = m_polyNodes.Childs[(int)m_lowest.x()]->Contour[(int)m_lowest.y()]; - if (newNode->Contour[k].y() > ip.y() || - (newNode->Contour[k].y() == ip.y() && - newNode->Contour[k].x() < ip.x())) - m_lowest = IntPoint2d(m_polyNodes.ChildCount() - 1, k); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::FixOrientations() -{ - //fixup orientations of all closed paths if the orientation of the - //closed path with the lowermost vertex is wrong ... - if (m_lowest.x() >= 0 && - !Orientation(m_polyNodes.Childs[(int)m_lowest.x()]->Contour)) - { - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedPolygon || - (node.m_endtype == etClosedLine && Orientation(node.Contour))) - ReversePath(node.Contour); - } - } else - { - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) - ReversePath(node.Contour); - } - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::Execute(Paths& solution, double delta) -{ - solution.clear(); - FixOrientations(); - DoOffset(delta); - - //now clean up 'corners' ... - Clipper clpr; - clpr.AddPaths(m_destPolys, ptSubject, true); - if (delta > 0) - { - clpr.Execute(ctUnion, solution, pftPositive, pftPositive); - } - else - { - IntRect r = clpr.GetBounds(); - Path outer(4); - outer[0] = IntPoint2d(r.left - 10, r.bottom + 10); - outer[1] = IntPoint2d(r.right + 10, r.bottom + 10); - outer[2] = IntPoint2d(r.right + 10, r.top - 10); - outer[3] = IntPoint2d(r.left - 10, r.top - 10); - - clpr.AddPath(outer, ptSubject, true); - clpr.ReverseSolution(true); - clpr.Execute(ctUnion, solution, pftNegative, pftNegative); - if (! solution.empty()) - solution.erase(solution.begin()); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::Execute(PolyTree& solution, double delta) -{ - solution.Clear(); - FixOrientations(); - DoOffset(delta); - - //now clean up 'corners' ... - Clipper clpr; - clpr.AddPaths(m_destPolys, ptSubject, true); - if (delta > 0) - { - clpr.Execute(ctUnion, solution, pftPositive, pftPositive); - } - else - { - IntRect r = clpr.GetBounds(); - Path outer(4); - outer[0] = IntPoint2d(r.left - 10, r.bottom + 10); - outer[1] = IntPoint2d(r.right + 10, r.bottom + 10); - outer[2] = IntPoint2d(r.right + 10, r.top - 10); - outer[3] = IntPoint2d(r.left - 10, r.top - 10); - - clpr.AddPath(outer, ptSubject, true); - clpr.ReverseSolution(true); - clpr.Execute(ctUnion, solution, pftNegative, pftNegative); - //remove the outer PolyNode rectangle ... - solution.RemoveOutermostPolygon(); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoOffset(double delta) -{ - m_destPolys.clear(); - m_delta = delta; - - //if Zero offset, just copy any CLOSED polygons to m_p and return ... - if (NEAR_ZERO(delta)) - { - m_destPolys.reserve(m_polyNodes.ChildCount()); - for (int i = 0; i < m_polyNodes.ChildCount(); i++) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedPolygon) - m_destPolys.emplace_back(node.Contour); - } - return; - } - - //see offset_triginometry3.svg in the documentation folder ... - m_miterLim = (MiterLimit > 2) ? - 2. / (MiterLimit * MiterLimit) : - 0.5; - - double y; - if (ArcTolerance <= 0.0) y = def_arc_tolerance; - else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) - y = std::fabs(delta) * def_arc_tolerance; - else y = ArcTolerance; - //see offset_triginometry2.svg in the documentation folder ... - double steps = pi / std::acos(1 - y / std::fabs(delta)); - if (steps > std::fabs(delta) * pi) - steps = std::fabs(delta) * pi; //ie excessive precision check - m_sin = std::sin(two_pi / steps); - m_cos = std::cos(two_pi / steps); - m_StepsPerRad = steps / two_pi; - if (delta < 0.0) m_sin = -m_sin; - - m_destPolys.reserve(m_polyNodes.ChildCount() * 2); - for (int i = 0; i < m_polyNodes.ChildCount(); i++) - { - PolyNode& node = *m_polyNodes.Childs[i]; - m_srcPoly = node.Contour; - - int len = (int)m_srcPoly.size(); - if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) - continue; - - m_destPoly.clear(); - if (len == 1) - { - if (node.m_jointype == jtRound) - { - double X = 1.0, Y = 0.0; - for (cInt j = 1; j <= steps; j++) - { - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[0].x() + X * delta), - Round(m_srcPoly[0].y() + Y * delta))); - double X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - } - else - { - double X = -1.0, Y = -1.0; - for (int j = 0; j < 4; ++j) - { - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[0].x() + X * delta), - Round(m_srcPoly[0].y() + Y * delta))); - if (X < 0) X = 1; - else if (Y < 0) Y = 1; - else X = -1; - } - } - m_destPolys.emplace_back(m_destPoly); - continue; - } - //build m_normals ... - m_normals.clear(); - m_normals.reserve(len); - for (int j = 0; j < len - 1; ++j) - m_normals.emplace_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); - if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) - m_normals.emplace_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); - else - m_normals.emplace_back(DoublePoint(m_normals[len - 2])); - - if (node.m_endtype == etClosedPolygon) - { - int k = len - 1; - for (int j = 0; j < len; ++j) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.emplace_back(m_destPoly); - } - else if (node.m_endtype == etClosedLine) - { - int k = len - 1; - for (int j = 0; j < len; ++j) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.emplace_back(m_destPoly); - m_destPoly.clear(); - //re-build m_normals ... - DoublePoint n = m_normals[len -1]; - for (int j = len - 1; j > 0; j--) - m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y()); - m_normals[0] = DoublePoint(-n.x(), -n.y()); - k = 0; - for (int j = len - 1; j >= 0; j--) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.emplace_back(m_destPoly); - } - else - { - int k = 0; - for (int j = 1; j < len - 1; ++j) - OffsetPoint(j, k, node.m_jointype); - - IntPoint pt1; - if (node.m_endtype == etOpenButt) - { - int j = len - 1; - pt1 = IntPoint2d(Round(m_srcPoly[j].x() + m_normals[j].x() * delta), Round(m_srcPoly[j].y() + m_normals[j].y() * delta)); - m_destPoly.emplace_back(pt1); - pt1 = IntPoint2d(Round(m_srcPoly[j].x() - m_normals[j].x() * delta), Round(m_srcPoly[j].y() - m_normals[j].y() * delta)); - m_destPoly.emplace_back(pt1); - } - else - { - int j = len - 1; - k = len - 2; - m_sinA = 0; - m_normals[j] = DoublePoint(-m_normals[j].x(), -m_normals[j].y()); - if (node.m_endtype == etOpenSquare) - DoSquare(j, k); - else - DoRound(j, k); - } - - //re-build m_normals ... - for (int j = len - 1; j > 0; j--) - m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y()); - m_normals[0] = DoublePoint(-m_normals[1].x(), -m_normals[1].y()); - - k = len - 1; - for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); - - if (node.m_endtype == etOpenButt) - { - pt1 = IntPoint2d(Round(m_srcPoly[0].x() - m_normals[0].x() * delta), Round(m_srcPoly[0].y() - m_normals[0].y() * delta)); - m_destPoly.emplace_back(pt1); - pt1 = IntPoint2d(Round(m_srcPoly[0].x() + m_normals[0].x() * delta), Round(m_srcPoly[0].y() + m_normals[0].y() * delta)); - m_destPoly.emplace_back(pt1); - } - else - { - k = 1; - m_sinA = 0; - if (node.m_endtype == etOpenSquare) - DoSquare(0, 1); - else - DoRound(0, 1); - } - m_destPolys.emplace_back(m_destPoly); - } - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) -{ - //cross product ... - m_sinA = (m_normals[k].x() * m_normals[j].y() - m_normals[j].x() * m_normals[k].y()); - if (std::fabs(m_sinA * m_delta) < 1.0) - { - //dot product ... - double cosA = (m_normals[k].x() * m_normals[j].x() + m_normals[j].y() * m_normals[k].y() ); - if (cosA > 0) // angle => 0 degrees - { - m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta), - Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta))); - return; - } - //else angle => 180 degrees - } - else if (m_sinA > 1.0) m_sinA = 1.0; - else if (m_sinA < -1.0) m_sinA = -1.0; - - if (m_sinA * m_delta < 0) - { - m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta), - Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta))); - m_destPoly.emplace_back(m_srcPoly[j]); - m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta), - Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta))); - } - else - switch (jointype) - { - case jtMiter: - { - double r = 1 + (m_normals[j].x() * m_normals[k].x() + - m_normals[j].y() * m_normals[k].y()); - if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); - break; - } - case jtSquare: DoSquare(j, k); break; - case jtRound: DoRound(j, k); break; - } - k = j; -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoSquare(int j, int k) -{ - double dx = std::tan(std::atan2(m_sinA, - m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y()) / 4); - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[j].x() + m_delta * (m_normals[k].x() - m_normals[k].y() * dx)), - Round(m_srcPoly[j].y() + m_delta * (m_normals[k].y() + m_normals[k].x() * dx)))); - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[j].x() + m_delta * (m_normals[j].x() + m_normals[j].y() * dx)), - Round(m_srcPoly[j].y() + m_delta * (m_normals[j].y() - m_normals[j].x() * dx)))); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoMiter(int j, int k, double r) -{ - double q = m_delta / r; - m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + (m_normals[k].x() + m_normals[j].x()) * q), - Round(m_srcPoly[j].y() + (m_normals[k].y() + m_normals[j].y()) * q))); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoRound(int j, int k) -{ - double a = std::atan2(m_sinA, - m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y()); - auto steps = std::max(Round(m_StepsPerRad * std::fabs(a)), 1); - - double X = m_normals[k].x(), Y = m_normals[k].y(), X2; - for (int i = 0; i < steps; ++i) - { - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[j].x() + X * m_delta), - Round(m_srcPoly[j].y() + Y * m_delta))); - X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - m_destPoly.emplace_back(IntPoint2d( - Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta), - Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta))); -} - -//------------------------------------------------------------------------------ -// Miscellaneous public functions -//------------------------------------------------------------------------------ - -// Called by Clipper::ExecuteInternal() -// For each polygon, search for exactly duplicate non-successive points. -// If such a point is found, the loop is split into two pieces. -// Search for the duplicate points is O(n^2)! -// http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Properties/StrictlySimple.htm -void Clipper::DoSimplePolygons() -{ - size_t i = 0; - while (i < m_PolyOuts.size()) - { - OutRec &outrec = m_PolyOuts[i++]; - OutPt* op = outrec.Pts; - if (!op || outrec.IsOpen) continue; - do //for each Pt in Polygon until duplicate found do ... - { - OutPt* op2 = op->Next; - while (op2 != outrec.Pts) - { - if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) - { - //split the polygon into two ... - OutPt* op3 = op->Prev; - OutPt* op4 = op2->Prev; - op->Prev = op4; - op4->Next = op; - op2->Prev = op3; - op3->Next = op2; - - outrec.Pts = op; - OutRec* outrec2 = CreateOutRec(); - outrec2->Pts = op2; - UpdateOutPtIdxs(*outrec2); - if (Poly2ContainsPoly1(outrec2->Pts, outrec.Pts)) - { - //OutRec2 is contained by OutRec1 ... - outrec2->IsHole = !outrec.IsHole; - outrec2->FirstLeft = &outrec; - // For each m_PolyOuts, replace FirstLeft from outRec2 to outrec. - if (m_UsingPolyTree) FixupFirstLefts2(outrec2, &outrec); - } - else - if (Poly2ContainsPoly1(outrec.Pts, outrec2->Pts)) - { - //OutRec1 is contained by OutRec2 ... - outrec2->IsHole = outrec.IsHole; - outrec.IsHole = !outrec2->IsHole; - outrec2->FirstLeft = outrec.FirstLeft; - outrec.FirstLeft = outrec2; - // For each m_PolyOuts, replace FirstLeft from outrec to outrec2. - if (m_UsingPolyTree) FixupFirstLefts2(&outrec, outrec2); - } - else - { - //the 2 polygons are separate ... - outrec2->IsHole = outrec.IsHole; - outrec2->FirstLeft = outrec.FirstLeft; - // For each polygon of m_PolyOuts, replace FirstLeft from outrec to outrec2 if the polygon is inside outRec2. - //FIXME This is potentially very expensive! O(n^3)! - if (m_UsingPolyTree) FixupFirstLefts1(&outrec, outrec2); - } - op2 = op; //ie get ready for the Next iteration - } - op2 = op2->Next; - } - op = op->Next; - } - while (op != outrec.Pts); - } -} -//------------------------------------------------------------------------------ - -void ReversePath(Path& p) -{ - std::reverse(p.begin(), p.end()); -} -//------------------------------------------------------------------------------ - -void ReversePaths(Paths& p) -{ - for (Paths::size_type i = 0; i < p.size(); ++i) - ReversePath(p[i]); -} -//------------------------------------------------------------------------------ - -Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType, bool strictly_simple /* = true */) -{ - Clipper c; - c.StrictlySimple(strictly_simple); - c.AddPath(in_poly, ptSubject, true); - Paths out; - c.Execute(ctUnion, out, fillType, fillType); - return out; -} - -//------------------------------------------------------------------------------ - -inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) -{ - auto Dx = double(pt1.x() - pt2.x()); - auto dy = double(pt1.y() - pt2.y()); - return (Dx*Dx + dy*dy); -} -//------------------------------------------------------------------------------ - -double DistanceFromLineSqrd( - const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) -{ - //The equation of a line in general form (Ax + By + C = 0) - //given 2 points (x¹,y¹) & (x²,y²) is ... - //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 - //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ - //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) - //see http://en.wikipedia.org/wiki/Perpendicular_distance - double A = double(ln1.y() - ln2.y()); - double B = double(ln2.x() - ln1.x()); - double C = A * ln1.x() + B * ln1.y(); - C = A * pt.x() + B * pt.y() - C; - return (C * C) / (A * A + B * B); -} -//--------------------------------------------------------------------------- - -bool SlopesNearCollinear(const IntPoint& pt1, - const IntPoint& pt2, const IntPoint& pt3, double distSqrd) -{ - //this function is more accurate when the point that's geometrically - //between the other 2 points is the one that's tested for distance. - //ie makes it more likely to pick up 'spikes' ... - if (std::abs(pt1.x() - pt2.x()) > std::abs(pt1.y() - pt2.y())) - { - if ((pt1.x() > pt2.x()) == (pt1.x() < pt3.x())) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.x() > pt1.x()) == (pt2.x() < pt3.x())) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - else - { - if ((pt1.y() > pt2.y()) == (pt1.y() < pt3.y())) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.y() > pt1.y()) == (pt2.y() < pt3.y())) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } -} -//------------------------------------------------------------------------------ - -bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) -{ - auto Dx = double(pt1.x() - pt2.x()); - auto dy = double(pt1.y() - pt2.y()); - return ((Dx * Dx) + (dy * dy) <= distSqrd); -} -//------------------------------------------------------------------------------ - -OutPt* ExcludeOp(OutPt* op) -{ - OutPt* result = op->Prev; - result->Next = op->Next; - op->Next->Prev = result; - result->Idx = 0; - return result; -} -//------------------------------------------------------------------------------ - -// Simplify a polygon using a linked list of points. -void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) -{ - //distance = proximity in units/pixels below which vertices - //will be stripped. Default ~= sqrt(2). - - size_t size = in_poly.size(); - - if (size == 0) - { - out_poly.clear(); - return; - } - - OutPts outPts(size); - for (size_t i = 0; i < size; ++i) - { - outPts[i].Pt = in_poly[i]; - outPts[i].Next = &outPts[(i + 1) % size]; - outPts[i].Next->Prev = &outPts[i]; - outPts[i].Idx = 0; - } - - double distSqrd = distance * distance; - OutPt* op = &outPts[0]; - while (op->Idx == 0 && op->Next != op->Prev) - { - if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) - { - op = ExcludeOp(op); - size--; - } - else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) - { - ExcludeOp(op->Next); - op = ExcludeOp(op); - size -= 2; - } - else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) - { - op = ExcludeOp(op); - size--; - } - else - { - op->Idx = 1; - op = op->Next; - } - } - - if (size < 3) size = 0; - out_poly.resize(size); - for (size_t i = 0; i < size; ++i) - { - out_poly[i] = op->Pt; - op = op->Next; - } -} -//------------------------------------------------------------------------------ - -void CleanPolygon(Path& poly, double distance) -{ - CleanPolygon(poly, poly, distance); -} -//------------------------------------------------------------------------------ - -void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) -{ - out_polys.resize(in_polys.size()); - for (Paths::size_type i = 0; i < in_polys.size(); ++i) - CleanPolygon(in_polys[i], out_polys[i], distance); -} -//------------------------------------------------------------------------------ - -void CleanPolygons(Paths& polys, double distance) -{ - CleanPolygons(polys, polys, distance); -} -//------------------------------------------------------------------------------ - -void Minkowski(const Path& poly, const Path& path, - Paths& solution, bool isSum, bool isClosed) -{ - int delta = (isClosed ? 1 : 0); - size_t polyCnt = poly.size(); - size_t pathCnt = path.size(); - Paths pp; - pp.reserve(pathCnt); - if (isSum) - for (size_t i = 0; i < pathCnt; ++i) - { - Path p; - p.reserve(polyCnt); - for (size_t j = 0; j < poly.size(); ++j) - p.emplace_back(IntPoint2d(path[i].x() + poly[j].x(), path[i].y() + poly[j].y())); - pp.emplace_back(p); - } - else - for (size_t i = 0; i < pathCnt; ++i) - { - Path p; - p.reserve(polyCnt); - for (size_t j = 0; j < poly.size(); ++j) - p.emplace_back(IntPoint2d(path[i].x() - poly[j].x(), path[i].y() - poly[j].y())); - pp.emplace_back(p); - } - - solution.clear(); - solution.reserve((pathCnt + delta) * (polyCnt + 1)); - for (size_t i = 0; i < pathCnt - 1 + delta; ++i) - for (size_t j = 0; j < polyCnt; ++j) - { - Path quad; - quad.reserve(4); - quad.emplace_back(pp[i % pathCnt][j % polyCnt]); - quad.emplace_back(pp[(i + 1) % pathCnt][j % polyCnt]); - quad.emplace_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); - quad.emplace_back(pp[i % pathCnt][(j + 1) % polyCnt]); - if (!Orientation(quad)) ReversePath(quad); - solution.emplace_back(quad); - } -} -//------------------------------------------------------------------------------ - -void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) -{ - Minkowski(pattern, path, solution, true, pathIsClosed); - Clipper c; - c.AddPaths(solution, ptSubject, true); - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -void TranslatePath(const Path& input, Path& output, const IntPoint& delta) -{ - //precondition: input != output - output.resize(input.size()); - for (size_t i = 0; i < input.size(); ++i) - output[i] = IntPoint2d(input[i].x() + delta.x(), input[i].y() + delta.y()); -} -//------------------------------------------------------------------------------ - -void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed) -{ - Clipper c; - for (size_t i = 0; i < paths.size(); ++i) - { - Paths tmp; - Minkowski(pattern, paths[i], tmp, true, pathIsClosed); - c.AddPaths(tmp, ptSubject, true); - if (pathIsClosed) - { - Path tmp2; - TranslatePath(paths[i], tmp2, pattern[0]); - c.AddPath(tmp2, ptClip, true); - } - } - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) -{ - Minkowski(poly1, poly2, solution, false, true); - Clipper c; - c.AddPaths(solution, ptSubject, true); - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -enum NodeType {ntAny, ntOpen, ntClosed}; - -void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths) -{ - bool match = true; - if (nodetype == ntClosed) match = !polynode.IsOpen(); - else if (nodetype == ntOpen) return; - - if (!polynode.Contour.empty() && match) - paths.emplace_back(polynode.Contour); - for (int i = 0; i < polynode.ChildCount(); ++i) - AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths); -} - -void AddPolyNodeToPaths(PolyNode&& polynode, NodeType nodetype, Paths& paths) -{ - bool match = true; - if (nodetype == ntClosed) match = !polynode.IsOpen(); - else if (nodetype == ntOpen) return; - - if (!polynode.Contour.empty() && match) - paths.emplace_back(std::move(polynode.Contour)); - for (int i = 0; i < polynode.ChildCount(); ++i) - AddPolyNodeToPaths(std::move(*polynode.Childs[i]), nodetype, paths); -} - -//------------------------------------------------------------------------------ - -void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) -{ - paths.clear(); - paths.reserve(polytree.Total()); - AddPolyNodeToPaths(polytree, ntAny, paths); -} - -void PolyTreeToPaths(PolyTree&& polytree, Paths& paths) -{ - paths.clear(); - paths.reserve(polytree.Total()); - AddPolyNodeToPaths(std::move(polytree), ntAny, paths); -} - -//------------------------------------------------------------------------------ - -void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) -{ - paths.clear(); - paths.reserve(polytree.Total()); - AddPolyNodeToPaths(polytree, ntClosed, paths); -} -//------------------------------------------------------------------------------ - -void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) -{ - paths.clear(); - paths.reserve(polytree.Total()); - //Open paths are top level only, so ... - for (int i = 0; i < polytree.ChildCount(); ++i) - if (polytree.Childs[i]->IsOpen()) - paths.emplace_back(polytree.Childs[i]->Contour); -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const IntPoint &p) -{ - s << "(" << p.x() << "," << p.y() << ")"; - return s; -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const Path &p) -{ - if (p.empty()) return s; - Path::size_type last = p.size() -1; - for (Path::size_type i = 0; i < last; i++) - s << "(" << p[i].x() << "," << p[i].y() << "), "; - s << "(" << p[last].x() << "," << p[last].y() << ")\n"; - return s; -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const Paths &p) -{ - for (Paths::size_type i = 0; i < p.size(); i++) - s << p[i]; - s << "\n"; - return s; -} -//------------------------------------------------------------------------------ - -} //ClipperLib namespace - -#ifdef CLIPPERLIB_NAMESPACE_PREFIX -} // namespace CLIPPERLIB_NAMESPACE_PREFIX -#endif // CLIPPERLIB_NAMESPACE_PREFIX diff --git a/deps_src/clipper/clipper.hpp b/deps_src/clipper/clipper.hpp deleted file mode 100644 index 06637effce..0000000000 --- a/deps_src/clipper/clipper.hpp +++ /dev/null @@ -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 -#include - -#include - -#include - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -#endif // CLIPPERLIB_INTPOINT_TYPE - -using DoublePoint = Eigen::Matrix; - -//------------------------------------------------------------------------------ - -template -using Allocator = tbb::scalable_allocator; -//using Allocator = std::allocator; -using Path = std::vector>; -using Paths = std::vector>; - -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 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> 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> 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>; - - // 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 - 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> 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> 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> 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>; - std::vector> 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> m_PolyOuts; - // Output points, allocated by a continuous sets of m_OutPtsChunkSize. - static constexpr const size_t m_OutPtsChunkSize = 32; - std::deque, Allocator>> 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> m_Joins; - std::vector> m_GhostJoins; - std::vector> m_IntersectList; - ClipType m_ClipType; - // A priority queue (a binary heap) of Y coordinates. - using cInts = std::vector>; - std::priority_queue 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 - 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> 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 -inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftNonZero, bool strictly_simple = true) { - Clipper c; - c.StrictlySimple(strictly_simple); - c.AddPaths(std::forward(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 diff --git a/deps_src/clipper/clipper_z.cpp b/deps_src/clipper/clipper_z.cpp deleted file mode 100644 index f26be7089a..0000000000 --- a/deps_src/clipper/clipper_z.cpp +++ /dev/null @@ -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" diff --git a/deps_src/clipper/clipper_z.hpp b/deps_src/clipper/clipper_z.hpp deleted file mode 100644 index 20596d8e19..0000000000 --- a/deps_src/clipper/clipper_z.hpp +++ /dev/null @@ -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 diff --git a/deps_src/clipper2/CMakeLists.txt b/deps_src/clipper2/CMakeLists.txt index 86c9a9efab..6343a6ceb5 100644 --- a/deps_src/clipper2/CMakeLists.txt +++ b/deps_src/clipper2/CMakeLists.txt @@ -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) diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h index 6d00f8fa07..25a5c02cc2 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h @@ -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 using Paths = std::vector>; + template + Path& operator<<(Path& poly, const Point& p) + { + poly.emplace_back(p); + return poly; + } + + template + Paths& operator<<(Paths& polys, const Path& p) + { + polys.emplace_back(p); + return polys; + } + using Path64 = Path; using PathD = Path; 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(std::abs(c)); const auto abs_d = static_cast(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 + inline int CrossProductSign(const Point& pt1, const Point& pt2, const Point& 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(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 - inline bool GetSegmentIntersectPt(const Point& ln1a, const Point& ln1b, + inline bool GetLineIntersectPt(const Point& ln1a, const Point& ln1b, const Point& ln2a, const Point& ln2b, Point& ip) { double ln1dy = static_cast(ln1b.y - ln1a.y); @@ -891,11 +944,14 @@ namespace Clipper2Lib { ip.x = originx + static_cast(hitx); ip.y = originy + static_cast(hity); } +#ifdef USINGZ + ip.z = 0; +#endif return true; } #else template - inline bool GetSegmentIntersectPt(const Point& ln1a, const Point& ln1b, + inline bool GetLineIntersectPt(const Point& ln1a, const Point& ln1b, const Point& ln2a, const Point& ln2b, Point& ip) { // https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection @@ -913,7 +969,10 @@ namespace Clipper2Lib { { ip.x = static_cast(ln1a.x + t * dx1); ip.y = static_cast(ln1a.y + t * dy1); - } +#ifdef USINGZ + ip.z = 0; +#endif + } return true; } #endif @@ -940,30 +999,53 @@ namespace Clipper2Lib { } template - 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(seg1b.y - seg1a.y); + double dx1 = static_cast(seg1b.x - seg1a.x); + double dy2 = static_cast(seg2b.y - seg2a.y); + double dx2 = static_cast(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; } diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h index 8387d2337d..5151e53c7b 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h @@ -15,6 +15,13 @@ #include #include +// 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 - static double Clipper2LibArea(const Path &poly) - { + // Area() of the namespace this header is compiled into (Clipper2Lib or Clipper2Lib_Z). + template + static double Clipper2LibArea(const Path &poly) + { #ifdef USINGZ - return Clipper2Lib_Z::Area(poly); + return Clipper2Lib_Z::Area(poly); #else - return Clipper2Lib::Area(poly); + return Clipper2Lib::Area(poly); #endif - } + } }; typedef typename std::vector> PolyPath64List; @@ -388,7 +402,8 @@ namespace Clipper2Lib { double Area() const { - return std::accumulate(childs_.cbegin(), childs_.cend(), Clipper2LibArea(polygon_), + return std::accumulate(childs_.cbegin(), childs_.cend(), + Clipper2LibArea(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(polygon_), + return std::accumulate(childs_.begin(), childs_.end(), + Clipper2LibArea(polygon_), [](double a, const auto& child) {return a + child->Area(); }); } }; diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h index a0d33d51df..2694f285fe 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h @@ -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 -#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 static void GetPathCountAndCPathsArrayLen(const Paths& paths, @@ -396,7 +393,7 @@ static Path ConvertCPathToPathT(T* path) #ifdef USINGZ z_type z = Reinterpret(*v++); result.emplace_back(x, y, z); -#else +#else result.emplace_back(x, y); #endif } @@ -414,7 +411,7 @@ static Paths ConvertCPathsToPathsT(T* paths) for (size_t i = 0; i < cnt; ++i) { size_t cnt2 = static_cast(*v); - v += 2; + v += 2; Path 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(*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(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(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); diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h index f6301fc52e..139dd0f9bd 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.h @@ -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 #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(paths, scale, error_code), jt, et); if (error_code) return PathsD(); Paths64 solution; clip_offset.Execute(delta * scale, solution); return ScalePaths(solution, 1 / scale, error_code); } - + template inline Path TranslatePath(const Path& path, T dx, T dy) { @@ -355,6 +356,29 @@ #endif } + inline size_t GetNext(size_t current, size_t high, + const std::vector& 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& 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& 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& 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 inline Path SimplifyPath(const Path &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 + inline bool Path2ContainsPath1(const Path& path1, const Path& path2) + { + // precondition: paths must not intersect, except for + // transient (and presumed 'micro') path intersections + PointInPolygonResult pip = PointInPolygonResult::IsOn; + for (const Point& 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 mp1 = GetBounds(path1).MidPoint(); + return PointInPolygon(mp1, path2) == PointInPolygonResult::IsInside; + } + template inline void RDP(const Path path, std::size_t begin, std::size_t end, double epsSqrd, std::vector& flags) diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h index a7d53df36f..fd553609c4 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h @@ -39,7 +39,7 @@ private: class Group { public: Paths64 paths_in; - std::optional lowest_path_idx{}; + std::optional 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;} diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.triangulation.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.triangulation.h new file mode 100644 index 0000000000..a33cb9fe6a --- /dev/null +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.triangulation.h @@ -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 +#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 diff --git a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h index 661b0f1c58..9aec09a2a8 100644 --- a/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.h +++ b/deps_src/clipper2/Clipper2Lib/include/clipper2/clipper.version.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 diff --git a/deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp index fd77bda7bb..2948565ff4 100644 --- a/deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp +++ b/deps_src/clipper2/Clipper2Lib/src/clipper.engine.cpp @@ -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 +#include +#include // 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; diff --git a/deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp index c00a345c01..60b514356a 100644 --- a/deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp +++ b/deps_src/clipper2/Clipper2Lib/src/clipper.offset.cpp @@ -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 GetLowestClosedPathIdx(const Paths64& paths) +void GetLowestClosedPathInfo(const Paths64& paths, std::optional& idx, bool& is_neg_area) { - std::optional 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(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(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 diff --git a/deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp index a4d83ad137..216ccbab19 100644 --- a/deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp +++ b/deps_src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp @@ -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); } diff --git a/deps_src/clipper2/Clipper2Lib/src/clipper.triangulation.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper.triangulation.cpp new file mode 100644 index 0000000000..25e3acd158 --- /dev/null +++ b/deps_src/clipper2/Clipper2Lib/src/clipper.triangulation.cpp @@ -0,0 +1,1222 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 13 December 2025 * +* Release : BETA RELEASE * +* Website : https://www.angusj.com * +* Copyright : Angus Johnson 2010-2025 * +* Purpose : Constrained Delaunay Triangulation * +* License : https://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#include "clipper2/clipper.h" +#include "clipper2/clipper.triangulation.h" + +#ifdef USINGZ +namespace Clipper2Lib_Z { +#else +namespace Clipper2Lib { +#endif + + enum class EdgeKind { loose, ascend, descend }; // ascend & descend are 'fixed' edges + enum class IntersectKind { none, collinear, intersect }; + enum class EdgeContainsResult { neither, left, right }; + + //forward definitions + class Vertex2; + class Edge; + class Triangle; + + typedef std::vector VertexList; + typedef std::vector EdgeList; + + class Vertex2 { + public: + Point64 pt; + EdgeList edges; + bool innerLM = false; + Vertex2(const Point64& p64) : pt(p64) { edges.reserve(2); }; + }; + + class Edge { + public: + Vertex2* vL = nullptr; + Vertex2* vR = nullptr; + Vertex2* vB = nullptr; + Vertex2* vT = nullptr; + EdgeKind kind = EdgeKind::loose; + Triangle* triA = nullptr; + Triangle* triB = nullptr; + bool isActive = false; + Edge* nextE = nullptr; + Edge* prevE = nullptr; + }; + + class Triangle { + public: + Edge* edges[3]; + Triangle(Edge* e1, Edge* e2, Edge* e3) + { + edges[0] = e1; + edges[1] = e2; + edges[2] = e3; + } + }; + + ///////////////////////////////////////////////////////////////////////////// + // Delaunay class declaration + ///////////////////////////////////////////////////////////////////////////// + + class Delaunay { + private: + VertexList allVertices; + EdgeList allEdges; + std::vector allTriangles; + std::stack pendingDelaunayStack; + std::stack horzEdgeStack; + std::stack locMinStack; + bool useDelaunay = true; + Vertex2* lowermostVertex = nullptr; + Edge* firstActive = nullptr; + void AddPath(const Path64& path); + bool AddPaths(const Paths64& paths); + void CleanUp(); + bool FixupEdgeIntersects(); + void MergeDupOrCollinearVertices(); + void SplitEdge(Edge* longE, Edge* shortE); + bool RemoveIntersection(Edge* e1, Edge* e2); + Edge* CreateEdge(Vertex2* v1, Vertex2* v2, EdgeKind k); + Triangle* CreateTriangle(Edge* e1, Edge* e2, Edge* e3); + Edge* CreateInnerLocMinLooseEdge(Vertex2* vAbove); + Edge* HorizontalBetween(Vertex2* v1, Vertex2* v2); + void DoTriangulateLeft(Edge* edge, Vertex2* pivot, int64_t minY); + void DoTriangulateRight(Edge* edge, Vertex2* pivot, int64_t minY); + void AddEdgeToActives(Edge* edge); + void RemoveEdgeFromActives(Edge* edge); + void ForceLegal(Edge* edge); + public: + explicit Delaunay(bool delaunay = true) : useDelaunay(delaunay) {}; + ~Delaunay() { CleanUp(); }; + Paths64 Execute(const Paths64& paths, TriangulateResult& triResult); + }; + + ///////////////////////////////////////////////////////////////////////////// + // Miscellaneous functions + ///////////////////////////////////////////////////////////////////////////// + + static bool VertexListSort(const Vertex2* a, const Vertex2* b) + { + return (a->pt.y == b->pt.y) ? (a->pt.x < b->pt.x) : (a->pt.y > b->pt.y); + } + + static bool EdgeListSort(const Edge* a, const Edge* b) + { + return (a->vL->pt.x < b->vL->pt.x); + } + + static bool IsLooseEdge(const Edge& e) + { + return e.kind == EdgeKind::loose; + } + + static bool IsLeftEdge(const Edge& e) + { + // left edge (bound) of a fill region + // ie fills on the **right** side of the edge + // precondition - e is never a 'loose' edge + return e.kind == EdgeKind::ascend; + } + + static bool IsRightEdge(const Edge& e) + { + // right edge (bound) of a fill region + // but still fills on the **right** side of the edge + // precondition - e is never a 'loose' edge + return e.kind == EdgeKind::descend; + } + + static bool IsHorizontal(const Edge& e) + { + return e.vB->pt.y == e.vT->pt.y; + } + + static bool LeftTurning(const Point64& p1, const Point64& p2, const Point64& p3) + { + return CrossProductSign(p1, p2, p3) < 0; + } + + static bool RightTurning(const Point64& p1, const Point64& p2, const Point64& p3) + { + return CrossProductSign(p1, p2, p3) > 0; + } + + static bool EdgeCompleted(Edge* edge) + { + if (!edge->triA) return false; + if (edge->triB) return true; + return edge->kind != EdgeKind::loose; + } + + static EdgeContainsResult EdgeContains(const Edge* edge, const Vertex2* v) + { + if (edge->vL == v) return EdgeContainsResult::left; + else if (edge->vR == v) return EdgeContainsResult::right; + else return EdgeContainsResult::neither; + } + + static double GetAngle(const Point64& a, const Point64& b, const Point64& c) + { + //https://stackoverflow.com/a/3487062/359538 + double abx = static_cast(b.x - a.x); + double aby = static_cast(b.y - a.y); + double bcx = static_cast(b.x - c.x); + double bcy = static_cast(b.y - c.y); + double dp = (abx * bcx + aby * bcy); + double cp = (abx * bcy - aby * bcx); + return std::atan2(cp, dp); //range between -Pi and Pi + } + + static double GetLocMinAngle(Vertex2* v) + { + // todo - recheck the result's sign compared to left vs right turning + // (currently assumes left turning => positive values) + // precondition - this function is called before processing locMin. + //Assert(v->edges.size() == 2); + int asc, des; + if (v->edges[0]->kind == EdgeKind::ascend) + { + asc = 0; + des = 1; + } + else + { + des = 0; + asc = 1; + } + // winding direction - descending to ascending + return GetAngle(v->edges[des]->vT->pt, v->pt, v->edges[asc]->vT->pt); + } + + static void RemoveEdgeFromVertex(Vertex2* vert, Edge* edge) + { + auto it = std::find(vert->edges.begin(), vert->edges.end(), edge); + if (it == vert->edges.end()) throw "oops!"; + vert->edges.erase(it); + } + + static bool FindLocMinIdx(const Path64& path, size_t len, size_t& idx) + { + if (len < 3) return false; + size_t i0 = idx, n = (idx + 1) % len; + while (path[n].y <= path[idx].y) + { + idx = n; n = (n + 1) % len; + if (idx == i0) return false; // fails if the path is completely horizontal + } + while (path[n].y >= path[idx].y) + { + idx = n; n = (n + 1) % len; + } + return true; + } + + static size_t Prev(size_t& idx, size_t len) + { + if (idx == 0) return len - 1; else return idx - 1; + } + + static size_t Next(size_t& idx, size_t len) + { + return (idx + 1) % len; + } + + static Edge* FindLinkingEdge(const Vertex2* vert1, const Vertex2* vert2, bool preferAscending) + { + Edge* res = nullptr; + for (auto e : vert1->edges) + { + if (e->vL == vert2 || e->vR == vert2) + { + if (e->kind == EdgeKind::loose || + ((e->kind == EdgeKind::ascend) == preferAscending)) return e; + res = e; + } + } + return res; + } + + static Path64 PathFromTriangle(Triangle tri) + { + Path64 res; + res.reserve(3); + res.push_back(tri.edges[0]->vL->pt); + res.push_back(tri.edges[0]->vR->pt); + const Edge& e = *tri.edges[1]; + if (e.vL->pt == res[0] || e.vL->pt == res[1]) + res.push_back(e.vR->pt); + else + res.push_back(e.vL->pt); + return res; + } + + static double InCircleTest(const Point64& ptA, const Point64& ptB, + const Point64& ptC, const Point64& ptD) + { + // Return the determinant value of 3 x 3 matrix ... + // | ax-dx ay-dy Sqr(ax-dx)+Sqr(ay-dy) | + // | bx-dx by-dy Sqr(bx-dx)+Sqr(by-dy) | + // | cx-dx cy-dy Sqr(cx-dx)+Sqr(cy-dy) | + + // The *sign* of the return value is determined by + // the orientation (CW vs CCW) of ptA, ptB & ptC. + + // precondition - ptA, ptB & ptC make a *non-empty* triangle + double m00 = static_cast(ptA.x - ptD.x); + double m01 = static_cast(ptA.y - ptD.y); + double m02 = (Sqr(m00) + Sqr(m01)); + double m10 = static_cast(ptB.x - ptD.x); + double m11 = static_cast(ptB.y - ptD.y); + double m12 = (Sqr(m10) + Sqr(m11)); + double m20 = static_cast(ptC.x - ptD.x); + double m21 = static_cast(ptC.y - ptD.y); + double m22 = (Sqr(m20) + Sqr(m21)); + return m00 * (m11 * m22 - m21 * m12) - + m10 * (m01 * m22 - m21 * m02) + + m20 * (m01 * m12 - m11 * m02); + } + + static double ShortestDistFromSegment(const Point64& pt, const Point64& segPt1, const Point64& segPt2) + { + // precondition: segPt1 <> segPt2 + double dx = static_cast(segPt2.x - segPt1.x); + double dy = static_cast(segPt2.y - segPt1.y); + //Assert((dx < > 0) or (dy < > 0)); // ie segPt1 <> segPt2 + + double ax = static_cast(pt.x - segPt1.x); + double ay = static_cast(pt.y - segPt1.y); + //q = (ax * dx + ay * dy) / (dx * dx + dy * dy); + double qNum = ax * dx + ay * dy; + if (qNum < 0) // pt is closest to seq1 + return DistanceSqr(pt, segPt1); + else if (qNum > (Sqr(dx) + Sqr(dy))) // pt is closest to seq2 + return DistanceSqr(pt, segPt2); + else + return Sqr(ax * dy - dx * ay) / (dx * dx + dy * dy); + } + + static IntersectKind SegsIntersect(const Point64 s1a, const Point64 s1b, + const Point64 s2a, const Point64 s2b) + { + double dy1 = static_cast(s1b.y - s1a.y); + double dx1 = static_cast(s1b.x - s1a.x); + double dy2 = static_cast(s2b.y - s2a.y); + double dx2 = static_cast(s2b.x - s2a.x); + double cp = dy1 * dx2 - dy2 * dx1; + if (cp == 0) return IntersectKind::collinear; + + double t = (static_cast(s1a.x - s2a.x) * dy2 - + static_cast(s1a.y - s2a.y) * dx2); + //ignore segments that 'intersect' at an end-point + if (t == 0) return IntersectKind::none; + if (t > 0) + { + if (cp < 0 || t >= cp) return IntersectKind::none; + } + else + { + if (cp > 0 || t <= cp) return IntersectKind::none; + } + + // so far, the *segment* 's1' intersects the *line* through 's2', + // but now make sure it also intersects the *segment* 's2' + t = ((s1a.x - s2a.x) * dy1 - (s1a.y - s2a.y) * dx1); + if (t == 0) return IntersectKind::none; + if (t > 0) + { + if (cp > 0 && t < cp) return IntersectKind::intersect; + } + else + { + if (cp < 0 && t > cp) return IntersectKind::intersect; + } + return IntersectKind::none; + } + + ///////////////////////////////////////////////////////////////////////////// + // Delaunay class definitions + ///////////////////////////////////////////////////////////////////////////// + + void Delaunay::CleanUp() + { + for (auto v : allVertices) delete v; + allVertices.resize(0); + for (auto e : allEdges) delete e; + allEdges.resize(0); + for (auto t : allTriangles) delete t; + allTriangles.resize(0); + + firstActive = nullptr; + lowermostVertex = nullptr; + } + + void Delaunay::ForceLegal(Edge* edge) + { + // don't try to make empty triangles legal + if (!edge->triA || !edge->triB) return; + + // vertA will be assigned the vertex in edge's triangleA + // that is NOT an end vertex of edge + // Likewise, vertB will be assigned the vertex in edge's + // triangleB that is NOT an end vertex of edge + // If edge is rotated, vertA & vertB will become its end vertices. + Vertex2* vertA = nullptr; + Vertex2* vertB = nullptr; + + // Excluding 'edge', edgesA will contain two edges (one from + // triangleA and one from triangleB) that touch edge.vL. + // And edgesB will contain the two edges that touch edge.vR. + + Edge* edgesA[3] = { nullptr, nullptr, nullptr }; + Edge* edgesB[3] = { nullptr, nullptr, nullptr }; + for (int i = 0; i < 3; ++i) + { + if (edge->triA->edges[i] == edge) continue; + switch (EdgeContains(edge->triA->edges[i], edge->vL)) + { + case EdgeContainsResult::left: + edgesA[1] = edge->triA->edges[i]; + vertA = edge->triA->edges[i]->vR; + break; + case EdgeContainsResult::right: + edgesA[1] = edge->triA->edges[i]; + vertA = edge->triA->edges[i]->vL; + break; + default: + edgesB[1] = edge->triA->edges[i]; + } + } + + for (int i = 0; i < 3; ++i) + { + if (edge->triB->edges[i] == edge) continue; + switch (EdgeContains(edge->triB->edges[i], edge->vL)) + { + case EdgeContainsResult::left: + edgesA[2] = edge->triB->edges[i]; + vertB = edge->triB->edges[i]->vR; + break; + case EdgeContainsResult::right: + edgesA[2] = edge->triB->edges[i]; + vertB = edge->triB->edges[i]->vL; + break; + default: + edgesB[2] = edge->triB->edges[i]; + } + } + + // InCircleTest reqires edge.triangleA to be a valid triangle + // if IsEmptyTriangle(edge.triangleA) then Exit; // slower + if (CrossProductSign(vertA->pt, edge->vL->pt, edge->vR->pt) == 0) return; + + // ictResult - result sign is dependant on triangleA's orientation + double ictResult = InCircleTest(vertA->pt, edge->vL->pt, edge->vR->pt, vertB->pt); + if (ictResult == 0 || // if on or out of circle then exit + (RightTurning(vertA->pt, edge->vL->pt, edge->vR->pt) == (ictResult < 0))) return; + + // TRIANGLES HERE ARE **NOT** DELAUNAY COMPLIANT, SO MAKE THEM SO. + + // NOTE: ONCE WE BEGIN DELAUNAY COMPLIANCE, vL & vR WILL + // NO LONGER REPRESENT LEFT AND RIGHT VERTEX ORIENTATION. + // THIS IS MINOR PERFORMANCE EFFICIENCY IS SAFE AS LONG AS + // THE TRIANGULATE() METHOD IS CALLED ONCE ONLY ON A GIVEN + // SET OF PATHS + + edge->vL = vertA; + edge->vR = vertB; + + edge->triA->edges[0] = edge; + for (int i = 1; i < 3; ++i) + { + edge->triA->edges[i] = edgesA[i]; + if (!edgesA[i]) throw "oops"; // stops compiler warnings + if (IsLooseEdge(*edgesA[i])) + pendingDelaunayStack.push(edgesA[i]); + // since each edge has its own triangleA and triangleB, we have to be careful + // to update the correct one ... + if (edgesA[i]->triA == edge->triA || edgesA[i]->triB == edge->triA) continue; + + if (edgesA[i]->triA == edge->triB) + edgesA[i]->triA = edge->triA; + else if (edgesA[i]->triB == edge->triB) + edgesA[i]->triB = edge->triA; + else throw "oops"; + } + + edge->triB->edges[0] = edge; + for (int i = 1; i < 3; ++i) + { + edge->triB->edges[i] = edgesB[i]; + if (!edgesB[i]) throw "oops"; // stops compiler warnings + if (IsLooseEdge(*edgesB[i])) + pendingDelaunayStack.push(edgesB[i]); + // since each edge has its own triangleA and triangleB, we have to be careful + // to update the correct one ... + if (edgesB[i]->triA == edge->triB || edgesB[i]->triB == edge->triB) continue; + + if (edgesB[i]->triA == edge->triA) + edgesB[i]->triA = edge->triB; + else if (edgesB[i]->triB == edge->triA) + edgesB[i]->triB = edge->triB; + else throw "oops"; + } + + } + + Edge* Delaunay::CreateEdge(Vertex2* v1, Vertex2* v2, EdgeKind k) + { + Edge* res = allEdges.emplace_back(new Edge()); + if (v1->pt.y == v2->pt.y) + { + res->vB = v1; res->vT = v2; + } + else if (v1->pt.y < v2->pt.y) + { + res->vB = v2; res->vT = v1; + } + else + { + res->vB = v1; res->vT = v2; + } + + if (v1->pt.x <= v2->pt.x) + { + res->vL = v1; res->vR = v2; + } + else + { + res->vL = v2; res->vR = v1; + } + res->kind = k; + v1->edges.push_back(res); + v2->edges.push_back(res); + + if (k == EdgeKind::loose) + { + pendingDelaunayStack.push(res); + AddEdgeToActives(res); + } + return res; + } + + Triangle* Delaunay::CreateTriangle(Edge* e1, Edge* e2, Edge* e3) + { + Triangle* res = allTriangles.emplace_back(new Triangle(e1, e2, e3)); + // nb: only expire loose edges when both sides of these edges have triangles. + for (int i = 0; i < 3; ++i) + if (res->edges[i]->triA) + { + res->edges[i]->triB = res; + // this is the edge's second triangle hence no longer active + RemoveEdgeFromActives(res->edges[i]); + } + else + { + res->edges[i]->triA = res; + // this is the edge's first triangle, so only remove + // this edge from actives if it's a fixed edge. + if (!IsLooseEdge(*res->edges[i])) + RemoveEdgeFromActives(res->edges[i]); + } + return res; + } + + bool Delaunay::RemoveIntersection(Edge* e1, Edge* e2) + { + // find which vertex is closest to the other segment + // (ie not the vertex closest to the intersection point) ... + + Vertex2* v = e1->vL; + Edge* tmpE = e2; + double d = ShortestDistFromSegment(e1->vL->pt, e2->vL->pt, e2->vR->pt); + double d2 = ShortestDistFromSegment(e1->vR->pt, e2->vL->pt, e2->vR->pt); + if (d2 < d) { d = d2; v = e1->vR; } + d2 = ShortestDistFromSegment(e2->vL->pt, e1->vL->pt, e1->vR->pt); + if (d2 < d) { d = d2; tmpE = e1; v = e2->vL; } + d2 = ShortestDistFromSegment(e2->vR->pt, e1->vL->pt, e1->vR->pt); + if (d2 < d) { d = d2; tmpE = e1; v = e2->vR; } + if (d > 1.000) + return false; // Oops - this is not just a simple 'rounding' intersection + + // split 'tmpE' into 2 edges at 'v' + Vertex2* v2 = tmpE->vT; + RemoveEdgeFromVertex(v2, tmpE); + // replace v2 in tmpE with v + if (tmpE->vL == v2) tmpE->vL = v; + else tmpE->vR = v; + tmpE->vT = v; + v->edges.push_back(tmpE); + v->innerLM = false; // #47 + // left turning is angle positive + if (tmpE->vB->innerLM && GetLocMinAngle(tmpE->vB) <= 0) + tmpE->vB->innerLM = false; // #44, 52 + // finally create a new edge between v and v2 ... + CreateEdge(v, v2, tmpE->kind); + return true; + } + + bool Delaunay::FixupEdgeIntersects() + { + // precondition - edgeList must be sorted - ascending on edge.vL.pt.x + + for (size_t i1 = 0; i1 < allEdges.size(); ++i1) + { + Edge* e1 = allEdges[i1]; + // nb: we can safely ignore edges newly created inside this for loop + for (size_t i2 = i1 + 1; i2 < allEdges.size(); ++i2) + { + Edge* e2 = allEdges[i2]; + if (e2->vL->pt.x >= e1->vR->pt.x) + break; // all 'e' from now on are too far right + + // 'e2' is inside e1's horizontal region. If 'e2' is also inside + // e1's vertical region, only then check for an intersection ... + if (e2->vT->pt.y < e1->vB->pt.y && e2->vB->pt.y > e1->vT->pt.y && + (SegsIntersect(e2->vL->pt, e2->vR->pt, + e1->vL->pt, e1->vR->pt) == IntersectKind::intersect)) + { + if (!RemoveIntersection(e2, e1)) + return false; // oops!! + } + // nb: collinear edges are managed in MergeDupOrCollinearVertices below + } + } + return true; + } + + void Delaunay::SplitEdge(Edge* longE, Edge* shortE) + { + auto oldT = longE->vT, newT = shortE->vT; + // remove longEdge from longEdge.vT.edges + RemoveEdgeFromVertex(oldT, longE); + // shorten longEdge + longE->vT = newT; + if (longE->vL == oldT) longE->vL = newT; + else longE->vR = newT; + // add shortened longEdge to newT.edges + newT->edges.push_back(longE); + // and create a new edge betweem newV, oldT + CreateEdge(newT, oldT, longE->kind); + } + + void Delaunay::MergeDupOrCollinearVertices() + { + // note: this procedure may add new edges and change the + // number of edges connected with a given vertex, but it + // won't add or delete vertices (so it's safe to use iterators) + auto vIter1 = allVertices.begin(); + for (auto vIter2 = allVertices.begin() + 1; vIter2 != allVertices.end(); ++vIter2) + { + if ((*vIter1)->pt != (*vIter2)->pt) + { + vIter1 = vIter2; + continue; + } + + // merge v1 & v2 + Vertex2* v1 = *vIter1, * v2 = *vIter2; + if (!v1->innerLM || !v2->innerLM) + v1->innerLM = false; + + // in all of v2's edges, replace links to v2 with links to v1 + for (auto e : v2->edges) + { + if (e->vB == v2) e->vB = v1; + else e->vT = v1; + if (e->vL == v2) e->vL = v1; + else e->vR = v1; + } + // move all of v2's edges to v1 + std::copy(v2->edges.begin(), v2->edges.end(), back_inserter(v1->edges)); + v2->edges.resize(0); + + // excluding horizontals, if pv.edges contains two edges + // that are *collinear* and share the same bottom coords + // but have different lengths, split the longer edge at + // the top of the shorter edge ... + for (auto itE = v1->edges.begin(); itE != v1->edges.end(); ++itE) + { + if (IsHorizontal(*(*itE)) || (*itE)->vB != v1) continue; + for (auto itE2 = itE + 1; itE2 != v1->edges.end(); ++itE2) + { + auto e1 = *itE, e2 = *itE2; + if (e2->vB != v1 || e1->vT->pt.y == e2->vT->pt.y || + (CrossProductSign(e1->vT->pt, v1->pt, e2->vT->pt) != 0)) continue; + // we have parallel edges, both heading up from v1.pt. + // split the longer edge at the top of the shorter edge. + if (e1->vT->pt.y < e2->vT->pt.y) SplitEdge(e1, e2); + else SplitEdge(e2, e1); + break; // because only two edges can be collinear + } + } + } + } + + Edge* Delaunay::CreateInnerLocMinLooseEdge(Vertex2* vAbove) + { + if (!firstActive) return nullptr; // oops!! + + int64_t xAbove = vAbove->pt.x; + int64_t yAbove = vAbove->pt.y; + + // find the closest 'active' edge with a vertex that's not above vAbove + Edge* e = firstActive, *eBelow = nullptr; + double bestD = -1.0; + while (e) + { + if (e->vL->pt.x <= xAbove && e->vR->pt.x >= xAbove && + e->vB->pt.y >= yAbove && e->vB != vAbove && e->vT != vAbove && + !LeftTurning(e->vL->pt, vAbove->pt, e->vR->pt)) + { + double d = ShortestDistFromSegment(vAbove->pt, e->vL->pt, e->vR->pt); + if (!eBelow || d < bestD) // compare e with eBelow + { + eBelow = e; + bestD = d; + } + } + e = e->nextE; + } + if (!eBelow) return nullptr; // oops!! + + // get the best vertex from 'eBelow' + Vertex2* vBest = (eBelow->vT->pt.y <= yAbove) ? eBelow->vB : eBelow->vT; + int64_t xBest = vBest->pt.x; + int64_t yBest = vBest->pt.y; + + // make sure no edges intersect 'vAbove' and 'vBest' ... + // todo: fActives is currently *unsorted* but consider making it + // a tree structure based on each edge's left and right bounds + e = firstActive; + if (xBest < xAbove) + { + while (e) + { + if (e->vR->pt.x > xBest && e->vL->pt.x < xAbove && + e->vB->pt.y > yAbove && e->vT->pt.y < yBest && + (SegsIntersect(e->vB->pt, e->vT->pt, + vBest->pt, vAbove->pt) == IntersectKind::intersect)) + { + vBest = (e->vT->pt.y > yAbove) ? e->vT : e->vB; + xBest = vBest->pt.x; + yBest = vBest->pt.y; + } + e = e->nextE; + } + } + else + { + while (e) + { + if (e->vR->pt.x < xBest && e->vL->pt.x > xAbove && + e->vB->pt.y > yAbove && e->vT->pt.y < yBest && + (SegsIntersect(e->vB->pt, e->vT->pt, + vBest->pt, vAbove->pt) == IntersectKind::intersect)) + { + vBest = e->vT->pt.y > yAbove ? e->vT : e->vB; + xBest = vBest->pt.x; + yBest = vBest->pt.y; + } + e = e->nextE; + } + } + return CreateEdge(vBest, vAbove, EdgeKind::loose); + } + + Edge* Delaunay::HorizontalBetween(Vertex2* v1, Vertex2* v2) + { + int64_t y = v1->pt.y, l, r; + if (v1->pt.x > v2->pt.x) + { + l = v2->pt.x; + r = v1->pt.x; + } + else + { + l = v1->pt.x; + r = v2->pt.x; + } + + Edge* res = firstActive; + while (res) + { + if (res->vL->pt.y == y && res->vR->pt.y == y && + res->vL->pt.x >= l && res->vR->pt.x <= r && + (res->vL->pt.x != l || res->vL->pt.x != r)) break; + res = res->nextE; + } + return res; + } + + void Delaunay::DoTriangulateLeft(Edge* edge, Vertex2* pivot, int64_t minY) + { + // precondition - pivot must be one end of edge (Usually .vB) + //Assert(!EdgeCompleted(edge)); + Vertex2* vAlt = nullptr; + Edge* eAlt = nullptr; + Vertex2* v = (edge->vB == pivot) ? edge->vT : edge->vB; + + for (auto e : pivot->edges) + { + if (e == edge || !e->isActive) continue; + Vertex2* vX = e->vT == pivot ? e->vB : e->vT; + if (vX == v) continue; + + int cps = CrossProductSign(v->pt, pivot->pt, vX->pt); + if (cps == 0) //collinear paths + { + // if pivot is between v and vX then continue; + // nb: this is important for both horiz and non-horiz collinear + if ((v->pt.x > pivot->pt.x) == (pivot->pt.x > vX->pt.x)) continue; + } + // else if right-turning or not the best edge, then continue + else if (cps > 0 || (vAlt && !LeftTurning(vX->pt, pivot->pt, vAlt->pt))) + continue; + vAlt = vX; + eAlt = e; + } + + if (!vAlt || vAlt->pt.y < minY) return; + + // Don't triangulate **across** fixed edges + if (vAlt->pt.y < pivot->pt.y) + { + if (IsLeftEdge(*eAlt)) return; + } + else if (vAlt->pt.y > pivot->pt.y) + { + if (IsRightEdge(*eAlt)) return; + } + + Edge* eX = FindLinkingEdge(vAlt, v, (vAlt->pt.y < v->pt.y)); + if (!eX) + { + // be very careful creating loose horizontals at minY + if (vAlt->pt.y == v->pt.y && v->pt.y == minY && + HorizontalBetween(vAlt, v)) return; + eX = CreateEdge(vAlt, v, EdgeKind::loose); + } + + CreateTriangle(edge, eAlt, eX); + if (!EdgeCompleted(eX)) + DoTriangulateLeft(eX, vAlt, minY); + + } + + void Delaunay::DoTriangulateRight(Edge* edge, Vertex2* pivot, int64_t minY) + { + // precondition - pivot must be one end of edge (Usually .vB) + //Assert(!EdgeCompleted(edge)); + Vertex2* vAlt = nullptr; + Edge* eAlt = nullptr; + Vertex2* v = (edge->vB == pivot) ? edge->vT : edge->vB; + + for (auto e : pivot->edges) + { + if (e == edge || !e->isActive) continue; + Vertex2* vX = e->vT == pivot ? e->vB : e->vT; + if (vX == v) continue; + + int cps = CrossProductSign(v->pt, pivot->pt, vX->pt); + if (cps == 0) //collinear paths + { + // if pivot is between v and vX then continue; + // nb: this is important for both horiz and non-horiz collinear + if ((v->pt.x > pivot->pt.x) == (pivot->pt.x > vX->pt.x)) continue; + } + // else if right-turning or not the best edge, then continue + else if (cps < 0 || (vAlt && !RightTurning(vX->pt, pivot->pt, vAlt->pt))) + continue; + vAlt = vX; + eAlt = e; + } + + if (!vAlt || vAlt->pt.y < minY) return; + + // Don't triangulate **across** fixed edges + if (vAlt->pt.y < pivot->pt.y) + { + if (IsRightEdge(*eAlt)) return; + } + else if (vAlt->pt.y > pivot->pt.y) + { + if (IsLeftEdge(*eAlt)) return; + } + + Edge* eX = FindLinkingEdge(vAlt, v, (vAlt->pt.y > v->pt.y)); + if (!eX) + { + // be very careful creating loose horizontals at minY + if (vAlt->pt.y == v->pt.y && v->pt.y == minY && + HorizontalBetween(vAlt, v)) return; + eX = CreateEdge(vAlt, v, EdgeKind::loose); + } + + CreateTriangle(edge, eX, eAlt); + if (!EdgeCompleted(eX)) + DoTriangulateRight(eX, vAlt, minY); + + + } + + void Delaunay::AddEdgeToActives(Edge* edge) + { + // nb: on occassions this method can get called twice for a given edge + // This is because, in the Triangulate() method where vertex 'edges' + // arrays are being parsed, edges can can be removed from the array + // which changes the index of following edges. + if (edge->isActive) return; + + edge->prevE = nullptr; + edge->nextE = firstActive; + edge->isActive = true; + if (firstActive) + firstActive->prevE = edge; + firstActive = edge; + } + + + void Delaunay::RemoveEdgeFromActives(Edge* edge) + { + // first, remove the edge from its vertices + RemoveEdgeFromVertex(edge->vB, edge); + RemoveEdgeFromVertex(edge->vT, edge); + + // now remove the edge from double linked list (AEL) + Edge* prev = edge->prevE; + Edge* next = edge->nextE; + if (next) next->prevE = prev; + if (prev) prev->nextE = next; + edge->isActive = false; + if (firstActive == edge) firstActive = next; + } + + Paths64 Delaunay::Execute(const Paths64& paths, TriangulateResult& triResult) + { + if (!AddPaths(paths)) + { + triResult = TriangulateResult::no_polygons; + return Paths64(); // oops! + } + + // if necessary fix path orientation because the algorithm + // expects clockwise outer paths and counter-clockwise inner paths + if (lowermostVertex->innerLM) + { + // the orientation of added paths must be wrong, so + // 1. reverse innerLM flags ... + Vertex2* lm; + while (!locMinStack.empty()) + { + lm = locMinStack.top(); + lm->innerLM = !lm->innerLM; + locMinStack.pop(); + } + // 2. swap edge kinds + for (Edge* e : allEdges) + if (e->kind == EdgeKind::ascend) + e->kind = EdgeKind::descend; + else + e->kind = EdgeKind::ascend; + } + else + { + // path orientation is fine so ... + while (!locMinStack.empty()) + locMinStack.pop(); + } + + std::sort(allEdges.begin(), allEdges.end(), EdgeListSort); + if (!FixupEdgeIntersects()) + { + CleanUp(); + triResult = TriangulateResult::paths_intersect; + return Paths64(); // oops! + } + + std::sort(allVertices.begin(), allVertices.end(), VertexListSort); + MergeDupOrCollinearVertices(); + + int64_t currY = allVertices[0]->pt.y; + for (auto vIt = allVertices.begin(); vIt != allVertices.end(); ++vIt) + { + Vertex2* v = *vIt; + if (v->edges.empty()) continue; + if (v->pt.y != currY) + { + // JOIN AN INNER LOCMIN WITH A SUITABLE EDGE BELOW + while (!locMinStack.empty()) + { + Vertex2* lm = locMinStack.top(); + locMinStack.pop(); + Edge* e = CreateInnerLocMinLooseEdge(lm); + if (!e) + { + CleanUp(); + triResult = TriangulateResult::fail; + return Paths64(); // oops! + } + + if (IsHorizontal(*e)) + { + if (e->vL == e->vB) + DoTriangulateLeft(e, e->vB, currY); else + DoTriangulateRight(e, e->vB, currY); + } + else + { + DoTriangulateLeft(e, e->vB, currY); + if (!EdgeCompleted(e)) + DoTriangulateRight(e, e->vB, currY); + } + + // and because adding locMin edges to Actives was delayed .. + AddEdgeToActives(lm->edges[0]); + AddEdgeToActives(lm->edges[1]); + } + + while (!horzEdgeStack.empty()) + { + Edge* e = horzEdgeStack.top(); + horzEdgeStack.pop(); + if (EdgeCompleted(e)) continue; + if (e->vB == e->vL) // #45 + { + if (IsLeftEdge(*e)) + DoTriangulateLeft(e, e->vB, currY); + } + else + if (IsRightEdge(*e)) + DoTriangulateRight(e, e->vB, currY); + } + currY = v->pt.y; + } + + for (int i = static_cast(v->edges.size()) - 1; i >= 0; --i) + { + // the following line may look superfluous, but within this loop + // v->edges may be altered with additions and or deletions. + // So this line *is* necessary (and why we can't use an iterator). + // Also, we need to use a *descending* index which is safe because + // any additions will be loose edges which are ignored here. + if (i >= static_cast(v->edges.size())) continue; + + Edge* e = v->edges[i]; + if (EdgeCompleted(e) || IsLooseEdge(*e)) continue; + + if (v == e->vB) + { + if (IsHorizontal(*e)) + horzEdgeStack.push(e); + // delay adding locMin edges to actives + if (!v->innerLM) + AddEdgeToActives(e); + } + else + { + if (IsHorizontal(*e)) + horzEdgeStack.push(e); + else if (IsLeftEdge(*e)) + DoTriangulateLeft(e, e->vB, v->pt.y); + else + DoTriangulateRight(e, e->vB, v->pt.y); + } + } // for v->edges loop + + if (v->innerLM) locMinStack.push(v); + + } // for allVertices loop + + + while (!horzEdgeStack.empty()) + { + Edge* e = horzEdgeStack.top(); + horzEdgeStack.pop(); + if (!EdgeCompleted(e) && e->vB == e->vL) + DoTriangulateLeft(e, e->vB, currY); + } + + if (useDelaunay) + { + // Convert triangles to Delaunay conforming + while (!pendingDelaunayStack.empty()) + { + Edge* e = pendingDelaunayStack.top(); + pendingDelaunayStack.pop(); + ForceLegal(e); + } + } + + Paths64 res; + res.reserve(allTriangles.size()); + for (auto tri : allTriangles) + { + Path64 p = PathFromTriangle(*tri); + int cps = CrossProductSign(p[0], p[1], p[2]); + if (cps == 0) continue; // skip any empty triangles + if (cps < 0) // ccw + std::reverse(p.begin(), p.end()); + res.push_back(p); + } + + CleanUp(); + triResult = TriangulateResult::success; + return res; + } + + static double DistSqr(const Point64& pt1, const Point64& pt2) + { + return Sqr(pt1.x - pt2.x) + Sqr(pt1.y - pt2.y); + } + + void Delaunay::AddPath(const Path64& path) + { + size_t len = path.size(), i0 = 0, iPrev, iNext; + // find the first locMin for the current path + if (!FindLocMinIdx(path, len, i0)) return; + iPrev = Prev(i0, len); + while (path[iPrev] == path[i0]) iPrev = Prev(iPrev, len); + iNext = Next(i0, len); + + // it is possible for a locMin here to simply be a + // collinear spike that should be ignored, so ... + size_t i = i0; + while (CrossProductSign(path[iPrev], path[i], path[iNext]) == 0) + { + FindLocMinIdx(path, len, i); + if (i == i0) return; // this is an entirely collinear path + iPrev = Prev(i, len); + while (path[iPrev] == path[i]) iPrev = Prev(iPrev, len); + iNext = Next(i, len); + } + + size_t vert_cnt = allVertices.size(); + + // we are now at the first legitimate locMin + Vertex2* v0 = allVertices.emplace_back(new Vertex2(path[i])); + + if (LeftTurning(path[iPrev], path[i], path[iNext])) + v0->innerLM = true; + Vertex2* vPrev = v0; + i = iNext; + + for (;;) + { + // vPrev is a locMin here + locMinStack.push(vPrev); + // ? update lowermostVertex ... + if (!lowermostVertex || + vPrev->pt.y > lowermostVertex->pt.y || + (vPrev->pt.y == lowermostVertex->pt.y && + vPrev->pt.x < lowermostVertex->pt.x)) + lowermostVertex = vPrev; + + iNext = Next(i, len); + if (CrossProductSign(vPrev->pt, path[i], path[iNext]) == 0) + { + i = iNext; + continue; + } + + // ascend up next bound to LocMax + while (path[i].y <= vPrev->pt.y) + { + Vertex2* v = allVertices.emplace_back(new Vertex2(path[i])); + CreateEdge(vPrev, v, EdgeKind::ascend); + vPrev = v; + i = iNext; + iNext = Next(i, len); + + while (CrossProductSign(vPrev->pt, path[i], path[iNext]) == 0) + { + i = iNext; + iNext = Next(i, len); + } + } + + // Now at a locMax, so descend to next locMin + Vertex2* vPrevPrev = vPrev; + while (i != i0 && path[i].y >= vPrev->pt.y) + { + Vertex2* v = allVertices.emplace_back(new Vertex2(path[i])); + CreateEdge(v, vPrev, EdgeKind::descend); + vPrevPrev = vPrev; + vPrev = v; + i = iNext; + iNext = Next(i, len); + + while (CrossProductSign(vPrev->pt, path[i], path[iNext]) == 0) + { + i = iNext; + iNext = Next(i, len); + } + } + + // now at the next locMin + if (i == i0) break; // break for(;;) loop + if (LeftTurning(vPrevPrev->pt, vPrev->pt, path[i])) + vPrev->innerLM = true; + } + CreateEdge(v0, vPrev, EdgeKind::descend); + + // finally, ignore this path if is not a polygon or too small + len = allVertices.size() - vert_cnt; + i = vert_cnt; + if (len < 3 || (len == 3 && // or just a very tiny triangle + ((DistSqr(allVertices[i]->pt, allVertices[i + 1]->pt) <= 1) || + (DistSqr(allVertices[i + 1]->pt, allVertices[i + 2]->pt) <= 1) || + (DistSqr(allVertices[i + 2]->pt, allVertices[i]->pt) <= 1)))) + { + for (size_t j = vert_cnt; j < allVertices.size(); ++j) + allVertices[j]->edges.clear(); // flag to ignore + } + } + + bool Delaunay::AddPaths(const Paths64& paths) + { + const auto total_vertex_count = + std::accumulate(paths.begin(), paths.end(), size_t(0), + [](const auto& a, const Path64& path) + {return a + path.size(); }); + if (total_vertex_count == 0) return false; + allVertices.reserve(allVertices.capacity() + total_vertex_count); + allEdges.reserve(allEdges.capacity() + total_vertex_count); + + for (const Path64& path : paths) + AddPath(path); + return (allVertices.size() > 2); + } + + TriangulateResult Triangulate(const Paths64& pp, Paths64& solution, bool useDelaunay) + { + TriangulateResult result; + Delaunay d(useDelaunay); + solution = d.Execute(pp, result); + return result; + } + + TriangulateResult Triangulate(const PathsD& pp, int decPlaces, PathsD& solution, bool useDelaunay) + { + int ec; + double scale; + TriangulateResult result; + if (decPlaces <= 0) scale = 1; + else if (decPlaces > 8) scale = std::pow(10, 8); + else scale = std::pow(10, decPlaces); + Paths64 pp64 = ScalePaths(pp, scale, ec); + + Delaunay d(useDelaunay); + Paths64 sol64 = d.Execute(pp64, result); + solution = ScalePaths(sol64, 1 / scale, ec); + return result; + } + +} // Clipper2Lib namespace diff --git a/deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp b/deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp index f5c7c6f4fd..385bd37463 100644 --- a/deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp +++ b/deps_src/clipper2/Clipper2Lib/src/clipper2_z.cpp @@ -6,3 +6,4 @@ #include "clipper.engine.cpp" #include "clipper.offset.cpp" #include "clipper.rectclip.cpp" +#include "clipper.triangulation.cpp" diff --git a/deps_src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp b/deps_src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp index 63ed1c2779..381e4a7e90 100644 --- a/deps_src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp +++ b/deps_src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp @@ -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(); } diff --git a/deps_src/qhull/CMakeLists.txt b/deps_src/qhull/CMakeLists.txt index 9cead64e2c..82a7bf627e 100644 --- a/deps_src/qhull/CMakeLists.txt +++ b/deps_src/qhull/CMakeLists.txt @@ -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) diff --git a/docs/HLSD/polygon-clipping.md b/docs/HLSD/polygon-clipping.md new file mode 100644 index 0000000000..60bf97d515 --- /dev/null +++ b/docs/HLSD/polygon-clipping.md @@ -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`. diff --git a/docs/HLSD/scene-benchmark.md b/docs/HLSD/scene-benchmark.md new file mode 100644 index 0000000000..21e4ec574c --- /dev/null +++ b/docs/HLSD/scene-benchmark.md @@ -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. diff --git a/docs/HLSD/section-view.md b/docs/HLSD/section-view.md new file mode 100644 index 0000000000..1cc1fd726e --- /dev/null +++ b/docs/HLSD/section-view.md @@ -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. diff --git a/localization/i18n/list.txt b/localization/i18n/list.txt index 296829814a..d9f2049565 100644 --- a/localization/i18n/list.txt +++ b/localization/i18n/list.txt @@ -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 diff --git a/resources/images/canvas_section.svg b/resources/images/canvas_section.svg new file mode 100644 index 0000000000..553c01b22c --- /dev/null +++ b/resources/images/canvas_section.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_active.svg b/resources/images/canvas_section_active.svg new file mode 100644 index 0000000000..1d8351730b --- /dev/null +++ b/resources/images/canvas_section_active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_active_dark.svg b/resources/images/canvas_section_active_dark.svg new file mode 100644 index 0000000000..45cc5a09c6 --- /dev/null +++ b/resources/images/canvas_section_active_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_active_dark_hover.svg b/resources/images/canvas_section_active_dark_hover.svg new file mode 100644 index 0000000000..9472dd39cd --- /dev/null +++ b/resources/images/canvas_section_active_dark_hover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_active_hover.svg b/resources/images/canvas_section_active_hover.svg new file mode 100644 index 0000000000..8664ba71d9 --- /dev/null +++ b/resources/images/canvas_section_active_hover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_dark.svg b/resources/images/canvas_section_dark.svg new file mode 100644 index 0000000000..3f5660f889 --- /dev/null +++ b/resources/images/canvas_section_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_dark_hover.svg b/resources/images/canvas_section_dark_hover.svg new file mode 100644 index 0000000000..b0d38d38e5 --- /dev/null +++ b/resources/images/canvas_section_dark_hover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/canvas_section_hover.svg b/resources/images/canvas_section_hover.svg new file mode 100644 index 0000000000..6bd98eda77 --- /dev/null +++ b/resources/images/canvas_section_hover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/shaders/110/gouraud.fs b/resources/shaders/110/gouraud.fs index 59c4e4d410..c5efeef277 100644 --- a/resources/shaders/110/gouraud.fs +++ b/resources/shaders/110/gouraud.fs @@ -63,6 +63,10 @@ uniform float shadow_map_texel; // LIGHT_TOP_DIR in eye space (matches the diffuse light used for shading in gouraud.vs). const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : SHADOW_LIGHT_DIR; } varying vec3 clipping_planes_dots; varying float color_clip_plane_dot; @@ -155,7 +159,7 @@ float shadow_shade() // Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This // suppresses self-shadow acne without discarding real shadows cast by other objects onto // back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow). - float NdotL = dot(normalize(eye_normal), SHADOW_LIGHT_DIR); + float NdotL = dot(normalize(eye_normal), top_light_dir()); float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0)); // 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne. float sum = 0.0; diff --git a/resources/shaders/110/gouraud.vs b/resources/shaders/110/gouraud.vs index 184529be82..37be529b09 100644 --- a/resources/shaders/110/gouraud.vs +++ b/resources/shaders/110/gouraud.vs @@ -39,6 +39,10 @@ uniform vec2 z_range; uniform vec4 clipping_plane; // Color clip plane - general orientation. Used by the cut gizmo. uniform vec4 color_clip_plane; +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : LIGHT_TOP_DIR; } attribute vec3 v_position; attribute vec3 v_normal; @@ -60,11 +64,11 @@ void main() // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. - float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + float NdotL = max(dot(eye_normal, top_light_dir()), 0.0); intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; vec4 position = view_model_matrix * vec4(v_position, 1.0); - intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-top_light_dir(), eye_normal)), 0.0), LIGHT_TOP_SHININESS); // Perform the same lighting calculation for the 2nd light source (no specular applied). NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); diff --git a/resources/shaders/110/phong.fs b/resources/shaders/110/phong.fs index 5fedf7edff..7b9a522eaa 100644 --- a/resources/shaders/110/phong.fs +++ b/resources/shaders/110/phong.fs @@ -70,6 +70,10 @@ uniform sampler2D shadow_map; uniform mat4 shadow_light_vp; uniform float shadow_intensity; uniform float shadow_map_texel; +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : LIGHT_TOP_DIR; } varying vec3 clipping_planes_dots; varying float color_clip_plane_dot; @@ -193,7 +197,7 @@ float shadow_shade() // Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This // suppresses self-shadow acne without discarding real shadows cast by other objects onto // back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow). - float NdotL = dot(normalize(eye_normal), LIGHT_TOP_DIR); + float NdotL = dot(normalize(eye_normal), top_light_dir()); float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0)); // 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne. float sum = 0.0; @@ -248,9 +252,9 @@ void main() vec3 normal = normalize(eye_normal); vec3 view_dir = normalize(-eye_position); - float NdotL_top = max(dot(normal, LIGHT_TOP_DIR), 0.0); + float NdotL_top = max(dot(normal, top_light_dir()), 0.0); float diffuse = INTENSITY_AMBIENT + NdotL_top * LIGHT_TOP_DIFFUSE; - vec3 half_top = normalize(LIGHT_TOP_DIR + view_dir); + vec3 half_top = normalize(top_light_dir() + view_dir); float specular = LIGHT_TOP_SPECULAR * pow(max(dot(normal, half_top), 0.0), LIGHT_TOP_SHININESS); float NdotL_front = max(dot(normal, LIGHT_FRONT_DIR), 0.0); diff --git a/resources/shaders/110/printbed_shadow.fs b/resources/shaders/110/printbed_shadow.fs index a4fd6801dd..394cfac5ee 100644 --- a/resources/shaders/110/printbed_shadow.fs +++ b/resources/shaders/110/printbed_shadow.fs @@ -6,6 +6,8 @@ uniform sampler2D shadow_map; uniform mat4 shadow_light_vp; uniform float shadow_intensity; uniform float shadow_map_texel; +// Plate area a shadow can reach, min xy then max xy; the rest is skipped before any lookup. +uniform vec4 shadow_bounds; varying vec4 world_pos; @@ -33,6 +35,8 @@ float shadow_occlusion() void main() { + if (any(lessThan(world_pos.xy, shadow_bounds.xy)) || any(greaterThan(world_pos.xy, shadow_bounds.zw))) + discard; float occ = shadow_occlusion(); if (occ <= 0.0) discard; diff --git a/resources/shaders/140/gouraud.fs b/resources/shaders/140/gouraud.fs index e099984b46..7b315f90c0 100644 --- a/resources/shaders/140/gouraud.fs +++ b/resources/shaders/140/gouraud.fs @@ -72,6 +72,10 @@ uniform float shadow_map_texel; // LIGHT_TOP_DIR in eye space (matches the diffuse light used for shading in gouraud.vs). const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : SHADOW_LIGHT_DIR; } in vec3 clipping_planes_dots; in float color_clip_plane_dot; @@ -206,7 +210,7 @@ float shadow_shade() // Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This // suppresses self-shadow acne without discarding real shadows cast by other objects onto // back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow). - float NdotL = dot(normalize(eye_normal), SHADOW_LIGHT_DIR); + float NdotL = dot(normalize(eye_normal), top_light_dir()); float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0)); // 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne. float sum = 0.0; diff --git a/resources/shaders/140/gouraud.vs b/resources/shaders/140/gouraud.vs index a31e751964..11fc4b70c8 100644 --- a/resources/shaders/140/gouraud.vs +++ b/resources/shaders/140/gouraud.vs @@ -39,6 +39,10 @@ uniform vec2 z_range; uniform vec4 clipping_plane; // Color clip plane - general orientation. Used by the cut gizmo. uniform vec4 color_clip_plane; +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : LIGHT_TOP_DIR; } in vec3 v_position; in vec3 v_normal; @@ -60,11 +64,11 @@ void main() // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. - float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + float NdotL = max(dot(eye_normal, top_light_dir()), 0.0); intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; vec4 position = view_model_matrix * vec4(v_position, 1.0); - intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position.xyz), reflect(-top_light_dir(), eye_normal)), 0.0), LIGHT_TOP_SHININESS); // Perform the same lighting calculation for the 2nd light source (no specular applied). NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); diff --git a/resources/shaders/140/phong.fs b/resources/shaders/140/phong.fs index f847763658..03ffbb3e5c 100644 --- a/resources/shaders/140/phong.fs +++ b/resources/shaders/140/phong.fs @@ -80,6 +80,10 @@ uniform sampler2D shadow_map; uniform mat4 shadow_light_vp; uniform float shadow_intensity; uniform float shadow_map_texel; +// ORCA: realistic view - static shadows also light the scene from their fixed light. +uniform bool use_static_light; +uniform vec3 static_light_dir; +vec3 top_light_dir() { return use_static_light ? static_light_dir : LIGHT_TOP_DIR; } in vec3 clipping_planes_dots; in float color_clip_plane_dot; @@ -250,7 +254,7 @@ float shadow_shade() // Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This // suppresses self-shadow acne without discarding real shadows cast by other objects onto // back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow). - float NdotL = dot(normalize(eye_normal), LIGHT_TOP_DIR); + float NdotL = dot(normalize(eye_normal), top_light_dir()); float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0)); // 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne. float sum = 0.0; @@ -305,9 +309,9 @@ void main() vec3 normal = normalize(eye_normal); vec3 view_dir = normalize(-eye_position); - float NdotL_top = max(dot(normal, LIGHT_TOP_DIR), 0.0); + float NdotL_top = max(dot(normal, top_light_dir()), 0.0); float diffuse = INTENSITY_AMBIENT + NdotL_top * LIGHT_TOP_DIFFUSE; - vec3 half_top = normalize(LIGHT_TOP_DIR + view_dir); + vec3 half_top = normalize(top_light_dir() + view_dir); float specular = LIGHT_TOP_SPECULAR * pow(max(dot(normal, half_top), 0.0), LIGHT_TOP_SHININESS); float NdotL_front = max(dot(normal, LIGHT_FRONT_DIR), 0.0); diff --git a/resources/shaders/140/printbed_shadow.fs b/resources/shaders/140/printbed_shadow.fs index 650d88950e..8804806d64 100644 --- a/resources/shaders/140/printbed_shadow.fs +++ b/resources/shaders/140/printbed_shadow.fs @@ -6,6 +6,8 @@ uniform sampler2D shadow_map; uniform mat4 shadow_light_vp; uniform float shadow_intensity; uniform float shadow_map_texel; +// Plate area a shadow can reach, min xy then max xy; the rest is skipped before any lookup. +uniform vec4 shadow_bounds; in vec4 world_pos; @@ -35,6 +37,8 @@ float shadow_occlusion() void main() { + if (any(lessThan(world_pos.xy, shadow_bounds.xy)) || any(greaterThan(world_pos.xy, shadow_bounds.zw))) + discard; float occ = shadow_occlusion(); if (occ <= 0.0) discard; diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 87352f505e..992a9c9bc2 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -20,6 +20,49 @@ #endif /* SLIC3R_GUI */ #endif /* WIN32 */ +#include +#include +#include "libslic3r/PrintBase.hpp" +#include "slic3r/Utils/json_diff.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/LocalesUtils.hpp" +#include +#include +#include +#include "libslic3r/Color.hpp" +#include "libslic3r/TriangleSelector.hpp" +#include +#include "libslic3r/Format/bbs_3mf.hpp" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r_version.h" +#include "libslic3r/Semver.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/CustomGCode.hpp" +#include +#include +#include +#include +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/GCode/WipeTowerEstimate.hpp" +#include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" +#include +#include "libslic3r/Arrange.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" +#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLShader.hpp" +#include +#include +#include + #include #include #include diff --git a/src/OrcaSlicer.hpp b/src/OrcaSlicer.hpp index 380607e95f..9aceee4a20 100644 --- a/src/OrcaSlicer.hpp +++ b/src/OrcaSlicer.hpp @@ -1,7 +1,14 @@ #ifndef SLIC3R_HPP #define SLIC3R_HPP +#include +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Format/bbs_3mf.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" #include +#include +#include #include "libslic3r/Config.hpp" #include "libslic3r/Model.hpp" diff --git a/src/dev-utils/OrcaSlicer_profile_validator.cpp b/src/dev-utils/OrcaSlicer_profile_validator.cpp index c328c565c8..bbfa53c262 100644 --- a/src/dev-utils/OrcaSlicer_profile_validator.cpp +++ b/src/dev-utils/OrcaSlicer_profile_validator.cpp @@ -8,6 +8,28 @@ #define NANOSVGRAST_IMPLEMENTATION #include "nanosvg/nanosvgrast.h" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/PrintConfig.hpp" +#include +#include "libslic3r/CustomGCode.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/PlaceholderParser.hpp" +#include +#include +#include +#include + #include "libslic3r/BoundingBox.hpp" #include "libslic3r/GCode.hpp" #include "libslic3r/GCode/WipeTower.hpp" diff --git a/src/dev-utils/encoding-check.cpp b/src/dev-utils/encoding-check.cpp index 2a645e2ab2..0eb390f161 100644 --- a/src/dev-utils/encoding-check.cpp +++ b/src/dev-utils/encoding-check.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/dev-utils/generate_system_cache.cpp b/src/dev-utils/generate_system_cache.cpp index 017db79836..7baa11a8a0 100644 --- a/src/dev-utils/generate_system_cache.cpp +++ b/src/dev-utils/generate_system_cache.cpp @@ -4,9 +4,19 @@ #include #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include "libslic3r/Config.hpp" using namespace Slic3r; namespace fs = boost::filesystem; diff --git a/src/dev-utils/profile_include_dump.cpp b/src/dev-utils/profile_include_dump.cpp index f2486dedfc..6561027f70 100644 --- a/src/dev-utils/profile_include_dump.cpp +++ b/src/dev-utils/profile_include_dump.cpp @@ -11,13 +11,19 @@ #include "libslic3r/Utils.hpp" #include +#include +#include #include #include "nlohmann/json.hpp" #include +#include +#include #include +#include "libslic3r/Config.hpp" #include #include +#include #include #include diff --git a/src/libslic3r/AABBMesh.cpp b/src/libslic3r/AABBMesh.cpp index be026f69d7..bcd34546ed 100644 --- a/src/libslic3r/AABBMesh.cpp +++ b/src/libslic3r/AABBMesh.cpp @@ -1,10 +1,19 @@ #include "AABBMesh.hpp" +#include "Point.hpp" +#include #include +#include +#include +#include +#include +#include #include #include +#include #include +#include #ifdef SLIC3R_HOLE_RAYCASTER #include diff --git a/src/libslic3r/AABBMesh.hpp b/src/libslic3r/AABBMesh.hpp index 9998f504b5..c9195b2105 100644 --- a/src/libslic3r/AABBMesh.hpp +++ b/src/libslic3r/AABBMesh.hpp @@ -1,6 +1,10 @@ #ifndef PRUSASLICER_AABBMESH_H #define PRUSASLICER_AABBMESH_H +#include +#include +#include +#include #include #include diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp index 483ca8efc4..5fd83e0be9 100644 --- a/src/libslic3r/AABBTreeIndirect.hpp +++ b/src/libslic3r/AABBTreeIndirect.hpp @@ -6,15 +6,20 @@ #ifndef slic3r_AABBTreeIndirect_hpp_ #define slic3r_AABBTreeIndirect_hpp_ +#include #include +#include +#include #include #include +#include #include #include #include "BoundingBox.hpp" #include "Utils.hpp" // for next_highest_power_of_2() +#include "libslic3r.h" // Definition of the ray intersection hit structure. #include diff --git a/src/libslic3r/AABBTreeLines.hpp b/src/libslic3r/AABBTreeLines.hpp index 52c4cdf545..de0c88aeb1 100644 --- a/src/libslic3r/AABBTreeLines.hpp +++ b/src/libslic3r/AABBTreeLines.hpp @@ -6,9 +6,15 @@ #include "libslic3r.h" #include "libslic3r/AABBTreeIndirect.hpp" #include "libslic3r/Line.hpp" +#include #include +#include #include +#include +#include +#include #include +#include #include namespace Slic3r { diff --git a/src/libslic3r/AStar.hpp b/src/libslic3r/AStar.hpp index a7d9e7b8f9..e79295c503 100644 --- a/src/libslic3r/AStar.hpp +++ b/src/libslic3r/AStar.hpp @@ -1,7 +1,11 @@ #ifndef ASTAR_HPP #define ASTAR_HPP +#include #include // std::isinf() is here +#include +#include +#include #include #include "libslic3r/MutablePriorityQueue.hpp" diff --git a/src/libslic3r/Algorithm/LineSplit.cpp b/src/libslic3r/Algorithm/LineSplit.cpp index 9e359b76ea..789ca39be6 100644 --- a/src/libslic3r/Algorithm/LineSplit.cpp +++ b/src/libslic3r/Algorithm/LineSplit.cpp @@ -1,8 +1,20 @@ #include "LineSplit.hpp" #include "AABBTreeLines.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/ClipperZUtils.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExPolygon.hpp" #include "SVG.hpp" #include "Utils.hpp" +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include //#define DEBUG_SPLIT_LINE @@ -14,7 +26,7 @@ static std::atomic g_dbg_id = 0; #endif // Z for points from clip polygon -static constexpr auto CLIP_IDX = std::numeric_limits::max(); +static constexpr auto CLIP_IDX = std::numeric_limits::max(); static void cb_split_line(const ClipperZUtils::ZPoint& e1bot, const ClipperZUtils::ZPoint& e1top, @@ -91,14 +103,7 @@ SplittedLine do_split_line(const ClipperZUtils::ZPath& path, const ExPolygons& c clip_path.emplace_back(ClipperZUtils::to_zpath(hole.points, CLIP_IDX)); } - ClipperLib_Z::Clipper zclipper; - zclipper.PreserveCollinear(true); - zclipper.ZFillFunction(cb_split_line); - zclipper.AddPaths(clip_path, ClipperLib_Z::ptClip, true); - zclipper.AddPath(path, ClipperLib_Z::ptSubject, false); - ClipperLib_Z::PolyTree polytree; - zclipper.Execute(ClipperLib_Z::ctIntersection, polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); - ClipperLib_Z::PolyTreeToPaths(std::move(polytree), intersections); + intersections = ClipperZUtils::clip_zpaths(ctIntersection, ClipperZUtils::ZPaths{ path }, true, clip_path, cb_split_line, true); } if (intersections.empty()) { return {}; diff --git a/src/libslic3r/Algorithm/LineSplit.hpp b/src/libslic3r/Algorithm/LineSplit.hpp index e12113fa6c..098ff72d09 100644 --- a/src/libslic3r/Algorithm/LineSplit.hpp +++ b/src/libslic3r/Algorithm/LineSplit.hpp @@ -2,6 +2,12 @@ #define SRC_LIBSLIC3R_ALGORITHM_LINE_SPLIT_HPP_ #include "ClipperZUtils.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include +#include +#include +#include "libslic3r/ExPolygon.hpp" namespace Slic3r { namespace Algorithm { @@ -50,7 +56,7 @@ SplittedLine split_line(const PathType& path, const ExPolygons& clip, bool close // Convert the input path into an open ZPath ClipperZUtils::ZPath p; p.reserve(path.size() + (closed ? 1 : 0)); - ClipperLib_Z::cInt z = 0; + coord_t z = 0; for (const auto& point : path) { p.emplace_back(point.x(), point.y(), z); z++; diff --git a/src/libslic3r/Algorithm/RegionExpansion.cpp b/src/libslic3r/Algorithm/RegionExpansion.cpp index 6a77c470e7..a4558a3939 100644 --- a/src/libslic3r/Algorithm/RegionExpansion.cpp +++ b/src/libslic3r/Algorithm/RegionExpansion.cpp @@ -1,16 +1,30 @@ #include "RegionExpansion.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Polygon.hpp" +#include +#include +#include +#include +#include +#include #include #include #include #include +#include #include +#include +#include namespace Slic3r { namespace Algorithm { -// Calculating radius discretization according to ClipperLib offsetter code, see void ClipperOffset::DoOffset(double delta) +// Calculating radius discretization according to the Clipper offsetter code, see ClipperOffset::DoGroupOffset() inline double clipper_round_offset_error(double offset, double arc_tolerance) { static constexpr const double def_arc_tolerance = 0.25; @@ -61,7 +75,6 @@ RegionExpansionParameters RegionExpansionParameters::build( // Accuracy of the offsetter for wave propagation. out.arc_tolerance = scaled(0.1); - out.shortest_edge_length = out.initial_step * ClipperOffsetShortestEdgeFactor; // Maximum inflation of seed contours over the boundary. Used to trim boundary to speed up // clipping during wave propagation. Needs to be in sync with the offsetter accuracy. @@ -75,25 +88,20 @@ RegionExpansionParameters RegionExpansionParameters::build( // similar to expolygons_to_zpaths(), but each contour is expanded before converted to zpath. // The expanded contours are then opened (the first point is repeated at the end). -static ClipperLib_Z::Paths expolygons_to_zpaths_expanded_opened( +static ClipperZUtils::ZPaths expolygons_to_zpaths_expanded_opened( const ExPolygons &src, const float expansion, coord_t &base_idx) { - ClipperLib_Z::Paths out; + ClipperZUtils::ZPaths out; out.reserve(2 * std::accumulate(src.begin(), src.end(), size_t(0), [](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); })); - ClipperLib::ClipperOffset offsetter; - offsetter.ShortestEdgeLength = expansion * ClipperOffsetShortestEdgeFactor; - ClipperLib::Paths expansion_cache; for (const ExPolygon &expoly : src) { for (size_t icontour = 0; icontour < expoly.num_contours(); ++ icontour) { - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - offsetter.Clear(); - offsetter.AddPath(expoly.contour_or_hole(icontour).points, ClipperLib::jtSquare, ClipperLib::etClosedPolygon); - expansion_cache.clear(); - offsetter.Execute(expansion_cache, icontour == 0 ? expansion : -expansion); - append(out, ClipperZUtils::to_zpaths(expansion_cache, base_idx)); + // Orient CCW, then grow the contour and shrink the holes. The output contours are CCW. + Polygon contour = expoly.contour_or_hole(icontour); + if (! contour.is_counter_clockwise()) + contour.reverse(); + for (const Polygon &expanded : offset(contour, icontour == 0 ? expansion : -expansion, jtSquare)) + out.emplace_back(ClipperZUtils::to_zpath(expanded.points, base_idx)); } ++ base_idx; } @@ -104,21 +112,21 @@ static ClipperLib_Z::Paths expolygons_to_zpaths_expanded_opened( // Thus some pieces of the clipped polygons may now become split at the ends of the source polygons. // Those ends are sorted lexicographically in "splits". // Reconnect those split pieces. -static inline void merge_splits(ClipperLib_Z::Paths &paths, std::vector> &splits) +static inline void merge_splits(ClipperZUtils::ZPaths &paths, std::vector> &splits) { for (auto it_path = paths.begin(); it_path != paths.end(); ) { - ClipperLib_Z::Path &path = *it_path; + ClipperZUtils::ZPath &path = *it_path; assert(path.size() >= 2); bool merged = false; if (path.size() >= 2) { - const ClipperLib_Z::IntPoint &front = path.front(); - const ClipperLib_Z::IntPoint &back = path.back(); + const ClipperZUtils::ZPoint &front = path.front(); + const ClipperZUtils::ZPoint &back = path.back(); // The path before clipping was supposed to cross the clipping boundary or be fully out of it. // Thus the clipped contour is supposed to become open, with one exception: The anchor expands into a closed hole. if (front.x() != back.x() || front.y() != back.y()) { // Look up the ends in "splits", possibly join the contours. // "splits" maps into the other piece connected to the same end point. - auto find_end = [&splits](const ClipperLib_Z::IntPoint &pt) -> std::pair* { + auto find_end = [&splits](const ClipperZUtils::ZPoint &pt) -> std::pair* { auto it = std::lower_bound(splits.begin(), splits.end(), pt, [](const auto &l, const auto &r){ return ClipperZUtils::zpoint_lower(l.first, r); }); return it != splits.end() && it->first == pt ? &(*it) : nullptr; @@ -136,7 +144,7 @@ static inline void merge_splits(ClipperLib_Z::Paths &paths, std::vectorsecond = int(it_path - paths.begin()); } else { // Open end was found and matched with end->second - ClipperLib_Z::Path &other_path = paths[end->second]; + ClipperZUtils::ZPath &other_path = paths[end->second]; polylines_merge(other_path, other_path.front() == end->first, std::move(path), end_front); if (std::next(it_path) == paths.end()) { paths.pop_back(); @@ -212,36 +220,29 @@ std::vector wave_seeds( using Intersection = ClipperZUtils::ClipperZIntersectionVisitor::Intersection; using Intersections = ClipperZUtils::ClipperZIntersectionVisitor::Intersections; - ClipperLib_Z::Paths segments; - Intersections intersections; + ClipperZUtils::ZPaths segments; + Intersections intersections; - coord_t idx_boundary_begin = 1; - coord_t idx_boundary_end = idx_boundary_begin; - coord_t idx_src_end; + coord_t idx_boundary_begin = 1; + coord_t idx_boundary_end = idx_boundary_begin; + coord_t idx_src_end; { - ClipperLib_Z::Clipper zclipper; ClipperZUtils::ClipperZIntersectionVisitor visitor(intersections); - zclipper.ZFillFunction(visitor.clipper_callback()); // as closed contours - zclipper.AddPaths(ClipperZUtils::expolygons_to_zpaths(boundary, idx_boundary_end), ClipperLib_Z::ptClip, true); + ClipperZUtils::ZPaths zboundary = ClipperZUtils::expolygons_to_zpaths(boundary, idx_boundary_end); // as open contours - std::vector> zsrc_splits; - { - idx_src_end = idx_boundary_end; - ClipperLib_Z::Paths zsrc = expolygons_to_zpaths_expanded_opened(src, tiny_expansion, idx_src_end); - zclipper.AddPaths(zsrc, ClipperLib_Z::ptSubject, false); - zsrc_splits.reserve(zsrc.size()); - for (const ClipperLib_Z::Path &path : zsrc) { - assert(path.size() >= 2); - assert(path.front() == path.back()); - zsrc_splits.emplace_back(path.front(), -1); - } - std::sort(zsrc_splits.begin(), zsrc_splits.end(), [](const auto &l, const auto &r){ return ClipperZUtils::zpoint_lower(l.first, r.first); }); + std::vector> zsrc_splits; + idx_src_end = idx_boundary_end; + ClipperZUtils::ZPaths zsrc = expolygons_to_zpaths_expanded_opened(src, tiny_expansion, idx_src_end); + zsrc_splits.reserve(zsrc.size()); + for (const ClipperZUtils::ZPath &path : zsrc) { + assert(path.size() >= 2); + assert(path.front() == path.back()); + zsrc_splits.emplace_back(path.front(), -1); } - ClipperLib_Z::PolyTree polytree; - zclipper.Execute(ClipperLib_Z::ctIntersection, polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); - ClipperLib_Z::PolyTreeToPaths(std::move(polytree), segments); + std::sort(zsrc_splits.begin(), zsrc_splits.end(), [](const auto &l, const auto &r){ return ClipperZUtils::zpoint_lower(l.first, r.first); }); + segments = ClipperZUtils::clip_zpaths(ctIntersection, zsrc, true, zboundary, visitor.clipper_callback()); merge_splits(segments, zsrc_splits); } @@ -256,10 +257,10 @@ std::vector wave_seeds( WaveSeeds out; out.reserve(segments.size()); int iseed = 0; - for (const ClipperLib_Z::Path &path : segments) { + for (const ClipperZUtils::ZPath &path : segments) { assert(path.size() >= 2); - ClipperLib_Z::IntPoint front = path.front(); - ClipperLib_Z::IntPoint back = path.back(); + ClipperZUtils::ZPoint front = path.front(); + ClipperZUtils::ZPoint back = path.back(); // Both ends of a seed segment are supposed to be inside a single boundary expolygon. // Thus as long as the seed contour is not closed, it should be open at a boundary point. assert((front == back && front.z() >= idx_boundary_end && front.z() < idx_src_end) || @@ -280,7 +281,7 @@ std::vector wave_seeds( // boundary ID is not directly available). coord_t src_z = -1, boundary_z = -1; // Scan all path points for the information we need. - for (const ClipperLib_Z::IntPoint &point : path) { + for (const ClipperZUtils::ZPoint &point : path) { if (point.z() >= idx_boundary_end && point.z() < idx_src_end && src_z < 0) src_z = point.z(); else if (point.z() >= idx_boundary_begin && point.z() < idx_boundary_end && boundary_z < 0) @@ -311,7 +312,7 @@ std::vector wave_seeds( // See https://github.com/prusa3d/PrusaSlicer/issues/12469. // Segement is open, yet its first point seems to be part of boundary polygon. // Take the first point with src polygon index. - for (const ClipperLib_Z::IntPoint &point : path) { + for (const ClipperZUtils::ZPoint &point : path) { if (point.z() >= idx_boundary_end) { front = point; back = point; @@ -360,17 +361,13 @@ std::vector wave_seeds( return out; } -static ClipperLib::Paths wavefront_initial(ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polylines, float offset) +static Polygons wavefront_initial(const VecOfPoints &polylines, float offset, double arc_tolerance) { - ClipperLib::Paths out; + Polygons out; out.reserve(polylines.size()); - ClipperLib::Paths out_this; - for (const ClipperLib::Path &path : polylines) { + for (const Points &path : polylines) { assert(path.size() >= 2); - co.Clear(); - co.AddPath(path, jtRound, path.front() == path.back() ? ClipperLib::etClosedLine : ClipperLib::etOpenRound); - co.Execute(out_this, offset); - append(out, std::move(out_this)); + append(out, Slic3r::offset(Polyline(path), offset, jtRound, arc_tolerance, path.front() == path.back() ? etClosedLine : etOpenRound)); } return out; } @@ -378,43 +375,24 @@ static ClipperLib::Paths wavefront_initial(ClipperLib::ClipperOffset &co, const // Input polygons may consist of multiple expolygons, even nested expolygons. // After inflation some polygons may thus overlap, however the overlap is being resolved during the successive // clipping operation, thus it is not being done here. -static ClipperLib::Paths wavefront_step(ClipperLib::ClipperOffset &co, const ClipperLib::Paths &polygons, float offset) +static Polygons wavefront_step(const Polygons &polygons, float offset, double arc_tolerance) { - ClipperLib::Paths out; + Polygons out; out.reserve(polygons.size()); - ClipperLib::Paths out_this; - for (const ClipperLib::Path &polygon : polygons) { - co.Clear(); - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.AddPath(polygon, jtRound, ClipperLib::etClosedPolygon); - bool ccw = ClipperLib::Orientation(polygon); - co.Execute(out_this, ccw ? offset : - offset); - if (! ccw) { - // Reverse the resulting contours. - for (ClipperLib::Path &path : out_this) - std::reverse(path.begin(), path.end()); - } - append(out, std::move(out_this)); - } + for (const Polygon &polygon : polygons) + // CCW contours grow, CW holes shrink. + append(out, Slic3r::offset(polygon, offset, jtRound, arc_tolerance)); return out; } -static ClipperLib::Paths wavefront_clip(const ClipperLib::Paths &wavefront, const Polygons &clipping) +static Polygons wavefront_clip(const Polygons &wavefront, const Polygons &clipping) { - ClipperLib::Clipper clipper; - clipper.AddPaths(wavefront, ClipperLib::ptSubject, true); - clipper.AddPaths(ClipperUtils::PolygonsProvider(clipping), ClipperLib::ptClip, true); - ClipperLib::Paths out; - clipper.Execute(ClipperLib::ctIntersection, out, ClipperLib::pftPositive, ClipperLib::pftPositive); - return out; + return intersection(wavefront, clipping, pftPositive); } static Polygons propagate_wave_from_boundary( - ClipperLib::ClipperOffset &co, // Seed of the wave: Open polylines very close to the boundary. - const ClipperLib::Paths &seed, + const VecOfPoints &seed, // Boundary inside which the waveform will propagate. const ExPolygon &boundary, // How much to inflate the seed lines to produce the first wave area. @@ -425,25 +403,24 @@ static Polygons propagate_wave_from_boundary( const size_t num_other_steps, // Maximum inflation of seed contours over the boundary. Used to trim boundary to speed up // clipping during wave propagation. - const float max_inflation) + const float max_inflation, + // Accuracy of the round offsets. + const double arc_tolerance) { assert(! seed.empty() && seed.front().size() >= 2); Polygons clipping = ClipperUtils::clip_clipper_polygons_with_subject_bbox(boundary, get_extents(seed).inflated(max_inflation)); - ClipperLib::Paths polygons = wavefront_clip(wavefront_initial(co, seed, initial_step), clipping); + Polygons polygons = wavefront_clip(wavefront_initial(seed, initial_step, arc_tolerance), clipping); // Now offset the remaining for (size_t ioffset = 0; ioffset < num_other_steps; ++ ioffset) - polygons = wavefront_clip(wavefront_step(co, polygons, other_step), clipping); - return to_polygons(polygons); + polygons = wavefront_clip(wavefront_step(polygons, other_step, arc_tolerance), clipping); + return polygons; } // Resulting regions are sorted by boundary id and source id. std::vector propagate_waves(const WaveSeeds &seeds, const ExPolygons &boundary, const RegionExpansionParameters ¶ms) { std::vector out; - ClipperLib::Paths paths; - ClipperLib::ClipperOffset co; - co.ArcTolerance = params.arc_tolerance; - co.ShortestEdgeLength = params.shortest_edge_length; + VecOfPoints paths; for (auto it_seed = seeds.begin(); it_seed != seeds.end();) { auto it = it_seed; paths.clear(); @@ -452,7 +429,7 @@ std::vector propagate_waves(const WaveSeeds &seeds, const ExPol // Propagate the wavefront while clipping it with the trimmed boundary. // Collect the expanded polygons, merge them with the source polygons. RegionExpansion re; - for (Polygon &polygon : propagate_wave_from_boundary(co, paths, boundary[it_seed->boundary], params.initial_step, params.other_step, params.num_other_steps, params.max_inflation)) + for (Polygon &polygon : propagate_wave_from_boundary(paths, boundary[it_seed->boundary], params.initial_step, params.other_step, params.num_other_steps, params.max_inflation, params.arc_tolerance)) out.push_back({ std::move(polygon), it_seed->src, it_seed->boundary }); it_seed = it; } diff --git a/src/libslic3r/Algorithm/RegionExpansion.hpp b/src/libslic3r/Algorithm/RegionExpansion.hpp index eb99674902..b493b72d5c 100644 --- a/src/libslic3r/Algorithm/RegionExpansion.hpp +++ b/src/libslic3r/Algorithm/RegionExpansion.hpp @@ -1,10 +1,12 @@ #ifndef SRC_LIBSLIC3R_ALGORITHM_REGION_EXPANSION_HPP_ #define SRC_LIBSLIC3R_ALGORITHM_REGION_EXPANSION_HPP_ +#include #include #include #include #include +#include namespace Slic3r { namespace Algorithm { @@ -25,7 +27,6 @@ struct RegionExpansionParameters // Accuracy of the offsetter for wave propagation. double arc_tolerance; - double shortest_edge_length; static RegionExpansionParameters build( // Scaled expansion value diff --git a/src/libslic3r/AnyPtr.hpp b/src/libslic3r/AnyPtr.hpp index c40d10093e..7c0f28b834 100644 --- a/src/libslic3r/AnyPtr.hpp +++ b/src/libslic3r/AnyPtr.hpp @@ -1,6 +1,7 @@ #ifndef ANYPTR_HPP #define ANYPTR_HPP +#include #include #include #include diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index d639604f51..663072d866 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -1,3 +1,8 @@ +#include "Technologies.hpp" +#include "Config.hpp" +#include "PrintConfig.hpp" +#include "calib.hpp" +#include "Semver.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "libslic3r/Format/DRC.hpp" @@ -9,9 +14,18 @@ #include "LocalesUtils.hpp" #include "Thread.hpp" #include "format.hpp" +#include "libslic3r_version.h" #include "nlohmann/json.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -304,6 +318,9 @@ void AppConfig::set_defaults() if (get(SETTING_OPENGL_SHOW_FPS_OVERLAY).empty()) set_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY, false); + if (get(SETTING_OPENGL_SHOW_RENDER_TIMINGS).empty()) + set_bool(SETTING_OPENGL_SHOW_RENDER_TIMINGS, false); + if (get(SETTING_OPENGL_REALISTIC_MODE).empty()) set_bool(SETTING_OPENGL_REALISTIC_MODE, false); @@ -316,8 +333,9 @@ void AppConfig::set_defaults() if (get(SETTING_OPENGL_SHADING_MODEL).empty()) set(SETTING_OPENGL_SHADING_MODEL, "gouraud"); - if (get(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS).empty()) - set_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS, false); + // Replaces the on/off setting, whose shadows turned with the camera. + if (get(SETTING_OPENGL_REALISTIC_SHADOWS).empty()) + set(SETTING_OPENGL_REALISTIC_SHADOWS, get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS) ? "orbit" : "off"); if (get(SETTING_OPENGL_PHONG_SMOOTH_NORMALS).empty()) set_bool(SETTING_OPENGL_PHONG_SMOOTH_NORMALS, false); diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 1bf6e730d0..a08c018bb2 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -5,8 +5,11 @@ #include #include #include +#include "LocalesUtils.hpp" #include "nlohmann/json.hpp" #include +#include +#include #include "libslic3r/Config.hpp" #include "libslic3r/Semver.hpp" @@ -37,10 +40,13 @@ using namespace nlohmann; #define SETTING_OPENGL_SCENE_CACHE "opengl_scene_cache" #define SETTING_OPENGL_SKIP_IDENTICAL_FRAMES "opengl_skip_identical_frames" #define SETTING_OPENGL_SHOW_FPS_OVERLAY "opengl_show_fps_overlay" +#define SETTING_OPENGL_SHOW_RENDER_TIMINGS "opengl_show_render_timings" #define SETTING_OPENGL_REALISTIC_MODE "opengl_realistic_mode" #define SETTING_OPENGL_REALISTIC_PHONG "opengl_realistic_phong" #define SETTING_OPENGL_SHADING_MODEL "opengl_shading_model" #define SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS "opengl_phong_basic_plate_shadows" +// off, static (light fixed in the world) or orbit (light turning with the camera) +#define SETTING_OPENGL_REALISTIC_SHADOWS "opengl_realistic_shadows" #define SETTING_OPENGL_PHONG_SSAO "opengl_phong_ssao" #define SETTING_OPENGL_PHONG_SMOOTH_NORMALS "opengl_phong_smooth_normals" #define SETTING_OPENGL_REALISTIC_PREVIEW "opengl_realistic_preview" diff --git a/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategy.cpp index 5ade0c9207..119ff8dd99 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategy.cpp @@ -2,7 +2,9 @@ //CuraEngine is released under the terms of the AGPLv3 or higher. #include "BeadingStrategy.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" +#include namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.cpp b/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.cpp index d6cb1331c1..242d54e63b 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.cpp @@ -12,6 +12,7 @@ #include "DistributedBeadingStrategy.hpp" #include "RedistributeBeadingStrategy.hpp" #include "OuterWallInsetBeadingStrategy.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/BeadingStrategy/DistributedBeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/DistributedBeadingStrategy.cpp index 7234015ae2..966682e054 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/DistributedBeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/DistributedBeadingStrategy.cpp @@ -6,6 +6,7 @@ #include #include "DistributedBeadingStrategy.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/BeadingStrategy/LimitedBeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/LimitedBeadingStrategy.cpp index 24e04c3f26..0c570bf307 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/LimitedBeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/LimitedBeadingStrategy.cpp @@ -3,10 +3,12 @@ #include #include +#include #include #include #include "LimitedBeadingStrategy.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" diff --git a/src/libslic3r/Arachne/BeadingStrategy/OuterWallInsetBeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/OuterWallInsetBeadingStrategy.cpp index ac9edb1dba..1b7bd7e342 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/OuterWallInsetBeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/OuterWallInsetBeadingStrategy.cpp @@ -6,6 +6,7 @@ #include #include +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp index 7307781840..e6a3c337ae 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/RedistributeBeadingStrategy.cpp @@ -7,6 +7,7 @@ #include #include +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/BeadingStrategy/WideningBeadingStrategy.cpp b/src/libslic3r/Arachne/BeadingStrategy/WideningBeadingStrategy.cpp index ab8b070604..0ceb2d9dd3 100644 --- a/src/libslic3r/Arachne/BeadingStrategy/WideningBeadingStrategy.cpp +++ b/src/libslic3r/Arachne/BeadingStrategy/WideningBeadingStrategy.cpp @@ -4,8 +4,11 @@ #include "WideningBeadingStrategy.hpp" #include +#include #include +#include +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp index da5c7357c1..82ca92e090 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp @@ -10,10 +10,18 @@ #include #include #include +#include +#include +#include #include #include #include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" #include "libslic3r/Geometry/VoronoiUtils.hpp" #include "ankerl/unordered_dense.h" #include "libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp" diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp index e0d3fe81d2..9eced8be93 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp @@ -4,10 +4,12 @@ #ifndef SKELETAL_TRAPEZOIDATION_EDGE_H #define SKELETAL_TRAPEZOIDATION_EDGE_H +#include #include // smart pointers #include #include +#include "libslic3r/libslic3r.h" #include "utils/ExtrusionJunction.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp index f7a30c32db..4621a04616 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationGraph.cpp @@ -6,11 +6,17 @@ #include #include #include +#include #include #include #include +#include +#include #include "../Line.hpp" +#include "libslic3r/Arachne/utils/HalfEdge.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Arachne/utils/HalfEdgeNode.hpp" #include "libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp" #include "libslic3r/Arachne/SkeletalTrapezoidationJoint.hpp" #include "libslic3r/Point.hpp" diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationJoint.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidationJoint.hpp index 346d511165..3eab9c0916 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationJoint.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationJoint.hpp @@ -6,6 +6,7 @@ #include // smart pointers +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" namespace Slic3r::Arachne diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index 724016bcb1..a116674daa 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -2,12 +2,31 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include //For std::partition_copy and std::min_element. +#include +#include +#include +#include +#include +#include +#include #include #include "WallToolPaths.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Arachne/utils/ExtrusionLine.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Arachne/utils/PolygonsPointIndex.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.hpp" +#include "libslic3r/Arachne/utils/ExtrusionJunction.hpp" +#include "libslic3r/Arachne/utils/SparsePointGrid.hpp" +#include "libslic3r/Arachne/utils/SquareGrid.hpp" #include "SkeletalTrapezoidation.hpp" #include "../ClipperUtils.hpp" +#include "libslic3r/libslic3r.h" #include "utils/linearAlg2D.hpp" #include "EdgeGrid.hpp" #include "utils/SparseLineGrid.hpp" @@ -17,6 +36,8 @@ #include "Utils.hpp" #include +#include +#include //#define ARACHNE_STITCH_PATCH_DEBUG @@ -263,10 +284,8 @@ std::unique_ptr cre */ void fixSelfIntersections(const coord_t epsilon, Polygons &thiss) { - if (epsilon < 1) { - ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss), ClipperLib::pftEvenOdd); + if (epsilon < 1) return; - } const int64_t half_epsilon = (epsilon + 1) / 2; @@ -304,8 +323,6 @@ void fixSelfIntersections(const coord_t epsilon, Polygons &thiss) } } } - - ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss), ClipperLib::pftEvenOdd); } /*! @@ -352,18 +369,11 @@ void removeDegenerateVerts(Polygons &thiss) void removeSmallAreas(Polygons &thiss, const double min_area_size, const bool remove_holes) { - auto to_path = [](const Polygon &poly) -> ClipperLib::Path { - ClipperLib::Path out; - for (const Point &pt : poly.points) - out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y())); - return out; - }; - auto new_end = thiss.end(); if (remove_holes) { for (auto it = thiss.begin(); it < new_end;) { // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector. - if (fabs(ClipperLib::Area(to_path(*it))) < min_area_size) { + if (fabs(it->area()) < min_area_size) { --new_end; *it = std::move(*new_end); continue; // Don't increment the iterator such that the polygon just swapped in is checked next. @@ -374,7 +384,7 @@ void removeSmallAreas(Polygons &thiss, const double min_area_size, const bool re // For each polygon, computes the signed area, move small outlines at the end of the vector and keep pointer on small holes Polygons small_holes; for (auto it = thiss.begin(); it < new_end;) { - if (double area = ClipperLib::Area(to_path(*it)); fabs(area) < min_area_size) { + if (double area = it->area(); fabs(area) < min_area_size) { if (area >= 0) { --new_end; if (it < new_end) { @@ -773,7 +783,7 @@ void WallToolPaths::separateOutInnerContour() //To get a correct shape, we need to make the outside contour positive and any holes inside negative. //This can be done by applying the even-odd rule to the shape. This rule is not sensitive to the winding order of the polygon. //The even-odd rule would be incorrect if the polygon self-intersects, but that should never be generated by the skeletal trapezoidation. - inner_contour = union_(inner_contour, ClipperLib::PolyFillType::pftEvenOdd); + inner_contour = union_(inner_contour, pftEvenOdd); } const Polygons& WallToolPaths::getInnerContour() diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index d7120a088c..cfec7284eb 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -4,10 +4,16 @@ #ifndef CURAENGINE_WALLTOOLPATHS_H #define CURAENGINE_WALLTOOLPATHS_H +#include +#include #include #include +#include +#include #include "BeadingStrategy/BeadingStrategyFactory.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" #include "utils/ExtrusionLine.hpp" #include "../Polygon.hpp" #include "../PrintConfig.hpp" diff --git a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp index 625bf9b727..aebfd81347 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionJunction.hpp @@ -6,6 +6,9 @@ #define UTILS_EXTRUSION_JUNCTION_H #include "../../Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp index 66bb707ebe..c1c29c50e9 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp @@ -2,11 +2,17 @@ //CuraEngine is released under the terms of the AGPLv3 or higher. #include +#include #include +#include #include +#include #include "ExtrusionLine.hpp" #include "../../VariableWidth.hpp" +#include "libslic3r/ClipperZUtils.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" #include "libslic3r/Arachne/utils/ExtrusionJunction.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ExtrusionEntity.hpp" @@ -287,9 +293,9 @@ double ExtrusionLine::area() const } // namespace Slic3r::Arachne namespace Slic3r { -void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extrusion_paths, const ExtrusionRole role, const Flow &flow) +void extrusion_paths_append(ExtrusionPaths &dst, const ClipperZUtils::ZPaths &extrusion_paths, const ExtrusionRole role, const Flow &flow) { - for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) { + for (const ClipperZUtils::ZPath &extrusion_path : extrusion_paths) { ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path); Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled(0.05), float(SCALED_EPSILON)).paths); } diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index 72e008cef1..421f73e0e8 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -5,7 +5,7 @@ #ifndef UTILS_EXTRUSION_LINE_H #define UTILS_EXTRUSION_LINE_H -#include +#include "../../ClipperZUtils.hpp" #include #include #include @@ -22,6 +22,7 @@ #include "../../BoundingBox.hpp" #include "../../ExtrusionEntity.hpp" #include "../../Flow.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" namespace Slic3r { @@ -294,7 +295,7 @@ using VariableWidthLines = std::vector; // +#include +#include #include #include "../../Point.hpp" diff --git a/src/libslic3r/Arachne/utils/PolygonsSegmentIndex.hpp b/src/libslic3r/Arachne/utils/PolygonsSegmentIndex.hpp index 3258b41c7d..2df641c085 100644 --- a/src/libslic3r/Arachne/utils/PolygonsSegmentIndex.hpp +++ b/src/libslic3r/Arachne/utils/PolygonsSegmentIndex.hpp @@ -6,7 +6,10 @@ #include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" #include "PolygonsPointIndex.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/utils/PolylineStitcher.cpp b/src/libslic3r/Arachne/utils/PolylineStitcher.cpp index 0abf63ac10..e011e5db51 100644 --- a/src/libslic3r/Arachne/utils/PolylineStitcher.cpp +++ b/src/libslic3r/Arachne/utils/PolylineStitcher.cpp @@ -4,6 +4,7 @@ #include "PolylineStitcher.hpp" #include "ExtrusionLine.hpp" +#include "libslic3r/Point.hpp" #include "libslic3r/Arachne/utils/PolygonsPointIndex.hpp" #include "libslic3r/Polygon.hpp" diff --git a/src/libslic3r/Arachne/utils/SparseGrid.hpp b/src/libslic3r/Arachne/utils/SparseGrid.hpp index 45876fb9a7..ce5bac81bc 100644 --- a/src/libslic3r/Arachne/utils/SparseGrid.hpp +++ b/src/libslic3r/Arachne/utils/SparseGrid.hpp @@ -6,11 +6,14 @@ #define UTILS_SPARSE_GRID_H #include +#include +#include #include #include #include "../../Point.hpp" #include "SquareGrid.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/utils/SparseLineGrid.hpp b/src/libslic3r/Arachne/utils/SparseLineGrid.hpp index 0b38988f92..be3c430749 100644 --- a/src/libslic3r/Arachne/utils/SparseLineGrid.hpp +++ b/src/libslic3r/Arachne/utils/SparseLineGrid.hpp @@ -6,10 +6,15 @@ #define UTILS_SPARSE_LINE_GRID_H #include +#include +#include +#include #include #include +#include "libslic3r/Point.hpp" #include "SparseGrid.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/utils/SparsePointGrid.hpp b/src/libslic3r/Arachne/utils/SparsePointGrid.hpp index 127380b3eb..ba1898a0ae 100644 --- a/src/libslic3r/Arachne/utils/SparsePointGrid.hpp +++ b/src/libslic3r/Arachne/utils/SparsePointGrid.hpp @@ -6,9 +6,13 @@ #define UTILS_SPARSE_POINT_GRID_H #include +#include +#include #include +#include "libslic3r/Point.hpp" #include "SparseGrid.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r::Arachne { diff --git a/src/libslic3r/Arachne/utils/SquareGrid.cpp b/src/libslic3r/Arachne/utils/SquareGrid.cpp index 1af9910426..dcbd018f1b 100644 --- a/src/libslic3r/Arachne/utils/SquareGrid.cpp +++ b/src/libslic3r/Arachne/utils/SquareGrid.cpp @@ -4,7 +4,11 @@ #include "SquareGrid.hpp" #include +#include +#include +#include +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" using namespace Slic3r::Arachne; diff --git a/src/libslic3r/Arachne/utils/linearAlg2D.hpp b/src/libslic3r/Arachne/utils/linearAlg2D.hpp index 599d3fa835..632032da8f 100644 --- a/src/libslic3r/Arachne/utils/linearAlg2D.hpp +++ b/src/libslic3r/Arachne/utils/linearAlg2D.hpp @@ -5,6 +5,9 @@ #define UTILS_LINEAR_ALG_2D_H #include "../../Point.hpp" +#include +#include +#include namespace Slic3r::Arachne::LinearAlg2D { diff --git a/src/libslic3r/ArcFitter.cpp b/src/libslic3r/ArcFitter.cpp index 46dd12931e..8bd1bc4fe6 100644 --- a/src/libslic3r/ArcFitter.cpp +++ b/src/libslic3r/ArcFitter.cpp @@ -1,8 +1,14 @@ #include "ArcFitter.hpp" +#include "Point.hpp" +#include "Circle.hpp" +#include "MultiPoint.hpp" #include "Polyline.hpp" +#include "libslic3r.h" #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ArcFitter.hpp b/src/libslic3r/ArcFitter.hpp index f2b2ee49d8..03d38abc85 100644 --- a/src/libslic3r/ArcFitter.hpp +++ b/src/libslic3r/ArcFitter.hpp @@ -2,6 +2,9 @@ #define slic3r_ArcFitter_hpp_ #include "Circle.hpp" +#include +#include "Point.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index fd496537f4..8a2cace499 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -1,9 +1,28 @@ #include "Arrange.hpp" +#include "ExPolygon.hpp" +#include "Point.hpp" #include "Print.hpp" #include "BoundingBox.hpp" +#include "PrintConfig.hpp" #include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include "libnest2d/common.hpp" +#include "libnest2d/geometry_traits_nfp.hpp" +#include "libnest2d/nester.hpp" +#include "libnest2d/geometry_traits.hpp" #include #include #include @@ -13,6 +32,11 @@ #include #include +#include +#include +#include +#include +#include #if defined(_MSC_VER) && defined(__clang__) #define BOOST_NO_CXX17_HDR_STRING_VIEW @@ -55,7 +79,7 @@ namespace Slic3r { template, int...EigenArgs> inline constexpr Eigen::Matrix unscaled( - const Slic3r::ClipperLib::IntPoint &v) noexcept + const Slic3r::Point &v) noexcept { return Eigen::Matrix{unscaled(v.x()), unscaled(v.y())}; @@ -405,7 +429,7 @@ protected: // 2) X distance of item corner to bed corner (low weight) // 3) item row occupancy (useful when rotation is enabled) // 4)需要允许往屏蔽区域的左边或下边去一点,不然很多物体可能认为摆不进去,实际上我们最后是可以做平移的 - double dist_for_BOTTOM_LEFT(Box ibb, const ClipperLib::IntPoint& origin_pack) + double dist_for_BOTTOM_LEFT(Box ibb, const Slic3r::Point& origin_pack) { double dist_corner_y = ibb.minCorner().y() - origin_pack.y(); double dist_corner_x = ibb.minCorner().x() - origin_pack.x(); @@ -421,7 +445,7 @@ protected: return bindist; } - double dist_to_bin(const Box& ibb, const ClipperLib::IntPoint& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment) + double dist_to_bin(const Box& ibb, const Slic3r::Point& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment) { double bindist = 0; if (starting_point_alignment == PConfig::Alignment::BOTTOM_LEFT) @@ -439,7 +463,7 @@ protected: // as it possibly can be but at the same time, it has to provide // reasonable results. std::tuple - objfunc(const Item &item, const ClipperLib::IntPoint &origin_pack) + objfunc(const Item &item, const Slic3r::Point &origin_pack) { const double bin_area = m_bin_area; const SpatIndex& spatindex = m_rtree; @@ -1014,7 +1038,12 @@ void _arrange( inline Box to_nestbin(const BoundingBox &bb) { return Box{{bb.min(X), bb.min(Y)}, {bb.max(X), bb.max(Y)}};} inline Circle to_nestbin(const CircleBed &c) { return Circle({c.center()(0), c.center()(1)}, c.radius()); } inline ExPolygon to_nestbin(const Polygon &p) { return ExPolygon{p}; } -inline Box to_nestbin(const InfiniteBed &bed) { return Box::infinite({bed.center.x(), bed.center.y()}); } +// libnest2d's infinite box reaches the int64 limit, where Clipper2's double math is no longer exact. +inline Box to_nestbin(const InfiniteBed &bed) +{ + const coord_t r = coord_t(1) << 50; + return Box{{bed.center.x() - r, bed.center.y() - r}, {bed.center.x() + r, bed.center.y() + r}}; +} inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x(); } inline coord_t height(const BoundingBox& box) { return box.max.y() - box.min.y(); } @@ -1122,8 +1151,6 @@ void arrange(ArrangePolygons & arrangables, const BedT & bed, const ArrangeParams & params) { - namespace clppr = Slic3r::ClipperLib; - std::vector items, fixeditems; items.reserve(arrangables.size()); diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index ad125aee7d..ea89640a7b 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -2,8 +2,17 @@ #define ARRANGE_HPP #include "ExPolygon.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "PrintConfig.hpp" #include "Print.hpp" +#include +#include "libslic3r.h" +#include +#include +#include +#include +#include #define BED_SHRINK_SEQ_PRINT 5 diff --git a/src/libslic3r/BoundingBox.cpp b/src/libslic3r/BoundingBox.cpp index cf5441dace..dc4f461dc7 100644 --- a/src/libslic3r/BoundingBox.cpp +++ b/src/libslic3r/BoundingBox.cpp @@ -1,5 +1,8 @@ #include "BoundingBox.hpp" +#include "Point.hpp" #include "Polygon.hpp" +#include "libslic3r.h" +#include #include #include diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index 8aac3f1cb9..03f6a8f9bb 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -5,7 +5,10 @@ #include "Exception.hpp" #include "Point.hpp" #include "Polygon.hpp" +#include +#include #include +#include namespace Slic3r { diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp index 321e066a8a..ad1b8bb6fb 100644 --- a/src/libslic3r/BridgeDetector.cpp +++ b/src/libslic3r/BridgeDetector.cpp @@ -1,7 +1,18 @@ #include "BridgeDetector.hpp" +#include "BoundingBox.hpp" #include "ClipperUtils.hpp" +#include "ExPolygon.hpp" #include "Geometry.hpp" +#include "libslic3r.h" +#include "Polygon.hpp" +#include "Line.hpp" +#include "Polyline.hpp" +#include "Point.hpp" #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/BridgeDetector.hpp b/src/libslic3r/BridgeDetector.hpp index 1e5bb1a101..85982ed91c 100644 --- a/src/libslic3r/BridgeDetector.hpp +++ b/src/libslic3r/BridgeDetector.hpp @@ -9,7 +9,14 @@ #include "PrincipalComponents2D.hpp" #include "libslic3r.h" #include "ExPolygon.hpp" +#include +#include +#include #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 8ba4dfb596..f48723cfef 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -1,18 +1,37 @@ +#include "BoundingBox.hpp" +#include "BrimEarsPoint.hpp" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" +#include "ExPolygon.hpp" +#include "Flow.hpp" +#include "Geometry.hpp" +#include "ExtrusionEntity.hpp" #include "Layer.hpp" +#include "Point.hpp" +#include "ObjectID.hpp" +#include "Polygon.hpp" +#include "Line.hpp" +#include "MultiPoint.hpp" +#include "Polyline.hpp" #include "Print.hpp" +#include "PrintBase.hpp" #include "ShortestPath.hpp" #include "libslic3r.h" #include "PrintConfig.hpp" #include "MaterialType.hpp" #include "Model.hpp" #include +#include +#include #include #include +#include +#include #include #include +#include +#include #ifndef NDEBUG // #define BRIM_DEBUG_TO_SVG diff --git a/src/libslic3r/Brim.hpp b/src/libslic3r/Brim.hpp index 0603af20cc..9279b1e023 100644 --- a/src/libslic3r/Brim.hpp +++ b/src/libslic3r/Brim.hpp @@ -4,8 +4,10 @@ #include "ExPolygon.hpp" #include "ObjectID.hpp" #include "Point.hpp" +#include "Polygon.hpp" #include +#include #include namespace Slic3r { diff --git a/src/libslic3r/BrimEarsPoint.hpp b/src/libslic3r/BrimEarsPoint.hpp index a859d54f23..020b03475a 100644 --- a/src/libslic3r/BrimEarsPoint.hpp +++ b/src/libslic3r/BrimEarsPoint.hpp @@ -1,7 +1,10 @@ #ifndef BRIMEARSPOINT_HPP #define BRIMEARSPOINT_HPP +#include +#include "libslic3r.h" #include +#include namespace Slic3r { diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index 15e6668bae..eb5a447249 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -1,11 +1,24 @@ #include "BuildVolume.hpp" +#include "BoundingBox.hpp" #include "ClipperUtils.hpp" +#include "Polygon.hpp" +#include "Geometry/Circle.hpp" +#include "ExtrusionEntity.hpp" #include "TriangleMesh.hpp" #include "Geometry/ConvexHull.hpp" #include "GCode/GCodeProcessor.hpp" #include "Point.hpp" +#include "libslic3r.h" +#include #include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index 6f53fdd704..8c53242fe8 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -5,9 +5,13 @@ #include "Geometry/Circle.hpp" #include "Polygon.hpp" #include "BoundingBox.hpp" +#include "libslic3r.h" #include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/CadDocument.cpp b/src/libslic3r/CAD/CadDocument.cpp index ea20ffd966..b4a89f6a69 100644 --- a/src/libslic3r/CAD/CadDocument.cpp +++ b/src/libslic3r/CAD/CadDocument.cpp @@ -1,8 +1,14 @@ #include "libslic3r/CAD/CadDocument.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/CAD/SketchEngine.hpp" +#include "libslic3r/CAD/GeometryEngine.hpp" #include "libslic3r/CAD/SketchConstraints.hpp" #include "libslic3r/CAD/SketchSolver.hpp" #include "libslic3r/CAD/SketchImport.hpp" // transform_regions for imported art +#include +#include +#include #include #include @@ -26,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -69,12 +79,18 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/CadDocument.hpp b/src/libslic3r/CAD/CadDocument.hpp index f62536384a..216be818bd 100644 --- a/src/libslic3r/CAD/CadDocument.hpp +++ b/src/libslic3r/CAD/CadDocument.hpp @@ -1,16 +1,20 @@ #ifndef slic3r_CadDocument_hpp_ #define slic3r_CadDocument_hpp_ +#include "libslic3r/Point.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/CAD/SketchEngine.hpp" #include "libslic3r/CAD/GeometryEngine.hpp" // FaceGroup #include "libslic3r/Color.hpp" // ColorRGBA (per-body display colour override) +#include #include #include #include #include #include +#include +#include #include #include #include diff --git a/src/libslic3r/CAD/GeometryEngine.cpp b/src/libslic3r/CAD/GeometryEngine.cpp index 2b923938c2..1e5896e67a 100644 --- a/src/libslic3r/CAD/GeometryEngine.cpp +++ b/src/libslic3r/CAD/GeometryEngine.cpp @@ -1,12 +1,25 @@ #include "libslic3r/CAD/GeometryEngine.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include #include #include #include @@ -43,6 +56,9 @@ #include #include #include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/GeometryEngine.hpp b/src/libslic3r/CAD/GeometryEngine.hpp index f27a0f2f17..6c0fb51daf 100644 --- a/src/libslic3r/CAD/GeometryEngine.hpp +++ b/src/libslic3r/CAD/GeometryEngine.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_GeometryEngine_hpp_ #define slic3r_GeometryEngine_hpp_ +#include "libslic3r/Point.hpp" #include "libslic3r/TriangleMesh.hpp" #include @@ -8,6 +9,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libslic3r/CAD/SketchConstraints.cpp b/src/libslic3r/CAD/SketchConstraints.cpp index 003afb4d63..acc82a0e42 100644 --- a/src/libslic3r/CAD/SketchConstraints.cpp +++ b/src/libslic3r/CAD/SketchConstraints.cpp @@ -1,6 +1,11 @@ #include "libslic3r/CAD/SketchConstraints.hpp" +#include "libslic3r/Point.hpp" +#include #include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/SketchConstraints.hpp b/src/libslic3r/CAD/SketchConstraints.hpp index 88bcadc403..10c3efacc4 100644 --- a/src/libslic3r/CAD/SketchConstraints.hpp +++ b/src/libslic3r/CAD/SketchConstraints.hpp @@ -2,6 +2,7 @@ #define slic3r_SketchConstraints_hpp_ #include "libslic3r/Point.hpp" +#include #include #include diff --git a/src/libslic3r/CAD/SketchEngine.cpp b/src/libslic3r/CAD/SketchEngine.cpp index 5cc36ce648..ba92fa88bb 100644 --- a/src/libslic3r/CAD/SketchEngine.cpp +++ b/src/libslic3r/CAD/SketchEngine.cpp @@ -1,7 +1,18 @@ #include "libslic3r/CAD/SketchEngine.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include @@ -47,8 +58,11 @@ #include #include #include +#include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/SketchImport.cpp b/src/libslic3r/CAD/SketchImport.cpp index 7140776603..32bcc608d3 100644 --- a/src/libslic3r/CAD/SketchImport.cpp +++ b/src/libslic3r/CAD/SketchImport.cpp @@ -1,5 +1,8 @@ #include "libslic3r/CAD/SketchImport.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/EmbossShape.hpp" #include "libslic3r/Emboss.hpp" #include "libslic3r/NSVGUtils.hpp" #include "libslic3r/ExPolygon.hpp" @@ -9,6 +12,11 @@ #include #include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/SketchInference.cpp b/src/libslic3r/CAD/SketchInference.cpp index cfeb2cd509..eca56ee5c1 100644 --- a/src/libslic3r/CAD/SketchInference.cpp +++ b/src/libslic3r/CAD/SketchInference.cpp @@ -1,7 +1,13 @@ #include "libslic3r/CAD/SketchInference.hpp" +#include "libslic3r/CAD/SketchEngine.hpp" +#include "libslic3r/Point.hpp" #include #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/SketchInference.hpp b/src/libslic3r/CAD/SketchInference.hpp index be51f0240e..eb30af184a 100644 --- a/src/libslic3r/CAD/SketchInference.hpp +++ b/src/libslic3r/CAD/SketchInference.hpp @@ -1,7 +1,9 @@ #ifndef slic3r_SketchInference_hpp_ #define slic3r_SketchInference_hpp_ +#include "libslic3r/Point.hpp" #include "libslic3r/CAD/SketchEngine.hpp" +#include #include #include #include diff --git a/src/libslic3r/CAD/SketchSolver.cpp b/src/libslic3r/CAD/SketchSolver.cpp index 952f9de16f..03033d061e 100644 --- a/src/libslic3r/CAD/SketchSolver.cpp +++ b/src/libslic3r/CAD/SketchSolver.cpp @@ -1,5 +1,7 @@ #include "libslic3r/CAD/SketchSolver.hpp" +#include "libslic3r/CAD/SketchEngine.hpp" +#include #include #include @@ -7,6 +9,8 @@ #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CAD/ThreadStandards.cpp b/src/libslic3r/CAD/ThreadStandards.cpp index 2d113d01e6..11b6b24d8f 100644 --- a/src/libslic3r/CAD/ThreadStandards.cpp +++ b/src/libslic3r/CAD/ThreadStandards.cpp @@ -1,4 +1,6 @@ #include "libslic3r/CAD/ThreadStandards.hpp" +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index cb296e43c0..ef15304c8b 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -94,12 +94,9 @@ set(lisbslic3r_sources calib.hpp Circle.cpp Circle.hpp - clipper.cpp - clipper.hpp ClipperUtils.cpp ClipperUtils.hpp - Clipper2Utils.cpp - Clipper2Utils.hpp + ClipperZUtils.cpp ClipperZUtils.hpp Color.cpp Color.hpp @@ -716,7 +713,6 @@ target_link_libraries(libslic3r ${OCCT_LIBS} boost_libs cereal::cereal - clipper Clipper2 draco::draco glu-libtess diff --git a/src/libslic3r/CSGMesh/CSGMesh.hpp b/src/libslic3r/CSGMesh/CSGMesh.hpp index ea16eae52a..bb5060b0d3 100644 --- a/src/libslic3r/CSGMesh/CSGMesh.hpp +++ b/src/libslic3r/CSGMesh/CSGMesh.hpp @@ -2,7 +2,11 @@ #define CSGMESH_HPP #include +#include +#include #include +#include +#include namespace Slic3r { namespace csg { diff --git a/src/libslic3r/CSGMesh/CSGMeshCopy.hpp b/src/libslic3r/CSGMesh/CSGMeshCopy.hpp index 78800f9bbb..f00b24b535 100644 --- a/src/libslic3r/CSGMesh/CSGMeshCopy.hpp +++ b/src/libslic3r/CSGMesh/CSGMeshCopy.hpp @@ -1,7 +1,11 @@ #ifndef CSGMESHCOPY_HPP #define CSGMESHCOPY_HPP +#include "libslic3r/AnyPtr.hpp" #include "CSGMesh.hpp" +#include "libslic3r/libslic3r.h" +#include +#include namespace Slic3r { namespace csg { diff --git a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp index 5963b29109..2dcd2eef2e 100644 --- a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp @@ -3,9 +3,13 @@ #include "CSGMesh.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/SLA/Hollowing.hpp" #include "libslic3r/MeshSplitImpl.hpp" +#include +#include namespace Slic3r { namespace csg { diff --git a/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp b/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp index df4a603382..091621ab84 100644 --- a/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp +++ b/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp @@ -1,11 +1,17 @@ #ifndef PERFORMCSGMESHBOOLEANS_HPP #define PERFORMCSGMESHBOOLEANS_HPP +#include #include +#include +#include #include +#include + #include "CSGMesh.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Execution/ExecutionTBB.hpp" //#include "libslic3r/Execution/ExecutionSeq.hpp" #include "libslic3r/MeshBoolean.hpp" diff --git a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp index 9d7b9a077d..165e9af2b6 100644 --- a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp @@ -3,8 +3,16 @@ #include "CSGMesh.hpp" +#include +#include +#include #include +#include +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Execution/Execution.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" diff --git a/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp b/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp index 81b05b0463..d5586823fb 100644 --- a/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp +++ b/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp @@ -3,6 +3,7 @@ #include "CSGMesh.hpp" +#include "libslic3r/Point.hpp" #include "libslic3r/TriangleMesh.hpp" namespace Slic3r { namespace csg { diff --git a/src/libslic3r/Channel.hpp b/src/libslic3r/Channel.hpp index 68369af638..8ed9da9a88 100644 --- a/src/libslic3r/Channel.hpp +++ b/src/libslic3r/Channel.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_Channel_hpp_ #define slic3r_Channel_hpp_ +#include +#include +#include #include #include #include diff --git a/src/libslic3r/Circle.cpp b/src/libslic3r/Circle.cpp index c277a67795..8d09ba8f89 100644 --- a/src/libslic3r/Circle.cpp +++ b/src/libslic3r/Circle.cpp @@ -2,8 +2,14 @@ #include #include +#include +#include +#include #include "Geometry.hpp" +#include "Point.hpp" +#include "Line.hpp" #include "Polygon.hpp" +#include "libslic3r.h" //BBS: Refer to ArcWelderLib for the arc fitting functions diff --git a/src/libslic3r/Circle.hpp b/src/libslic3r/Circle.hpp index c06b197e19..388c7488ea 100644 --- a/src/libslic3r/Circle.hpp +++ b/src/libslic3r/Circle.hpp @@ -3,6 +3,8 @@ #include "Point.hpp" #include "Line.hpp" +#include "libslic3r.h" +#include namespace Slic3r { diff --git a/src/libslic3r/Clipper2Utils.cpp b/src/libslic3r/Clipper2Utils.cpp deleted file mode 100644 index f119fc3924..0000000000 --- a/src/libslic3r/Clipper2Utils.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include "Clipper2Utils.hpp" -#include "libslic3r.h" -#include "clipper2/clipper.h" - -namespace Slic3r { - -//BBS: FIXME -Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in) -{ - Slic3r::Polylines out; - out.reserve(in.size()); - for (const Clipper2Lib::Path64& path64 : in) { - Slic3r::Points points; - points.reserve(path64.size()); - for (const Clipper2Lib::Point64& point64 : path64) - points.emplace_back(Slic3r::Point(point64.x, point64.y)); - out.emplace_back(Slic3r::Polyline(points)); - } - return out; -} - -//BBS: FIXME -template -Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const Container& in) -{ - Clipper2Lib::Paths64 out; - out.reserve(in.size()); - for (const auto& item : in) { - Clipper2Lib::Path64 path; - path.reserve(item.size()); - for (const Slic3r::Point& point : item.points) - path.emplace_back(Clipper2Lib::Point64(point.x(), point.y())); - out.emplace_back(std::move(path)); - } - return out; -} - -Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Polylines& in) -{ - return Slic3rPoints_to_Paths64(in); -} - -Points Path64ToPoints(const Clipper2Lib::Path64& path64) -{ - Points points; - points.reserve(path64.size()); - for (const Clipper2Lib::Point64 &point64 : path64) points.emplace_back(Slic3r::Point(point64.x, point64.y)); - return points; -} - -static ExPolygons PolyTreeToExPolygons(Clipper2Lib::PolyTree64 &&polytree) -{ - struct Inner - { - static void PolyTreeToExPolygonsRecursive(Clipper2Lib::PolyTree64 &&polynode, ExPolygons *expolygons) - { - size_t cnt = expolygons->size(); - expolygons->resize(cnt + 1); - (*expolygons)[cnt].contour.points = Path64ToPoints(polynode.Polygon()); - - (*expolygons)[cnt].holes.resize(polynode.Count()); - for (int i = 0; i < polynode.Count(); ++i) { - (*expolygons)[cnt].holes[i].points = Path64ToPoints(polynode[i]->Polygon()); - // Add outer polygons contained by (nested within) holes. - for (int j = 0; j < polynode[i]->Count(); ++j) PolyTreeToExPolygonsRecursive(std::move(*polynode[i]->Child(j)), expolygons); - } - } - - static size_t PolyTreeCountExPolygons(const Clipper2Lib::PolyPath64& polynode) - { - size_t cnt = 1; - for (size_t i = 0; i < polynode.Count(); ++i) { - for (size_t j = 0; j < polynode.Child(i)->Count(); ++j) cnt += PolyTreeCountExPolygons(*polynode.Child(i)->Child(j)); - } - return cnt; - } - }; - - ExPolygons retval; - size_t cnt = 0; - for (int i = 0; i < polytree.Count(); ++i) cnt += Inner::PolyTreeCountExPolygons(*polytree[i]); - retval.reserve(cnt); - for (int i = 0; i < polytree.Count(); ++i) Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree[i]), &retval); - return retval; -} - -void SimplifyPolyTree(const Clipper2Lib::PolyPath64 &polytree, double epsilon, Clipper2Lib::PolyPath64 &result) -{ - for (const auto &child : polytree) { - Clipper2Lib::PolyPath64 *newchild = result.AddChild(Clipper2Lib::SimplifyPath(child->Polygon(), epsilon)); - SimplifyPolyTree(*child, epsilon, *newchild); - } -} - -Clipper2Lib::Paths64 Slic3rPolygons_to_Paths64(const Polygons &in) -{ - Clipper2Lib::Paths64 out; - out.reserve(in.size()); - for (const Polygon &poly : in) { - Clipper2Lib::Path64 path; - path.reserve(poly.points.size()); - for (const Slic3r::Point &point : poly.points) path.emplace_back(Clipper2Lib::Point64(point.x(), point.y())); - out.emplace_back(std::move(path)); - } - return out; -} - -Clipper2Lib::Paths64 Slic3rExPolygons_to_Paths64(const ExPolygons& in) -{ - Clipper2Lib::Paths64 out; - out.reserve(in.size()); - for (const ExPolygon& expolygon : in) { - for (size_t i = 0; i < expolygon.num_contours(); i++) { - const auto &poly = expolygon.contour_or_hole(i); - Clipper2Lib::Path64 path; - path.reserve(poly.points.size()); - for (const Slic3r::Point &point : poly.points) path.emplace_back(Clipper2Lib::Point64(point.x(), point.y())); - out.emplace_back(std::move(path)); - } - } - return out; -} - -Polylines _clipper2_pl_open(Clipper2Lib::ClipType clipType, const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) -{ - Clipper2Lib::Clipper64 c; - c.AddOpenSubject(Slic3rPoints_to_Paths64(subject)); - c.AddClip(Slic3rPoints_to_Paths64(clip)); - - Clipper2Lib::ClipType ct = clipType; - Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero; - Clipper2Lib::Paths64 solution, solution_open; - c.Execute(ct, fr, solution, solution_open); - - Slic3r::Polylines out; - out.reserve(solution.size() + solution_open.size()); - polylines_append(out, Paths64_to_polylines(solution)); - polylines_append(out, Paths64_to_polylines(solution_open)); - - return out; -} - -Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) - { return _clipper2_pl_open(Clipper2Lib::ClipType::Intersection, subject, clip); } -Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) - { return _clipper2_pl_open(Clipper2Lib::ClipType::Difference, subject, clip); } - -ExPolygons union_ex_2(const Polygons& polygons) -{ - Clipper2Lib::Clipper64 c; - c.AddSubject(Slic3rPolygons_to_Paths64(polygons)); - - Clipper2Lib::ClipType ct = Clipper2Lib::ClipType::Union; - Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero; - Clipper2Lib::PolyTree64 solution; - c.Execute(ct, fr, solution); - - ExPolygons results = PolyTreeToExPolygons(std::move(solution)); - - return results; -} - -ExPolygons union_ex_2(const ExPolygons &expolygons) -{ - Clipper2Lib::Clipper64 c; - c.AddSubject(Slic3rExPolygons_to_Paths64(expolygons)); - - Clipper2Lib::ClipType ct = Clipper2Lib::ClipType::Union; - Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero; - Clipper2Lib::PolyTree64 solution; - c.Execute(ct, fr, solution); - - ExPolygons results = PolyTreeToExPolygons(std::move(solution)); - - return results; -} - -// 对 ExPolygons 进行偏移 -ExPolygons offset_ex_2(const ExPolygons &expolygons, double delta) -{ - Clipper2Lib::Paths64 subject = Slic3rExPolygons_to_Paths64(expolygons); - Clipper2Lib::ClipperOffset offsetter; - offsetter.AddPaths(subject, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon); - Clipper2Lib::PolyPath64 polytree; - offsetter.Execute(delta, polytree); - ExPolygons results = PolyTreeToExPolygons(std::move(polytree)); - - return results; -} - -ExPolygons offset_ex_2(const ExPolygons &expolygons, double delta, Clipper2Lib::JoinType joinType) -{ - Clipper2Lib::Paths64 subject = Slic3rExPolygons_to_Paths64(expolygons); - Clipper2Lib::ClipperOffset offsetter; - offsetter.AddPaths(subject, joinType, Clipper2Lib::EndType::Polygon); - Clipper2Lib::PolyPath64 polytree; - offsetter.Execute(delta, polytree); - ExPolygons results = PolyTreeToExPolygons(std::move(polytree)); - - return results; -} - -ExPolygons offset2_ex_2(const ExPolygons& expolygons, double delta1, double delta2) -{ - // 1st offset - Clipper2Lib::Paths64 subject = Slic3rExPolygons_to_Paths64(expolygons); - Clipper2Lib::ClipperOffset offsetter; - offsetter.AddPaths(subject, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon); - Clipper2Lib::PolyPath64 polytree; - offsetter.Execute(delta1, polytree); - - // simplify the result - Clipper2Lib::PolyPath64 polytree2; - SimplifyPolyTree(polytree, SCALED_EPSILON, polytree2); - - // 2nd offset - offsetter.Clear(); - offsetter.AddPaths(Clipper2Lib::PolyTreeToPaths64(polytree2), Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon); - polytree.Clear(); - offsetter.Execute(delta2, polytree); - - // convert back to expolygons - ExPolygons results = PolyTreeToExPolygons(std::move(polytree)); - - return results; -} - -} \ No newline at end of file diff --git a/src/libslic3r/Clipper2Utils.hpp b/src/libslic3r/Clipper2Utils.hpp deleted file mode 100644 index 2b4b0fb2ef..0000000000 --- a/src/libslic3r/Clipper2Utils.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef slic3r_Clipper2Utils_hpp_ -#define slic3r_Clipper2Utils_hpp_ - -#include "ExPolygon.hpp" -#include "Polygon.hpp" -#include "Polyline.hpp" -#include "clipper2/clipper.h" - -namespace Slic3r { - -Clipper2Lib::Paths64 Slic3rPolylines_to_Paths64(const Slic3r::Polylines& in); -Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in); -Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip); -Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip); -ExPolygons union_ex_2(const Polygons &expolygons); -ExPolygons union_ex_2(const ExPolygons &expolygons); -ExPolygons offset_ex_2(const ExPolygons &expolygons, double delta); -ExPolygons offset_ex_2(const ExPolygons &expolygons, double delta, Clipper2Lib::JoinType joinType); -ExPolygons offset2_ex_2(const ExPolygons &expolygons, double delta1, double delta2); -} - -#endif \ No newline at end of file diff --git a/src/libslic3r/Clipper2ZUtils.hpp b/src/libslic3r/Clipper2ZUtils.hpp deleted file mode 100644 index b0891d1c63..0000000000 --- a/src/libslic3r/Clipper2ZUtils.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef slic3r_Clipper2ZUtils_hpp_ -#define slic3r_Clipper2ZUtils_hpp_ -#include -#include -#include - -#include -#include -namespace Slic3r { namespace Clipper2ZUtils { - -using ZPoint64 = Clipper2Lib_Z::Point64; -using ZPoints64 = Clipper2Lib_Z::Path64; -using ZPath64 = Clipper2Lib_Z::Path64; -using ZPaths64 = Clipper2Lib_Z::Paths64; - -inline bool zpoint64_lower(const ZPoint64 &l, const ZPoint64 &r) { - return l.x < r.x || (l.x == r.x && (l.y < r.y || (l.y == r.y && l.z < r.z))); -} - -// Convert a single path to zpath with a given Z coordinate. -// If Open, then duplicate the first point at the end. -template -inline ZPath64 to_zpath64(const Points &path, int64_t z) -{ - ZPath64 out; - if (!path.empty()) { - out.reserve(path.size() + (Open ? 1 : 0)); - for (const Point &p : path) out.emplace_back(p.x(), p.y(), z); - if (Open) out.emplace_back(out.front()); - } - return out; -} - -template -inline ZPath64 to_zpath64(const Clipper2Lib_Z::Path64 &path, int64_t z) -{ - ZPath64 out; - if (!path.empty()) { - out.reserve(path.size() + (Open ? 1 : 0)); - for (const Clipper2Lib_Z::Point64 &p : path) out.emplace_back(p.x, p.y, z); - if (Open) out.emplace_back(out.front()); - } - return out; -} - -// Convert multiple paths to zpaths with a given Z coordinate. -template -inline ZPaths64 to_zpaths64(const VecOfPoints &paths, int64_t z) -{ - ZPaths64 out; - out.reserve(paths.size()); - for (const Points &path : paths) out.emplace_back(to_zpath64(path, z)); - return out; -} - -template -inline ZPaths64 to_zpaths64(const Clipper2Lib_Z::Paths64 &paths, int64_t z) -{ - ZPaths64 out; - out.reserve(paths.size()); - for (const Clipper2Lib_Z::Path64 &path : paths) out.emplace_back(to_zpath64(path, z)); - return out; -} - -// Convert multiple expolygons into zpaths with Z specified by index -// offset by base_idx. -template -inline ZPaths64 expolygons_to_zpaths64(const ExPolygons &src, int64_t &base_idx) -{ - ZPaths64 out; - out.reserve(std::accumulate(src.begin(), src.end(), size_t(0), - [](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); })); - for (const ExPolygon &expoly : src) { - out.emplace_back(to_zpath64(expoly.contour.points, base_idx)); - for (const Polygon &hole : expoly.holes) - out.emplace_back(to_zpath64(hole.points, base_idx)); - ++base_idx; - } - return out; -} - -// Convert multiple expolygons into zpaths with the same Z. -template -inline ZPaths64 expolygons_to_zpaths64_with_same_z(const ExPolygons &src, int64_t z) -{ - ZPaths64 out; - out.reserve(std::accumulate(src.begin(), src.end(), size_t(0), - [](const size_t acc, const ExPolygon &expoly) { return acc + expoly.num_contours(); })); - for (const ExPolygon &expoly : src) { - out.emplace_back(to_zpath64(expoly.contour.points, z)); - for (const Polygon &hole : expoly.holes) - out.emplace_back(to_zpath64(hole.points, z)); - } - return out; -} - -// Convert a zpath back to 2D Points. -// If Open, then duplicate the first point at the end. -template -inline Points from_zpath64(const ZPath64 &path) -{ - Points out; - if (!path.empty()) { - out.reserve(path.size() + (Open ? 1 : 0)); - for (const ZPoint64 &p : path) out.emplace_back(p.x, p.y); - if (Open) out.emplace_back(out.front()); - } - return out; -} - -// Convert multiple zpaths back to 2D paths. -template -inline void from_zpaths64(const ZPaths64 &paths, VecOfPoints &out) -{ - out.reserve(out.size() + paths.size()); - for (const ZPath64 &path : paths) out.emplace_back(from_zpath64(path)); -} -template -inline VecOfPoints from_zpaths64(const ZPaths64 &paths) -{ - VecOfPoints out; - from_zpaths64(paths, out); - return out; -} - -// Intersection visitor for Clipper2 (zCallback_). -class Clipper2ZIntersectionVisitor -{ -public: - using Intersection = std::pair; - using Intersections = std::vector; - - Clipper2ZIntersectionVisitor(Intersections &intersections) : m_intersections(intersections) {} - - void reset() { m_intersections.clear(); } - - void operator()(const ZPoint64 &e1bot, const ZPoint64 &e1top, const ZPoint64 &e2bot, const ZPoint64 &e2top, ZPoint64 &pt) - { - std::array srcs{e1bot.z, e1top.z, e2bot.z, e2top.z}; - std::sort(srcs.begin(), srcs.end()); - auto it = std::unique(srcs.begin(), srcs.end()); - int new_size = std::distance(srcs.begin(), it); - assert(new_size == 1 || new_size == 2); - if (new_size == 1) { - pt.z = srcs[0]; - } - else if(new_size == 2){ - m_intersections.emplace_back(srcs[0], srcs[1]); - pt.z = -int64_t(m_intersections.size()); - } - } - - auto clipper_callback() - { - return [this](const ZPoint64 &e1bot, const ZPoint64 &e1top, - const ZPoint64 &e2bot, const ZPoint64 &e2top, ZPoint64 &pt) { - return (*this)(e1bot, e1top, e2bot, e2top, pt); }; - } - - const Intersections &intersections() const { return m_intersections; } - -private: - Intersections &m_intersections; -}; - -}} // namespace Slic3r::Clipper2ZUtils -#endif // slic3r_Clipper2ZUtils_hpp_ \ No newline at end of file diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index ea19eeb559..d80936515e 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -1,10 +1,29 @@ +#include +#include +#include +#include +#include +#include +#include #include #include #include #include "ClipperUtils.hpp" +#include "BoundingBox.hpp" +#include "ExPolygon.hpp" #include "Geometry.hpp" +#include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "Line.hpp" #include "ShortestPath.hpp" +#include "libslic3r.h" +#include "Surface.hpp" + +#include +#include +#include // #define CLIPPER_UTILS_DEBUG @@ -25,45 +44,12 @@ namespace Slic3r { -#ifdef CLIPPER_UTILS_DEBUG -// For debugging the Clipper library, for providing bug reports to the Clipper author. -bool export_clipper_input_polygons_bin(const char *path, const ClipperLib::Paths &input_subject, const ClipperLib::Paths &input_clip) -{ - FILE *pfile = fopen(path, "wb"); - if (pfile == NULL) - return false; - - uint32_t sz = uint32_t(input_subject.size()); - fwrite(&sz, 1, sizeof(sz), pfile); - for (size_t i = 0; i < input_subject.size(); ++i) { - const ClipperLib::Path &path = input_subject[i]; - sz = uint32_t(path.size()); - ::fwrite(&sz, 1, sizeof(sz), pfile); - ::fwrite(path.data(), sizeof(ClipperLib::IntPoint), sz, pfile); - } - sz = uint32_t(input_clip.size()); - ::fwrite(&sz, 1, sizeof(sz), pfile); - for (size_t i = 0; i < input_clip.size(); ++i) { - const ClipperLib::Path &path = input_clip[i]; - sz = uint32_t(path.size()); - ::fwrite(&sz, 1, sizeof(sz), pfile); - ::fwrite(path.data(), sizeof(ClipperLib::IntPoint), sz, pfile); - } - ::fclose(pfile); - return true; - -err: - ::fclose(pfile); - return false; -} -#endif /* CLIPPER_UTILS_DEBUG */ - namespace ClipperUtils { Points EmptyPathsProvider::s_empty_points; Points SinglePathProvider::s_end; // Clip source polygon to be used as a clipping polygon with a bouding box around the source (to be clipped) polygon. -// Useful as an optimization for expensive ClipperLib operations, for example when clipping source polygons one by one +// Useful as an optimization for expensive Clipper operations, for example when clipping source polygons one by one // with a set of polygons covering the whole layer below. template inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType &src, const BoundingBox &bbox, PointsType &out, const bool get_entire_polygons=false) { @@ -170,517 +156,501 @@ void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBo } } -static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) +namespace C2 = Clipper2Lib; + +namespace { + +C2::ClipType to_c2(ClipType type) { - struct Inner { - static void PolyTreeToExPolygonsRecursive(ClipperLib::PolyNode &&polynode, ExPolygons *expolygons) - { - size_t cnt = expolygons->size(); - expolygons->resize(cnt + 1); - (*expolygons)[cnt].contour.points = std::move(polynode.Contour); - (*expolygons)[cnt].holes.resize(polynode.ChildCount()); - for (int i = 0; i < polynode.ChildCount(); ++ i) { - (*expolygons)[cnt].holes[i].points = std::move(polynode.Childs[i]->Contour); - // Add outer polygons contained by (nested within) holes. - for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j) - PolyTreeToExPolygonsRecursive(std::move(*polynode.Childs[i]->Childs[j]), expolygons); - } - } - - static size_t PolyTreeCountExPolygons(const ClipperLib::PolyNode &polynode) - { - size_t cnt = 1; - for (int i = 0; i < polynode.ChildCount(); ++ i) { - for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++ j) - cnt += PolyTreeCountExPolygons(*polynode.Childs[i]->Childs[j]); - } - return cnt; - } - }; - - ExPolygons retval; - size_t cnt = 0; - for (int i = 0; i < polytree.ChildCount(); ++ i) - cnt += Inner::PolyTreeCountExPolygons(*polytree.Childs[i]); - retval.reserve(cnt); - for (int i = 0; i < polytree.ChildCount(); ++ i) - Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree.Childs[i]), &retval); - return retval; + switch (type) { + case ctIntersection: return C2::ClipType::Intersection; + case ctUnion: return C2::ClipType::Union; + case ctDifference: return C2::ClipType::Difference; + default: return C2::ClipType::Xor; + } } -Polylines PolyTreeToPolylines(ClipperLib::PolyTree &&polytree) +C2::FillRule to_c2(PolyFillType type) { - struct Inner { - static void AddPolyNodeToPaths(ClipperLib::PolyNode &polynode, Polylines &out) - { - if (! polynode.Contour.empty()) - out.emplace_back(std::move(polynode.Contour)); - for (ClipperLib::PolyNode *child : polynode.Childs) - AddPolyNodeToPaths(*child, out); - } - }; - - Polylines out; - out.reserve(polytree.Total()); - Inner::AddPolyNodeToPaths(polytree, out); - return out; + switch (type) { + case pftEvenOdd: return C2::FillRule::EvenOdd; + case pftNonZero: return C2::FillRule::NonZero; + case pftPositive: return C2::FillRule::Positive; + default: return C2::FillRule::Negative; + } } -#if 0 -// Global test. -bool has_duplicate_points(const ClipperLib::PolyTree &polytree) +C2::JoinType to_c2(JoinType type) { - struct Helper { - static void collect_points_recursive(const ClipperLib::PolyNode &polynode, ClipperLib::Path &out) { - // For each hole of the current expolygon: - out.insert(out.end(), polynode.Contour.begin(), polynode.Contour.end()); - for (int i = 0; i < polynode.ChildCount(); ++ i) - collect_points_recursive(*polynode.Childs[i], out); - } - }; - ClipperLib::Path pts; - for (int i = 0; i < polytree.ChildCount(); ++ i) - Helper::collect_points_recursive(*polytree.Childs[i], pts); - return has_duplicate_points(std::move(pts)); + switch (type) { + case jtSquare: return C2::JoinType::Square; + case jtRound: return C2::JoinType::Round; + default: return C2::JoinType::Miter; + } } -#else -// Local test inside each of the contours. -bool has_duplicate_points(const ClipperLib::PolyTree &polytree) -{ - struct Helper { - static bool has_duplicate_points_recursive(const ClipperLib::PolyNode &polynode) { - if (has_duplicate_points(polynode.Contour)) - return true; - for (int i = 0; i < polynode.ChildCount(); ++ i) - if (has_duplicate_points_recursive(*polynode.Childs[i])) - return true; - return false; - } - }; - ClipperLib::Path pts; - for (int i = 0; i < polytree.ChildCount(); ++ i) - if (Helper::has_duplicate_points_recursive(*polytree.Childs[i])) - return true; - return false; -} -#endif -// Offset CCW contours outside, CW contours (holes) inside. -// Don't calculate union of the output paths. +C2::EndType to_c2(EndType type) +{ + switch (type) { + case etClosedPolygon: return C2::EndType::Polygon; + case etClosedLine: return C2::EndType::Joined; + case etOpenSquare: return C2::EndType::Square; + case etOpenRound: return C2::EndType::Round; + default: return C2::EndType::Butt; + } +} + +inline int64_t px(const Point &pt) { return pt.x(); } +inline int64_t py(const Point &pt) { return pt.y(); } +inline int64_t px(const C2::Point64 &pt) { return pt.x; } +inline int64_t py(const C2::Point64 &pt) { return pt.y; } + template -static ClipperLib::Paths raw_offset(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType endType = ClipperLib::etClosedPolygon) +C2::Paths64 to_paths64(PathsProvider &&paths) { - ClipperLib::ClipperOffset co; - ClipperLib::Paths out; + C2::Paths64 out; out.reserve(paths.size()); - ClipperLib::Paths out_this; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = std::abs(offset * ClipperOffsetShortestEdgeFactor); - for (const ClipperLib::Path &path : paths) { - co.Clear(); - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.AddPath(path, joinType, endType); - bool ccw = endType == ClipperLib::etClosedPolygon ? ClipperLib::Orientation(path) : true; - co.Execute(out_this, ccw ? offset : - offset); - if (! ccw) { - // Reverse the resulting contours. - for (ClipperLib::Path &path : out_this) - std::reverse(path.begin(), path.end()); + for (const Points &path : paths) { + C2::Path64 &dst = out.emplace_back(); + dst.reserve(path.size()); + for (const Point &pt : path) + dst.emplace_back(pt.x(), pt.y()); + } + return out; +} + +// Drops vertices closer than `shortest` to the last kept one, like Clipper1's ShortestEdgeLength. +template +bool append_offset_path(C2::Paths64 &out, const PathT &path, double shortest, C2::EndType end) +{ + int high = int(path.size()) - 1; + if (high < 0) + return false; + const double shortest2 = shortest * shortest; + auto same = [shortest2](const auto &a, const auto &b) { + const double dx = double(px(a) - px(b)); + const double dy = double(py(a) - py(b)); + return shortest2 > 0. ? dx * dx + dy * dy < shortest2 : dx == 0. && dy == 0.; + }; + if (end == C2::EndType::Polygon || end == C2::EndType::Joined) + while (high > 0 && same(path[high], path[0])) + -- high; + C2::Path64 dst; + dst.reserve(high + 1); + dst.emplace_back(px(path[0]), py(path[0])); + for (int i = 1, last = 0; i <= high; ++ i) + if (! same(path[i], path[last])) { + dst.emplace_back(px(path[i]), py(path[i])); + last = i; } - append(out, std::move(out_this)); - } + if (end == C2::EndType::Polygon && dst.size() < 3) + return false; + out.emplace_back(std::move(dst)); + return true; +} + +inline Points c2_to_points(const C2::Path64 &path) +{ + Points out; + out.reserve(path.size()); + for (const C2::Point64 &pt : path) + out.emplace_back(pt.x, pt.y); return out; } -// Offset outside by 10um, one by one. -template -static ClipperLib::Paths safety_offset(PathsProvider &&paths) +Polygons c2_to_polygons(const C2::Paths64 &paths) { - return raw_offset(std::forward(paths), ClipperSafetyOffset, DefaultJoinType, DefaultMiterLimit); -} - -template -TResult clipper_do( - const ClipperLib::ClipType clipType, - TSubj && subject, - TClip && clip, - const ClipperLib::PolyFillType fillType) -{ - ClipperLib::Clipper clipper; - clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, true); - clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true); - TResult retval; - clipper.Execute(clipType, retval, fillType, fillType); - return retval; -} - -template -TResult clipper_do( - const ClipperLib::ClipType clipType, - TSubj && subject, - TClip && clip, - const ClipperLib::PolyFillType fillType, - const ApplySafetyOffset do_safety_offset) -{ - // Safety offset only allowed on intersection and difference. - assert(do_safety_offset == ApplySafetyOffset::No || clipType != ClipperLib::ctUnion); - return do_safety_offset == ApplySafetyOffset::Yes ? - clipper_do(clipType, std::forward(subject), safety_offset(std::forward(clip)), fillType) : - clipper_do(clipType, std::forward(subject), std::forward(clip), fillType); -} - -template -TResult clipper_union( - TSubj && subject, - // fillType pftNonZero and pftPositive "should" produce the same result for "normalized with implicit union" set of polygons - const ClipperLib::PolyFillType fillType = ClipperLib::pftNonZero) -{ - ClipperLib::Clipper clipper; - clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, true); - TResult retval; - clipper.Execute(ClipperLib::ctUnion, retval, fillType, fillType); - return retval; -} - -// Perform union of input polygons using the positive rule, convert to ExPolygons. -//FIXME is there any benefit of not doing the boolean / using pftEvenOdd? -inline ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union) -{ - return PolyTreeToExPolygons(clipper_union(input, do_union ? ClipperLib::pftNonZero : ClipperLib::pftEvenOdd)); -} - -template -static ClipperLib::Paths raw_offset_polyline(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type = ClipperLib::etOpenButt) -{ - assert(offset > 0); - return raw_offset(std::forward(paths), offset, joinType, miterLimit, end_type); -} - -template -static TResult expand_paths(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit) -{ - // BBS - //assert(offset > 0); - return clipper_union(raw_offset(std::forward(paths), offset, joinType, miterLimit)); -} - -// used by shrink_paths() -template static void remove_outermost_polygon(Container & solution); -template<> void remove_outermost_polygon(ClipperLib::Paths &solution) - { if (! solution.empty()) solution.erase(solution.begin()); } -template<> void remove_outermost_polygon(ClipperLib::PolyTree &solution) - { solution.RemoveOutermostPolygon(); } - -template -static TResult shrink_paths(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit) -{ - // BBS - //assert(offset > 0); - TResult out; - if (auto raw = raw_offset(std::forward(paths), - offset, joinType, miterLimit); ! raw.empty()) { - ClipperLib::Clipper clipper; - clipper.AddPaths(raw, ClipperLib::ptSubject, true); - ClipperLib::IntRect r = clipper.GetBounds(); - clipper.AddPath({ { r.left - 10, r.bottom + 10 }, { r.right + 10, r.bottom + 10 }, { r.right + 10, r.top - 10 }, { r.left - 10, r.top - 10 } }, ClipperLib::ptSubject, true); - clipper.ReverseSolution(true); - clipper.Execute(ClipperLib::ctUnion, out, ClipperLib::pftNegative, ClipperLib::pftNegative); - remove_outermost_polygon(out); - } + Polygons out; + out.reserve(paths.size()); + for (const C2::Path64 &path : paths) + out.emplace_back().points = c2_to_points(path); return out; } -template -static TResult offset_paths(PathsProvider &&paths, float offset, ClipperLib::JoinType joinType, double miterLimit) +Polylines c2_to_polylines(const C2::Paths64 &paths) { - // BBS - //assert(offset != 0); - - return offset > 0 ? - expand_paths(std::forward(paths), offset, joinType, miterLimit) : - shrink_paths(std::forward(paths), - offset, joinType, miterLimit); + Polylines out; + out.reserve(paths.size()); + for (const C2::Path64 &path : paths) + out.emplace_back(c2_to_points(path)); + return out; } -Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(raw_offset(ClipperUtils::SinglePathProvider(polygon.points), delta, joinType, miterLimit)); } +size_t c2_count_expolygons(const C2::PolyPath64 &outer) +{ + size_t cnt = 1; + for (const auto &hole : outer) + for (const auto &island : *hole) + cnt += c2_count_expolygons(*island); + return cnt; +} -Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(offset_paths(ClipperUtils::PolygonsProvider(polygons), delta, joinType, miterLimit)); } -Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return PolyTreeToExPolygons(offset_paths(ClipperUtils::PolygonsProvider(polygons), delta, joinType, miterLimit)); } +void c2_append_expolygons(const C2::PolyPath64 &outer, ExPolygons &out) +{ + ExPolygon &expoly = out.emplace_back(); + expoly.contour.points = c2_to_points(outer.Polygon()); + expoly.holes.reserve(outer.Count()); + for (const auto &hole : outer) + expoly.holes.emplace_back().points = c2_to_points(hole->Polygon()); + // Islands inside the holes. + for (const auto &hole : outer) + for (const auto &island : *hole) + c2_append_expolygons(*island, out); +} -Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type) - { assert(delta > 0); return to_polygons(clipper_union(raw_offset_polyline(ClipperUtils::SinglePathProvider(polyline.points), delta, joinType, miterLimit, end_type))); } +ExPolygons c2_to_expolygons(const C2::PolyTree64 &tree) +{ + size_t cnt = 0; + for (const auto &outer : tree) + cnt += c2_count_expolygons(*outer); + ExPolygons out; + out.reserve(cnt); + for (const auto &outer : tree) + c2_append_expolygons(*outer, out); + return out; +} -Slic3r::Polygons offset(const Slic3r::Polyline3 &polyline, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type) +template +void c2_clip(C2::ClipType type, const C2::Paths64 &subject, const C2::Paths64 &clip, C2::FillRule fill, TOut &out) +{ + C2::Clipper64 clipper; + // Clipper2 keeps collinear vertices by default, Clipper1 removed them. + clipper.PreserveCollinear(false); + clipper.AddSubject(subject); + if (! clip.empty()) + clipper.AddClip(clip); + clipper.Execute(type, fill, out); +} + +Polylines c2_clip_open(C2::ClipType type, const C2::Paths64 &subject, const C2::Paths64 &clip) +{ + C2::Clipper64 clipper; + clipper.PreserveCollinear(false); + clipper.AddOpenSubject(subject); + if (! clip.empty()) + clipper.AddClip(clip); + C2::Paths64 closed, open; + clipper.Execute(type, C2::FillRule::NonZero, closed, open); + return c2_to_polylines(open); +} + +// Clipper1 semantics: miter limit at least 2, arc tolerance (also for round caps) at most a quarter of the offset. +void c2_offset_setup(C2::ClipperOffset &co, float delta, JoinType joinType, double miterLimit) +{ + const double max_arc_tolerance = std::abs(delta) * 0.25; + if (joinType == jtRound) + co.ArcTolerance(miterLimit > 0. ? std::min(miterLimit, max_arc_tolerance) : 0.25); + else { + co.MiterLimit(std::max(miterLimit, 2.)); + co.ArcTolerance(std::min(0.25, max_arc_tolerance)); + } +} + +// A single group offsets like Clipper1's path by path offset only if every CW path is a hole of a CCW path. +bool c2_offset_as_group(const C2::Paths64 &paths, const std::vector &areas) +{ + std::vector contours; + for (size_t i = 0; i < paths.size(); ++ i) + if (areas[i] > 0.) + contours.emplace_back(C2::GetBounds(paths[i])); + for (size_t i = 0; i < paths.size(); ++ i) + if (areas[i] < 0.) { + const C2::Rect64 hole = C2::GetBounds(paths[i]); + if (std::none_of(contours.begin(), contours.end(), [&hole](const C2::Rect64 &r) { + return r.left < hole.left && r.right > hole.right && r.top < hole.top && r.bottom > hole.bottom; + })) + return false; + } + return true; +} + +template +void c2_offset_closed_paths(C2::Paths64 &&paths, float delta, JoinType joinType, double miterLimit, TOut &out) +{ + std::vector areas; + areas.reserve(paths.size()); + for (const C2::Path64 &path : paths) + areas.emplace_back(C2::Area(path)); + C2::ClipperOffset co; + c2_offset_setup(co, delta, joinType, miterLimit); + if (c2_offset_as_group(paths, areas)) { + // Clipper2 would grow degenerate paths even for a negative offset. + if (delta < 0. && std::all_of(areas.begin(), areas.end(), [](double a) { return a == 0.; })) + return; + co.AddPaths(paths, to_c2(joinType), C2::EndType::Polygon); + co.Execute(delta, out); + return; + } + C2::Paths64 offsetted, single; + for (size_t i = 0; i < paths.size(); ++ i) { + if (areas[i] == 0. && delta < 0.) + continue; + co.Clear(); + co.AddPath(paths[i], to_c2(joinType), C2::EndType::Polygon); + // Clipper2 reverses a lone CW path, so the flipped sign shrinks it as a hole. + co.Execute(areas[i] < 0. ? - delta : delta, single); + append(offsetted, std::move(single)); + } + c2_clip(C2::ClipType::Union, offsetted, {}, delta > 0. ? C2::FillRule::NonZero : C2::FillRule::Positive, out); +} + +template +void c2_offset_closed(PathsT &&src, float delta, JoinType joinType, double miterLimit, TOut &out) +{ + const double shortest = std::abs(delta * ClipperOffsetShortestEdgeFactor); + C2::Paths64 paths; + paths.reserve(src.size()); + for (const auto &path : src) + append_offset_path(paths, path, shortest, C2::EndType::Polygon); + c2_offset_closed_paths(std::move(paths), delta, joinType, miterLimit, out); +} + +template +void c2_offset2_closed(PathsProvider &&src, float delta1, float delta2, JoinType joinType, double miterLimit, TOut &out) +{ + C2::Paths64 first; + c2_offset_closed(std::forward(src), delta1, joinType, miterLimit, first); + c2_offset_closed(first, delta2, joinType, miterLimit, out); +} + +inline const ExPolygon& expolygon_of(const ExPolygon &expoly) { return expoly; } +inline const ExPolygon& expolygon_of(const ExPolygon *expoly) { return *expoly; } +inline const ExPolygon& expolygon_of(const Surface &surface) { return surface.expolygon; } +inline const ExPolygon& expolygon_of(const Surface *surface) { return surface->expolygon; } + +// Clipper1 ignored the orientation of expolygons, a single group needs CCW contours and CW holes. +template +void c2_offset_expolygons(const ExPolygonRange &src, float delta, JoinType joinType, double miterLimit, TOut &out) +{ + const double shortest = std::abs(delta * ClipperOffsetShortestEdgeFactor); + C2::Paths64 paths; + for (const auto &item : src) { + const ExPolygon &expoly = expolygon_of(item); + if (! append_offset_path(paths, expoly.contour.points, shortest, C2::EndType::Polygon)) + continue; + if (const double area = C2::Area(paths.back()); area == 0.) { + // A degenerate contour vanishes when shrunk and encloses no hole when grown. + if (delta < 0.) + paths.pop_back(); + continue; + } else if (area < 0.) + std::reverse(paths.back().begin(), paths.back().end()); + for (const Polygon &hole : expoly.holes) + if (append_offset_path(paths, hole.points, shortest, C2::EndType::Polygon)) { + if (const double area = C2::Area(paths.back()); area == 0.) + paths.pop_back(); + else if (area > 0.) + std::reverse(paths.back().begin(), paths.back().end()); + } + } + C2::ClipperOffset co; + c2_offset_setup(co, delta, joinType, miterLimit); + co.AddPaths(paths, to_c2(joinType), C2::EndType::Polygon); + co.Execute(delta, out); +} + +template +Polygons c2_expolygons_offset(const ExPolygonRange &src, float delta, JoinType joinType, double miterLimit) +{ + C2::Paths64 out; + c2_offset_expolygons(src, delta, joinType, miterLimit, out); + return c2_to_polygons(out); +} + +template +ExPolygons c2_expolygons_offset_ex(const ExPolygonRange &src, float delta, JoinType joinType, double miterLimit) +{ + C2::PolyTree64 out; + c2_offset_expolygons(src, delta, joinType, miterLimit, out); + return c2_to_expolygons(out); +} + +template +Polygons c2_offset_lines(PathsProvider &&src, float delta, JoinType joinType, double miterLimit, EndType endType) +{ + C2::Paths64 out; + if (endType == etClosedPolygon) { + c2_offset_closed(std::forward(src), delta, joinType, miterLimit, out); + return c2_to_polygons(out); + } + const C2::EndType end = to_c2(endType); + const double shortest = std::abs(delta * ClipperOffsetShortestEdgeFactor); + C2::Paths64 paths; + paths.reserve(src.size()); + for (const Points &path : src) + append_offset_path(paths, path, shortest, end); + C2::ClipperOffset co; + c2_offset_setup(co, delta, joinType, miterLimit); + co.AddPaths(paths, to_c2(joinType), end); + co.Execute(delta, out); + return c2_to_polygons(out); +} + +template +C2::Paths64 c2_clip_paths(PathsProvider &&clip, ApplySafetyOffset do_safety_offset) +{ + if (do_safety_offset == ApplySafetyOffset::No) + return to_paths64(std::forward(clip)); + C2::Paths64 out; + c2_offset_closed(std::forward(clip), ClipperSafetyOffset, DefaultJoinType, DefaultMiterLimit, out); + return out; +} + +} // namespace + +Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit) +{ + C2::Paths64 paths; + if (! append_offset_path(paths, polygon.points, std::abs(delta * ClipperOffsetShortestEdgeFactor), C2::EndType::Polygon)) + return {}; + const double area = C2::Area(paths.front()); + if (area == 0. && delta < 0.) + return {}; + C2::ClipperOffset co; + c2_offset_setup(co, delta, joinType, miterLimit); + co.AddPaths(paths, to_c2(joinType), C2::EndType::Polygon); + C2::Paths64 out; + // A CW polygon shrinks as a hole and stays CW. + co.Execute(area < 0. ? - delta : delta, out); + return c2_to_polygons(out); +} + +Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit) +{ + C2::Paths64 out; + c2_offset_closed(ClipperUtils::PolygonsProvider(polygons), delta, joinType, miterLimit, out); + return c2_to_polygons(out); +} +Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit) +{ + C2::PolyTree64 out; + c2_offset_closed(ClipperUtils::PolygonsProvider(polygons), delta, joinType, miterLimit, out); + return c2_to_expolygons(out); +} + +Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, JoinType joinType, double miterLimit, EndType end_type) + { assert(delta > 0); return c2_offset_lines(ClipperUtils::SinglePathProvider(polyline.points), delta, joinType, miterLimit, end_type); } + +Slic3r::Polygons offset(const Slic3r::Polyline3 &polyline, const float delta, JoinType joinType, double miterLimit, EndType end_type) { assert(delta > 0); - return to_polygons( - clipper_union( - raw_offset_polyline( - ClipperUtils::SinglePathProvider(polyline.to_polyline().points), - delta, - joinType, - miterLimit, - end_type))); + return c2_offset_lines(ClipperUtils::SinglePathProvider(polyline.to_polyline().points), delta, joinType, miterLimit, end_type); } -Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::EndType end_type) - { assert(delta > 0); return to_polygons(clipper_union(raw_offset_polyline(ClipperUtils::PolylinesProvider(polylines), delta, joinType, miterLimit, end_type))); } +Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, JoinType joinType, double miterLimit, EndType end_type) + { assert(delta > 0); return c2_offset_lines(ClipperUtils::PolylinesProvider(polylines), delta, joinType, miterLimit, end_type); } -Polygons contour_to_polygons(const Polygon &polygon, const float line_width, ClipperLib::JoinType join_type, double miter_limit){ - assert(line_width > 1.f); return to_polygons(clipper_union( - raw_offset(ClipperUtils::SinglePathProvider(polygon.points), line_width/2, join_type, miter_limit, ClipperLib::etClosedLine)));} -Polygons contour_to_polygons(const Polygons &polygons, const float line_width, ClipperLib::JoinType join_type, double miter_limit){ - assert(line_width > 1.f); return to_polygons(clipper_union( - raw_offset(ClipperUtils::PolygonsProvider(polygons), line_width/2, join_type, miter_limit, ClipperLib::etClosedLine)));} +Polygons contour_to_polygons(const Polygon &polygon, const float line_width, JoinType join_type, double miter_limit) + { assert(line_width > 1.f); return c2_offset_lines(ClipperUtils::SinglePathProvider(polygon.points), line_width / 2, join_type, miter_limit, etClosedLine); } +Polygons contour_to_polygons(const Polygons &polygons, const float line_width, JoinType join_type, double miter_limit) + { assert(line_width > 1.f); return c2_offset_lines(ClipperUtils::PolygonsProvider(polygons), line_width / 2, join_type, miter_limit, etClosedLine); } -// returns number of expolygons collected (0 or 1). -static int offset_expolygon_inner(const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) +Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset(std::array{ &expolygon }, delta, joinType, miterLimit); } +Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset(expolygons, delta, joinType, miterLimit); } +Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset(surfaces, delta, joinType, miterLimit); } +Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset(surfaces, delta, joinType, miterLimit); } +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset_ex(std::array{ &expolygon }, delta, joinType, miterLimit); } +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset_ex(expolygons, delta, joinType, miterLimit); } +Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset_ex(surfaces, delta, joinType, miterLimit); } +Slic3r::ExPolygons offset_ex(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType, double miterLimit) + { return c2_expolygons_offset_ex(surfaces, delta, joinType, miterLimit); } + +Polygons offset2(const ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { - // 1) Offset the outer contour. - ClipperLib::Paths contours; - { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = std::abs(delta * ClipperOffsetShortestEdgeFactor); - co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon); - co.Execute(contours, delta); - } - if (contours.empty()) - // No need to try to offset the holes. - return 0; - - if (expoly.holes.empty()) { - // No need to subtract holes from the offsetted expolygon, we are done. - append(out, std::move(contours)); - } else { - // 2) Offset the holes one by one, collect the offsetted holes. - ClipperLib::Paths holes; - { - for (const Polygon &hole : expoly.holes) { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = std::abs(delta * ClipperOffsetShortestEdgeFactor); - co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon); - ClipperLib::Paths out2; - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.Execute(out2, - delta); - append(holes, std::move(out2)); - } - } - - // 3) Subtract holes from the contours. - if (holes.empty()) { - // No hole remaining after an offset. Just copy the outer contour. - append(out, std::move(contours)); - } else if (delta < 0) { - // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. - // Subtract the offsetted holes from the offsetted contours. - if (auto output = clipper_do(ClipperLib::ctDifference, contours, holes, ClipperLib::pftNonZero); ! output.empty()) { - append(out, std::move(output)); - } else { - // The offsetted holes have eaten up the offsetted outer contour. - return 0; - } - } else { - // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller - // area than the original hole or even disappear, therefore there will be no new intersections. - // Just collect the reversed holes. - out.reserve(contours.size() + holes.size()); - append(out, std::move(contours)); - // Reverse the holes in place. - for (size_t i = 0; i < holes.size(); ++ i) - std::reverse(holes[i].begin(), holes[i].end()); - append(out, std::move(holes)); - } - } - - return 1; + C2::Paths64 first, out; + c2_offset_expolygons(expolygons, delta1, joinType, miterLimit, first); + c2_offset_closed(first, delta2, joinType, miterLimit, out); + return c2_to_polygons(out); } - -static int offset_expolygon_inner(const Slic3r::Surface &surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) - { return offset_expolygon_inner(surface.expolygon, delta, joinType, miterLimit, out); } -static int offset_expolygon_inner(const Slic3r::Surface *surface, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib::Paths &out) - { return offset_expolygon_inner(surface->expolygon, delta, joinType, miterLimit, out); } - -ClipperLib::Paths expolygon_offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) +ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { - ClipperLib::Paths out; - offset_expolygon_inner(expolygon, delta, joinType, miterLimit, out); - return out; + C2::Paths64 first; + C2::PolyTree64 out; + c2_offset_expolygons(expolygons, delta1, joinType, miterLimit, first); + c2_offset_closed(first, delta2, joinType, miterLimit, out); + return c2_to_expolygons(out); } - -// This is a safe variant of the polygons offset, tailored for multiple ExPolygons. -// It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours. -// Each ExPolygon is offsetted separately. For outer offset, the offsetted ExPolygons shall be united outside of this function. -template -static std::pair expolygons_offset_raw(const ExPolygonVector &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) +ExPolygons offset2_ex(const Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType, double miterLimit) { - // Offsetted ExPolygons before they are united. - ClipperLib::Paths output; - output.reserve(expolygons.size()); - // How many non-empty offsetted expolygons were actually collected into output? - // If only one, then there is no need to do a final union. - size_t expolygons_collected = 0; - for (const auto &expoly : expolygons) - expolygons_collected += offset_expolygon_inner(expoly, delta, joinType, miterLimit, output); - return std::make_pair(std::move(output), expolygons_collected); -} - -// See comment on expolygon_offsets_raw. In addition, for positive offset the contours are united. -template -static ClipperLib::Paths expolygons_offset(const ExPolygonVector &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) -{ - auto [output, expolygons_collected] = expolygons_offset_raw(expolygons, delta, joinType, miterLimit); - // Unite the offsetted expolygons. - return expolygons_collected > 1 && delta > 0 ? - // There is a chance that the outwards offsetted expolygons may intersect. Perform a union. - clipper_union(output) : - // Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output. - output; -} - -// See comment on expolygons_offset_raw. In addition, the polygons are always united to conver to polytree. -template -static ClipperLib::PolyTree expolygons_offset_pt(const ExPolygonVector &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) -{ - auto [output, expolygons_collected] = expolygons_offset_raw(expolygons, delta, joinType, miterLimit); - // Unite the offsetted expolygons for both the - return clipper_union(output); -} - -Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(expolygon_offset(expolygon, delta, joinType, miterLimit)); } -Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(expolygons_offset(expolygons, delta, joinType, miterLimit)); } -Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(expolygons_offset(surfaces, delta, joinType, miterLimit)); } -Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return to_polygons(expolygons_offset(surfaces, delta, joinType, miterLimit)); } -Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) - //FIXME one may spare one Clipper Union call. - { return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit)); } -Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return PolyTreeToExPolygons(expolygons_offset_pt(expolygons, delta, joinType, miterLimit)); } -Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return PolyTreeToExPolygons(expolygons_offset_pt(surfaces, delta, joinType, miterLimit)); } -Slic3r::ExPolygons offset_ex(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit) - { return PolyTreeToExPolygons(expolygons_offset_pt(surfaces, delta, joinType, miterLimit)); } - -Polygons offset2(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) -{ - return to_polygons(offset_paths(expolygons_offset(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit)); -} -ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) -{ - return PolyTreeToExPolygons(offset_paths(expolygons_offset(expolygons, delta1, joinType, miterLimit), delta2, joinType, miterLimit)); -} -ExPolygons offset2_ex(const Surfaces &surfaces, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) -{ - //FIXME it may be more efficient to offset to_expolygons(surfaces) instead of to_polygons(surfaces). - return PolyTreeToExPolygons(offset_paths(expolygons_offset(surfaces, delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::Paths64 first; + C2::PolyTree64 out; + c2_offset_expolygons(surfaces, delta1, joinType, miterLimit, first); + c2_offset_closed(first, delta2, joinType, miterLimit, out); + return c2_to_expolygons(out); } // Offset outside, then inside produces morphological closing. All deltas should be positive. -Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - return to_polygons(shrink_paths(expand_paths(ClipperUtils::PolygonsProvider(polygons), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::Paths64 out; + c2_offset2_closed(ClipperUtils::PolygonsProvider(polygons), delta1, - delta2, joinType, miterLimit, out); + return c2_to_polygons(out); } -Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - return PolyTreeToExPolygons(shrink_paths(expand_paths(ClipperUtils::PolygonsProvider(polygons), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::PolyTree64 out; + c2_offset2_closed(ClipperUtils::PolygonsProvider(polygons), delta1, - delta2, joinType, miterLimit, out); + return c2_to_expolygons(out); } -Slic3r::ExPolygons closing_ex(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::ExPolygons closing_ex(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - //FIXME it may be more efficient to offset to_expolygons(surfaces) instead of to_polygons(surfaces). - return PolyTreeToExPolygons(shrink_paths(expand_paths(ClipperUtils::SurfacesProvider(surfaces), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::PolyTree64 out; + c2_offset2_closed(ClipperUtils::SurfacesProvider(surfaces), delta1, - delta2, joinType, miterLimit, out); + return c2_to_expolygons(out); } // Offset inside, then outside produces morphological opening. All deltas should be positive. -Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - return to_polygons(expand_paths(shrink_paths(ClipperUtils::PolygonsProvider(polygons), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::Paths64 out; + c2_offset2_closed(ClipperUtils::PolygonsProvider(polygons), - delta1, delta2, joinType, miterLimit, out); + return c2_to_polygons(out); } -Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - return to_polygons(expand_paths(shrink_paths(ClipperUtils::ExPolygonsProvider(expolygons), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); + C2::Paths64 out; + c2_offset2_closed(ClipperUtils::ExPolygonsProvider(expolygons), - delta1, delta2, joinType, miterLimit, out); + return c2_to_polygons(out); } -Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit) +Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType, double miterLimit) { assert(delta1 > 0); assert(delta2 > 0); - //FIXME it may be more efficient to offset to_expolygons(surfaces) instead of to_polygons(surfaces). - return to_polygons(expand_paths(shrink_paths(ClipperUtils::SurfacesProvider(surfaces), delta1, joinType, miterLimit), delta2, joinType, miterLimit)); -} - -// Fix of #117: A large fractal pyramid takes ages to slice -// The Clipper library has difficulties processing overlapping polygons. -// Namely, the function ClipperLib::JoinCommonEdges() has potentially a terrible time complexity if the output -// of the operation is of the PolyTree type. -// This function implemenets a following workaround: -// 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time. -// 2) Run Clipper Union once again to extract the PolyTree from the result of 1). -template -inline ClipperLib::PolyTree clipper_do_polytree( - const ClipperLib::ClipType clipType, - PathProvider1 &&subject, - PathProvider2 &&clip, - const ClipperLib::PolyFillType fillType) -{ - // Perform the operation with the output to input_subject. - // This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library - // if there are overapping edges. - if (auto output = clipper_do(clipType, subject, clip, fillType); ! output.empty()) - // Perform an additional Union operation to generate the PolyTree ordering. - return clipper_union(output, fillType); - return ClipperLib::PolyTree(); -} -template -inline ClipperLib::PolyTree clipper_do_polytree( - const ClipperLib::ClipType clipType, - PathProvider1 &&subject, - PathProvider2 &&clip, - const ClipperLib::PolyFillType fillType, - const ApplySafetyOffset do_safety_offset) -{ - assert(do_safety_offset == ApplySafetyOffset::No || clipType != ClipperLib::ctUnion); - return do_safety_offset == ApplySafetyOffset::Yes ? - clipper_do_polytree(clipType, std::forward(subject), safety_offset(std::forward(clip)), fillType) : - clipper_do_polytree(clipType, std::forward(subject), std::forward(clip), fillType); + C2::Paths64 out; + c2_offset2_closed(ClipperUtils::SurfacesProvider(surfaces), - delta1, delta2, joinType, miterLimit, out); + return c2_to_polygons(out); } template -static inline Polygons _clipper(ClipperLib::ClipType clipType, TSubj &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset) +static inline Polygons _clipper(ClipType clipType, TSubj &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset) { - return to_polygons(clipper_do(clipType, std::forward(subject), std::forward(clip), ClipperLib::pftNonZero, do_safety_offset)); + // Safety offset only allowed on intersection and difference. + assert(do_safety_offset == ApplySafetyOffset::No || clipType != ctUnion); + C2::Paths64 out; + c2_clip(to_c2(clipType), to_paths64(std::forward(subject)), c2_clip_paths(std::forward(clip), do_safety_offset), C2::FillRule::NonZero, out); + return c2_to_polygons(out); } Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) { return diff(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); } Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) @@ -690,31 +660,37 @@ Slic3r::ExPolygons diff_clipped(const Slic3r::ExPolygons & subject, const Slic3r return diff_ex(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons diff(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } Slic3r::Polygons intersection_clipped(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) { return intersection(subject, ClipperUtils::clip_clipper_polygons_with_subject_bbox(clip, get_extents(subject).inflated(SCALED_EPSILON)), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } +Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, PolyFillType fill_type) +{ + C2::Paths64 out; + c2_clip(C2::ClipType::Intersection, to_paths64(ClipperUtils::PolygonsProvider(subject)), to_paths64(ClipperUtils::PolygonsProvider(clip)), to_c2(fill_type), out); + return c2_to_polygons(out); +} Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::Polygons intersection(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper(ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } // BBS Slic3r::Polygons intersection(const Slic3r::Polygons& subject, const Slic3r::Polygon& clip, ApplySafetyOffset do_safety_offset) { @@ -724,11 +700,16 @@ Slic3r::Polygons intersection(const Slic3r::Polygons& subject, const Slic3r::Pol } Slic3r::Polygons union_(const Slic3r::Polygons &subject) - { return _clipper(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } + { return _clipper(ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } Slic3r::Polygons union_(const Slic3r::ExPolygons &subject) - { return _clipper(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } -Slic3r::Polygons union_(const Slic3r::Polygons &subject, const ClipperLib::PolyFillType fillType) - { return to_polygons(clipper_do(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), fillType, ApplySafetyOffset::No)); } + { return _clipper(ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const PolyFillType fillType) +{ + C2::Paths64 out; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::PolygonsProvider(subject)), {}, to_c2(fillType), out); + return c2_to_polygons(out); +} + Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2) { // BBS @@ -738,38 +719,44 @@ Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons return union_(polys); } +// Clipper2 builds the PolyTree in one pass without Clipper1's slowdown on shared edges (#117). template -static ExPolygons _clipper_ex(ClipperLib::ClipType clipType, TSubject &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) - { return PolyTreeToExPolygons(clipper_do_polytree(clipType, std::forward(subject), std::forward(clip), fill_type, do_safety_offset)); } +static ExPolygons _clipper_ex(ClipType clipType, TSubject &&subject, TClip &&clip, ApplySafetyOffset do_safety_offset, PolyFillType fill_type = pftNonZero) +{ + assert(do_safety_offset == ApplySafetyOffset::No || clipType != ctUnion); + C2::PolyTree64 out; + c2_clip(to_c2(clipType), to_paths64(std::forward(subject)), c2_clip_paths(std::forward(clip), do_safety_offset), to_c2(fill_type), out); + return c2_to_expolygons(out); +} Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctDifference, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } // BBS inline Slic3r::ExPolygons diff_ex(const Slic3r::Polygon& subject, const Slic3r::Polygons& clip, ApplySafetyOffset do_safety_offset) { @@ -790,38 +777,39 @@ inline Slic3r::ExPolygons diff_ex(const Slic3r::Polygon& subject, const Slic3r:: } Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons& subject, const Slic3r::ExPolygon& clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset);} + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset);} Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygon& subject, const Slic3r::ExPolygons& clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset);} + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset);} Slic3r::ExPolygons intersection_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::SurfacesProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); } Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) - { return _clipper_ex(ClipperLib::ctIntersection, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } + { return _clipper_ex(ctIntersection, ClipperUtils::SurfacesPtrProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } // May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative). -Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type) - { return _clipper_ex(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No, fill_type); } +Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type) + { return _clipper_ex(ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No, fill_type); } Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject) - { return PolyTreeToExPolygons(clipper_do_polytree(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); } + { return _clipper_ex(ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &subject2) - { return PolyTreeToExPolygons(clipper_do_polytree(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ClipperLib::pftNonZero)); } + { return _clipper_ex(ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(subject2), ApplySafetyOffset::No); } Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject) - { return PolyTreeToExPolygons(clipper_do_polytree(ClipperLib::ctUnion, ClipperUtils::SurfacesProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftNonZero)); } + { return _clipper_ex(ctUnion, ClipperUtils::SurfacesProvider(subject), ClipperUtils::EmptyPathsProvider(), ApplySafetyOffset::No); } + // BBS Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& poly1, const Slic3r::ExPolygons& poly2, bool safety_offset_) { @@ -832,22 +820,15 @@ Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& poly1, const Slic3r::ExPol } Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset) { - return _clipper_ex(ClipperLib::ctXor, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); + return _clipper_ex(ctXor, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonProvider(clip), do_safety_offset); } Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset) { - return _clipper_ex(ClipperLib::ctXor, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); + return _clipper_ex(ctXor, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); } template -Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip) -{ - ClipperLib::Clipper clipper; - clipper.AddPaths(std::forward(subject), ClipperLib::ptSubject, false); - clipper.AddPaths(std::forward(clip), ClipperLib::ptClip, true); - ClipperLib::PolyTree retval; - clipper.Execute(clipType, retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - return PolyTreeToPolylines(std::move(retval)); -} +Polylines _clipper_pl_open(ClipType clipType, PathsProvider1 &&subject, PathsProvider2 &&clip) + { return c2_clip_open(to_c2(clipType), to_paths64(std::forward(subject)), to_paths64(std::forward(clip))); } // If the split_at_first_point() call above happens to split the polygon inside the clipping area // we would get two consecutive polylines instead of a single one, so we go through them in order @@ -888,51 +869,52 @@ static void _clipper_pl_recombine(Polylines &polylines) } template -Polylines _clipper_pl_closed(ClipperLib::ClipType clipType, PathProvider1 &&subject, PathProvider2 &&clip) +Polylines _clipper_pl_closed(ClipType clipType, PathProvider1 &&subject, PathProvider2 &&clip) { // Transform input polygons into open paths. - ClipperLib::Paths paths; + C2::Paths64 paths; paths.reserve(subject.size()); for (const Points &poly : subject) { // Emplace polygon, duplicate the 1st point. - paths.push_back({}); - ClipperLib::Path &path = paths.back(); + C2::Path64 &path = paths.emplace_back(); path.reserve(poly.size() + 1); - path = poly; - path.emplace_back(poly.front()); + for (const Point &pt : poly) + path.emplace_back(pt.x(), pt.y()); + if (! poly.empty()) + path.emplace_back(poly.front().x(), poly.front().y()); } // perform clipping - Polylines retval = _clipper_pl_open(clipType, paths, std::forward(clip)); + Polylines retval = c2_clip_open(to_c2(clipType), paths, to_paths64(std::forward(clip))); _clipper_pl_recombine(retval); return retval; } Slic3r::Polylines diff_pl(const Slic3r::Polyline& subject, const Slic3r::Polygons& clip) - { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_open(ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip) - { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_open(ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip) - { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); } + { return _clipper_pl_open(ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip) - { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); } + { return _clipper_pl_open(ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip) - { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); } + { return _clipper_pl_open(ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); } Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip) - { return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_closed(ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); } Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip) - { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); } + { return _clipper_pl_open(ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); } Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip) - { return _clipper_pl_closed(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); } + { return _clipper_pl_closed(ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); } // Orca: Sort and orient open polyline fragments produced by clipping `source` with // intersection_pl(), so that they run in the same order and direction as the source @@ -1005,7 +987,7 @@ void restore_source_path_order(const Slic3r::Polyline &source, Slic3r::Polylines fragments = std::move(sorted); } -Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons &clip) +Lines _clipper_ln(ClipType clipType, const Lines &subject, const Polygons &clip) { // convert Lines to Polylines Polylines polylines; @@ -1025,162 +1007,83 @@ Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Pol return retval; } -// Convert polygons / expolygons into ClipperLib::PolyTree using ClipperLib::pftEvenOdd, thus union will NOT be performed. -// If the contours are not intersecting, their orientation shall not be modified by union_pt(). -ClipperLib::PolyTree union_pt(const Polygons &subject) -{ - return clipper_do(ClipperLib::ctUnion, ClipperUtils::PolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftEvenOdd); -} -ClipperLib::PolyTree union_pt(const ExPolygons &subject) -{ - return clipper_do(ClipperLib::ctUnion, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::EmptyPathsProvider(), ClipperLib::pftEvenOdd); -} - -// Simple spatial ordering of Polynodes -ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes) +static void traverse_pt_outside_in(const C2::PolyPath64 &parent, Polygons *retval) { // collect ordering points Points ordering_points; - ordering_points.reserve(nodes.size()); - - for (const ClipperLib::PolyNode *node : nodes) - ordering_points.emplace_back( - Point(node->Contour.front().x(), node->Contour.front().y())); - - // perform the ordering - ClipperLib::PolyNodes ordered_nodes = - chain_clipper_polynodes(ordering_points, nodes); - - return ordered_nodes; -} - -static void traverse_pt_noholes(const ClipperLib::PolyNodes &nodes, Polygons *out) -{ - foreach_node(nodes, [&out](const ClipperLib::PolyNode *node) - { - traverse_pt_noholes(node->Childs, out); - out->emplace_back(node->Contour); - if (node->IsHole()) out->back().reverse(); // ccw - }); -} - -static void traverse_pt_outside_in(ClipperLib::PolyNodes &&nodes, Polygons *retval) -{ - // collect ordering points - Points ordering_points; - ordering_points.reserve(nodes.size()); - for (const ClipperLib::PolyNode *node : nodes) - ordering_points.emplace_back(node->Contour.front().x(), node->Contour.front().y()); + ordering_points.reserve(parent.Count()); + for (const auto &node : parent) + ordering_points.emplace_back(node->Polygon().front().x, node->Polygon().front().y); // Perform the ordering, push results recursively. - //FIXME pass the last point to chain_clipper_polynodes? - for (ClipperLib::PolyNode *node : chain_clipper_polynodes(ordering_points, nodes)) { - retval->emplace_back(std::move(node->Contour)); - if (node->IsHole()) + //FIXME pass the last point to chain_points? + for (size_t idx : chain_points(ordering_points)) { + const C2::PolyPath64 &node = *parent.Child(idx); + retval->emplace_back().points = c2_to_points(node.Polygon()); + if (node.IsHole()) // Orient a hole, which is clockwise oriented, to CCW. retval->back().reverse(); // traverse the next depth - traverse_pt_outside_in(std::move(node->Childs), retval); + traverse_pt_outside_in(node, retval); } } Polygons union_pt_chained_outside_in(const Polygons &subject) { + C2::PolyTree64 tree; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::PolygonsProvider(subject)), {}, C2::FillRule::EvenOdd, tree); Polygons retval; - traverse_pt_outside_in(union_pt(subject).Childs, &retval); + traverse_pt_outside_in(tree, &retval); return retval; } +// Clipper2 unions are strictly simple, like Clipper1's with StrictlySimple(true). Polygons simplify_polygons(const Polygons &subject) { - ClipperLib::Paths output; - ClipperLib::Clipper c; -// c.PreserveCollinear(true); - //FIXME StrictlySimple is very expensive! Is it needed? - c.StrictlySimple(true); - c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true); - c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - - // convert into Slic3r polygons - return to_polygons(std::move(output)); + C2::Paths64 out; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::PolygonsProvider(subject)), {}, C2::FillRule::NonZero, out); + return c2_to_polygons(out); } ExPolygons simplify_polygons_ex(const Polygons &subject) { - ClipperLib::PolyTree polytree; - ClipperLib::Clipper c; -// c.PreserveCollinear(true); - //FIXME StrictlySimple is very expensive! Is it needed? - c.StrictlySimple(true); - c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true); - c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - - // convert into ExPolygons - return PolyTreeToExPolygons(std::move(polytree)); + C2::PolyTree64 out; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::PolygonsProvider(subject)), {}, C2::FillRule::NonZero, out); + return c2_to_expolygons(out); } Polygons top_level_islands(const Slic3r::Polygons &polygons) { - // init Clipper - ClipperLib::Clipper clipper; - clipper.Clear(); - // perform union - clipper.AddPaths(ClipperUtils::PolygonsProvider(polygons), ClipperLib::ptSubject, true); - ClipperLib::PolyTree polytree; - clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); + C2::PolyTree64 tree; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::PolygonsProvider(polygons)), {}, C2::FillRule::EvenOdd, tree); // Convert only the top level islands to the output. Polygons out; - out.reserve(polytree.ChildCount()); - for (int i = 0; i < polytree.ChildCount(); ++i) - out.emplace_back(std::move(polytree.Childs[i]->Contour)); + out.reserve(tree.Count()); + for (const auto &island : tree) + out.emplace_back().points = c2_to_points(island->Polygon()); return out; } -// Outer offset shall not split the input contour into multiples. It is expected, that the solution will be non empty and it will contain just a single polygon. -ClipperLib::Paths fix_after_outer_offset( - const ClipperLib::Path &input, - // combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta) - // to produce a CCW output contour from CCW input contour for a positive offset. - ClipperLib::PolyFillType filltype, // = ClipperLib::pftPositive - bool reverse_result) // = false +ExPolygons top_level_expolygons(const ExPolygons &expolygons, ExPolygons *nested) { - ClipperLib::Paths solution; - if (! input.empty()) { - ClipperLib::Clipper clipper; - clipper.AddPath(input, ClipperLib::ptSubject, true); - clipper.ReverseSolution(reverse_result); - clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype); - } - return solution; + C2::PolyTree64 tree; + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::ExPolygonsProvider(expolygons)), {}, C2::FillRule::EvenOdd, tree); + ExPolygons out; + out.reserve(tree.Count()); + for (const auto &outer : tree) { + ExPolygon &expoly = out.emplace_back(); + expoly.contour.points = c2_to_points(outer->Polygon()); + for (const auto &hole : *outer) { + expoly.holes.emplace_back().points = c2_to_points(hole->Polygon()); + if (nested) + for (const auto &island : *hole) + c2_append_expolygons(*island, *nested); + } + } + return out; } -// Inner offset may split the source contour into multiple contours, but one resulting contour shall not lie inside the other. -ClipperLib::Paths fix_after_inner_offset( - const ClipperLib::Path &input, - // combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta) - // to produce a CCW output contour from CCW input contour for a negative offset. - ClipperLib::PolyFillType filltype, // = ClipperLib::pftNegative - bool reverse_result) // = true -{ - ClipperLib::Paths solution; - if (! input.empty()) { - ClipperLib::Clipper clipper; - clipper.AddPath(input, ClipperLib::ptSubject, true); - ClipperLib::IntRect r = clipper.GetBounds(); - r.left -= 10; r.top -= 10; r.right += 10; r.bottom += 10; - if (filltype == ClipperLib::pftPositive) - clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.left, r.top), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.right, r.bottom) }, ClipperLib::ptSubject, true); - else - clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.right, r.bottom), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.left, r.top) }, ClipperLib::ptSubject, true); - clipper.ReverseSolution(reverse_result); - clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype); - if (! solution.empty()) - solution.erase(solution.begin()); - } - return solution; -} - -ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit) +Points mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit) { assert(contour.size() == deltas.size()); @@ -1196,7 +1099,7 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v assert(! (negative && positive)); #endif /* NDEBUG */ - ClipperLib::Path out; + Points out; if (deltas.size() > 2) { @@ -1208,10 +1111,10 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v // perpenduclar vector auto perp = [](const Vec2d &v) -> Vec2d { return Vec2d(v.y(), - v.x()); }; - // Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt. + // Add a new point to the output, rounded to coord_t. auto add_offset_point = [&out](Vec2d pt) { pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0)); - out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y())); + out.emplace_back(coord_t(pt.x()), coord_t(pt.y())); }; // Minimum edge length, squared. @@ -1301,25 +1204,41 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v } } -#if 0 - { - ClipperLib::Path polytmp(out); - unscaleClipperPolygon(polytmp); - Slic3r::Polygon offsetted(std::move(polytmp)); - BoundingBox bbox = get_extents(contour); - bbox.merge(get_extents(offsetted)); - static int iRun = 0; - SVG svg(debug_out_path("mittered_offset_path_scaled-%d.svg", iRun ++).c_str(), bbox); - svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); - svg.draw_outline(offsetted, "red", scale_(0.01)); - svg.draw(contour, "blue", scale_(0.03)); - svg.draw((Points)offsetted, "blue", scale_(0.03)); - } -#endif - return out; } +// Clipper1 united the raw contour offsets with the positive rule and the raw hole offsets with the negative rule. +template +static void variable_offset(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit, TOut &out) +{ + auto unite = [](const Points &raw, C2::FillRule fill) { + C2::Paths64 united; + if (! raw.empty()) + c2_clip(C2::ClipType::Union, to_paths64(ClipperUtils::SinglePathProvider(raw)), {}, fill, united); + return united; + }; + + // 1) Offset the outer contour. + C2::Paths64 contours = unite(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), C2::FillRule::Positive); +#ifndef NDEBUG + for (auto &c : contours) + assert(C2::Area(c) > 0.); +#endif /* NDEBUG */ + + // 2) Offset the holes one by one, collect the results. + C2::Paths64 holes; + holes.reserve(expoly.holes.size()); + for (const Polygon& hole : expoly.holes) + append(holes, unite(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), C2::FillRule::Negative)); +#ifndef NDEBUG + for (auto &c : holes) + assert(C2::Area(c) > 0.); +#endif /* NDEBUG */ + + // 3) Subtract holes from the contours. + c2_clip(C2::ClipType::Difference, contours, holes, C2::FillRule::NonZero, out); +} + Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) { #ifndef NDEBUG @@ -1330,126 +1249,41 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector 0.); -#endif /* NDEBUG */ - - // 2) Offset the holes one by one, collect the results. - ClipperLib::Paths holes; - holes.reserve(expoly.holes.size()); - for (const Polygon& hole : expoly.holes) - append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false)); -#ifndef NDEBUG - for (auto &c : holes) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 3) Subtract holes from the contours. - ClipperLib::Paths output; - if (holes.empty()) - output = std::move(contours); - else { - ClipperLib::Clipper clipper; - clipper.Clear(); - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - } - - return to_polygons(std::move(output)); + C2::Paths64 out; + variable_offset(expoly, deltas, miter_limit, out); + return c2_to_polygons(out); } Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) { #ifndef NDEBUG - // Verify that the deltas are all non positive. -for (const std::vector& ds : deltas) + // Verify that the deltas are all non negative. + for (const std::vector& ds : deltas) for (float delta : ds) assert(delta >= 0.); assert(expoly.holes.size() + 1 == deltas.size()); #endif /* NDEBUG */ - // 1) Offset the outer contour. - ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false); -#ifndef NDEBUG - for (auto &c : contours) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 2) Offset the holes one by one, collect the results. - ClipperLib::Paths holes; - holes.reserve(expoly.holes.size()); - for (const Polygon& hole : expoly.holes) - append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); -#ifndef NDEBUG - for (auto &c : holes) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 3) Subtract holes from the contours. - ClipperLib::Paths output; - if (holes.empty()) - output = std::move(contours); - else { - ClipperLib::Clipper clipper; - clipper.Clear(); - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - } - - return to_polygons(std::move(output)); + C2::Paths64 out; + variable_offset(expoly, deltas, miter_limit, out); + return c2_to_polygons(out); } ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) { #ifndef NDEBUG - // Verify that the deltas are all non positive. -for (const std::vector& ds : deltas) + // Verify that the deltas are all non negative. + for (const std::vector& ds : deltas) for (float delta : ds) assert(delta >= 0.); assert(expoly.holes.size() + 1 == deltas.size()); #endif /* NDEBUG */ - // 1) Offset the outer contour. - ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false); -#ifndef NDEBUG - for (auto &c : contours) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 2) Offset the holes one by one, collect the results. - ClipperLib::Paths holes; - holes.reserve(expoly.holes.size()); - for (const Polygon& hole : expoly.holes) - append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); -#ifndef NDEBUG - for (auto &c : holes) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 3) Subtract holes from the contours. - ExPolygons output; - if (holes.empty()) { - output.reserve(contours.size()); - for (ClipperLib::Path &path : contours) - output.emplace_back(std::move(path)); - } else { - ClipperLib::Clipper clipper; - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - ClipperLib::PolyTree polytree; - clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - output = PolyTreeToExPolygons(std::move(polytree)); - } - - return output; + C2::PolyTree64 out; + variable_offset(expoly, deltas, miter_limit, out); + return c2_to_expolygons(out); } - ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) { #ifndef NDEBUG @@ -1460,39 +1294,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector 0.); -#endif /* NDEBUG */ - - // 2) Offset the holes one by one, collect the results. - ClipperLib::Paths holes; - holes.reserve(expoly.holes.size()); - for (const Polygon& hole : expoly.holes) - append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false)); -#ifndef NDEBUG - for (auto &c : holes) - assert(ClipperLib::Area(c) > 0.); -#endif /* NDEBUG */ - - // 3) Subtract holes from the contours. - ExPolygons output; - if (holes.empty()) { - output.reserve(contours.size()); - for (ClipperLib::Path &path : contours) - output.emplace_back(std::move(path)); - } else { - ClipperLib::Clipper clipper; - clipper.AddPaths(contours, ClipperLib::ptSubject, true); - clipper.AddPaths(holes, ClipperLib::ptClip, true); - ClipperLib::PolyTree polytree; - clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - output = PolyTreeToExPolygons(std::move(polytree)); - } - - return output; + C2::PolyTree64 out; + variable_offset(expoly, deltas, miter_limit, out); + return c2_to_expolygons(out); } Pointfs make_counter_clockwise(const Pointfs& pointfs) diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 5ed161c27a..00cf60076b 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -1,24 +1,40 @@ #ifndef slic3r_ClipperUtils_hpp_ #define slic3r_ClipperUtils_hpp_ +#include "Point.hpp" +#include "Polyline.hpp" +#include "Line.hpp" #include "libslic3r.h" -#include "clipper.hpp" #include "ExPolygon.hpp" #include "Polygon.hpp" #include "Surface.hpp" +#include +#include +#include +#include + +namespace Slic3r { + +// Offset joins and ends, fill rules and boolean operations, named as in Clipper1. +enum JoinType { jtSquare, jtRound, jtMiter }; +enum EndType { etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound }; +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; + +} // namespace Slic3r // import these wherever we're included -using Slic3r::ClipperLib::jtMiter; -using Slic3r::ClipperLib::jtRound; -using Slic3r::ClipperLib::jtSquare; +using Slic3r::jtMiter; +using Slic3r::jtRound; +using Slic3r::jtSquare; namespace Slic3r { static constexpr const float ClipperSafetyOffset = 10.f; -static constexpr const Slic3r::ClipperLib::JoinType DefaultJoinType = Slic3r::ClipperLib::jtMiter; +static constexpr const JoinType DefaultJoinType = jtMiter; -static constexpr const Slic3r::ClipperLib::EndType DefaultEndType = Slic3r::ClipperLib::etOpenButt; +static constexpr const EndType DefaultEndType = etOpenButt; //FIXME evaluate the default miter limit. 3 seems to be extreme, Cura uses 1.2. // Mitter Limit 3 is useful for perimeter generator, where sharp corners are extruded without needing a gap fill. @@ -26,7 +42,7 @@ static constexpr const Slic3r::ClipperLib::EndType DefaultEndType = Sl // is extended excessively. static constexpr const double DefaultMiterLimit = 3.; -static constexpr const Slic3r::ClipperLib::JoinType DefaultLineJoinType = Slic3r::ClipperLib::jtSquare; +static constexpr const JoinType DefaultLineJoinType = jtSquare; // Miter limit is ignored for jtSquare. static constexpr const double DefaultLineMiterLimit = 0.; @@ -304,12 +320,12 @@ namespace ClipperUtils { }; - // For ClipperLib with Z coordinates. + // Points with a Z coordinate. using ZPoint = Vec3i32; using ZPoints = std::vector; // Clip source polygon to be used as a clipping polygon with a bouding box around the source (to be clipped) polygon. - // Useful as an optimization for expensive ClipperLib operations, for example when clipping source polygons one by one + // Useful as an optimization for expensive Clipper operations, for example when clipping source polygons one by one // with a set of polygons covering the whole layer below. void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons = false); void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out); @@ -323,31 +339,28 @@ namespace ClipperUtils { } -// Perform union of input polygons using the non-zero rule, convert to ExPolygons. -ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union = false); - // offset Polygons // Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better. -Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); // offset Polylines // Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better. // Input polygons for negative offset shall be "normalized": There must be no overlap / intersections between the input polygons. -Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, ClipperLib::EndType end_type = DefaultEndType); -Slic3r::Polygons offset(const Slic3r::Polyline3 &polyline, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, ClipperLib::EndType end_type = DefaultEndType); -Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, ClipperLib::JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, ClipperLib::EndType end_type = DefaultEndType); -Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset_ex(const Slic3r::SurfacesPtr &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType); +Slic3r::Polygons offset(const Slic3r::Polyline3 &polyline, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType); +Slic3r::Polygons offset(const Slic3r::Polylines &polylines, const float delta, JoinType joinType = DefaultLineJoinType, double miterLimit = DefaultLineMiterLimit, EndType end_type = DefaultEndType); +Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset_ex(const Slic3r::SurfacesPtr &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); // BBS -inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { Slic3r::Polygons temp; temp.push_back(polygon); @@ -356,8 +369,8 @@ inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float } // convert stroke to path by offsetting of contour -Polygons contour_to_polygons(const Polygon &polygon, const float line_width, ClipperLib::JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit); -Polygons contour_to_polygons(const Polygons &polygon, const float line_width, ClipperLib::JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit); +Polygons contour_to_polygons(const Polygon &polygon, const float line_width, JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit); +Polygons contour_to_polygons(const Polygons &polygon, const float line_width, JoinType join_type = DefaultJoinType, double miter_limit = DefaultMiterLimit); inline Slic3r::Polygons union_safety_offset (const Slic3r::Polygons &polygons) { return offset (polygons, ClipperSafetyOffset); } inline Slic3r::Polygons union_safety_offset (const Slic3r::ExPolygons &expolygons) { return offset (expolygons, ClipperSafetyOffset); } @@ -370,62 +383,62 @@ Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons); Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::ExPolygons &expolygons); // Aliases for the various offset(...) functions, conveying the purpose of the offset. -inline Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset(polygon, delta, joinType, miterLimit); } -inline Slic3r::Polygons expand(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons expand(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); } -inline Slic3r::Polygons expand(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons expand(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset(polygons, delta, joinType, miterLimit); } -inline Slic3r::ExPolygons expand_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons expand_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset_ex(polygons, delta, joinType, miterLimit); } // Input polygons for shrinking shall be "normalized": There must be no overlap / intersections between the input polygons. -inline Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset(polygons, -delta, joinType, miterLimit); } -inline Slic3r::ExPolygons shrink_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons shrink_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset_ex(polygons, -delta, joinType, miterLimit); } -inline Slic3r::ExPolygons shrink_ex(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons shrink_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset_ex(polygons, -delta, joinType, miterLimit); } // Wherever applicable, please use the opening() / closing() variants instead, they convey their purpose better. // Input polygons for negative offset shall be "normalized": There must be no overlap / intersections between the input polygons. -Slic3r::Polygons offset2(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::ExPolygons offset2_ex(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons offset2(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::ExPolygons offset2_ex(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); // BBS -Slic3r::ExPolygons _clipper_ex(ClipperLib::ClipType clipType, +Slic3r::ExPolygons _clipper_ex(ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false); // Offset outside, then inside produces morphological closing. All deltas should be positive. -Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -inline Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +inline Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { return closing(polygons, delta, delta, joinType, miterLimit); } -Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -inline Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +inline Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { return closing_ex(polygons, delta, delta, joinType, miterLimit); } -inline Slic3r::ExPolygons closing_ex(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons closing_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset2_ex(polygons, delta, - delta, joinType, miterLimit); } -inline Slic3r::ExPolygons closing_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons closing_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset2_ex(surfaces, delta, - delta, joinType, miterLimit); } // Offset inside, then outside produces morphological opening. All deltas should be positive. // Input polygons for opening shall be "normalized": There must be no overlap / intersections between the input polygons. -Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); -inline Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta1, const float delta2, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit); +inline Slic3r::Polygons opening(const Slic3r::Polygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { return opening(polygons, delta, delta, joinType, miterLimit); } -inline Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons opening(const Slic3r::ExPolygons &expolygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { return opening(expolygons, delta, delta, joinType, miterLimit); } -inline Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::Polygons opening(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { return opening(surfaces, delta, delta, joinType, miterLimit); } -inline Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset2_ex(polygons, - delta, delta, joinType, miterLimit); } -inline Slic3r::ExPolygons opening_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) +inline Slic3r::ExPolygons opening_ex(const Slic3r::Surfaces &surfaces, const float delta, JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit) { assert(delta > 0); return offset2_ex(surfaces, - delta, delta, joinType, miterLimit); } -Slic3r::Lines _clipper_ln(ClipperLib::ClipType clipType, const Slic3r::Lines &subject, const Slic3r::Polygons &clip); +Slic3r::Lines _clipper_ln(ClipType clipType, const Slic3r::Lines &subject, const Slic3r::Polygons &clip); // Safety offset is applied to the clipping polygons only. Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); @@ -489,13 +502,14 @@ inline Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons& subject, const Slic3 inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip) { - return _clipper_ln(ClipperLib::ctDifference, subject, clip); + return _clipper_ln(ctDifference, subject, clip); } // Safety offset is applied to the clipping polygons only. Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); +Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, PolyFillType fill_type); Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); // Optimized version clipping the "clipping" polygon using clip_clipper_polygon_with_subject_bbox(). // To be used with complex clipping polygons, where majority of the clipping polygons are outside of the source polygon. @@ -534,135 +548,42 @@ void restore_source_path_order(const Slic3r::Polyline &source, Slic3r::Polylines inline Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip) { - return _clipper_ln(ClipperLib::ctIntersection, subject, clip); + return _clipper_ln(ctIntersection, subject, clip); } inline Slic3r::Lines intersection_ln(const Slic3r::Line &subject, const Slic3r::Polygons &clip) { Slic3r::Lines lines; lines.emplace_back(subject); - return _clipper_ln(ClipperLib::ctIntersection, lines, clip); + return _clipper_ln(ctIntersection, lines, clip); } Slic3r::Polygons union_(const Slic3r::Polygons &subject); Slic3r::Polygons union_(const Slic3r::ExPolygons &subject); -Slic3r::Polygons union_(const Slic3r::Polygons &subject, const ClipperLib::PolyFillType fillType); +Slic3r::Polygons union_(const Slic3r::Polygons &subject, const PolyFillType fillType); Slic3r::Polygons union_(const Slic3r::Polygons &subject, const Slic3r::Polygons &subject2); // May be used to "heal" unusual models (3DLabPrints etc.) by providing fill_type (pftEvenOdd, pftNonZero, pftPositive, pftNegative). -Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero); +Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type = pftNonZero); Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject); Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &subject2); Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject); Slic3r::ExPolygons union_ex(const Slic3r::ExPolygons& poly1, const Slic3r::ExPolygons& poly2, bool safety_offset_ = false); -// Convert polygons / expolygons into ClipperLib::PolyTree using ClipperLib::pftEvenOdd, thus union will NOT be performed. -// If the contours are not intersecting, their orientation shall not be modified by union_pt(). -ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject); -ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject); - Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::ExPolygons xor_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No); Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject); -ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes); - -// Implementing generalized loop (foreach) over a list of nodes which can be -// ordered or unordered (performance gain) based on template parameter -enum class e_ordering { - ON, - OFF -}; - -// Create a template struct, template functions can not be partially specialized -template struct _foreach_node { - void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn); -}; - -// Specialization with NO ordering -template struct _foreach_node { - void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn) - { - for (auto &n : nodes) fn(n); - } -}; - -// Specialization with ordering -template struct _foreach_node { - void operator()(const ClipperLib::PolyNodes &nodes, Fn &&fn) - { - auto ordered_nodes = order_nodes(nodes); - for (auto &n : nodes) fn(n); - } -}; - -// Wrapper function for the foreach_node which can deduce arguments automatically -template -void foreach_node(const ClipperLib::PolyNodes &nodes, Fn &&fn) -{ - _foreach_node()(nodes, std::forward(fn)); -} - -// Collecting polygons of the tree into a list of Polygons, holes have clockwise -// orientation. -template -void traverse_pt(const ClipperLib::PolyNode *tree, Polygons *out) -{ - if (!tree) return; // terminates recursion - - // Push the contour of the current level - out->emplace_back(tree->Contour); - - // Do the recursion for all the children. - traverse_pt(tree->Childs, out); -} - -// Collecting polygons of the tree into a list of ExPolygons. -template -void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *out) -{ - if (!tree) return; - else if(tree->IsHole()) { - // Levels of holes are skipped and handled together with the - // contour levels. - traverse_pt(tree->Childs, out); - return; - } - - ExPolygon level; - level.contour.points = tree->Contour; - - foreach_node(tree->Childs, - [out, &level] (const ClipperLib::PolyNode *node) { - - // Holes are collected here. - level.holes.emplace_back(node->Contour); - - // By doing a recursion, a new level expoly is created with the contour - // and holes of the lower level. Doing this for all the childs. - traverse_pt(node->Childs, out); - }); - - out->emplace_back(level); -} - -template -void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval) -{ - foreach_node(nodes, [&retval](const ClipperLib::PolyNode *node) { - traverse_pt(node, retval); - }); -} - - /* OTHER */ Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject); Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject); Polygons top_level_islands(const Slic3r::Polygons &polygons); +// Top level expolygons of the even-odd union, the ones nested in their holes go to `nested`. +ExPolygons top_level_expolygons(const ExPolygons &expolygons, ExPolygons *nested = nullptr); -ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit); +Points mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit); Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); diff --git a/src/libslic3r/ClipperZUtils.cpp b/src/libslic3r/ClipperZUtils.cpp new file mode 100644 index 0000000000..a07f40dc4a --- /dev/null +++ b/src/libslic3r/ClipperZUtils.cpp @@ -0,0 +1,79 @@ +#include "ClipperZUtils.hpp" +#include "ClipperUtils.hpp" + +#include +#include + +namespace Slic3r { +namespace ClipperZUtils { + +namespace C2 = Clipper2Lib_Z; + +static C2::Paths64 to_paths64(const ZPaths &paths) +{ + C2::Paths64 out; + out.reserve(paths.size()); + for (const ZPath &path : paths) { + C2::Path64 &dst = out.emplace_back(); + dst.reserve(path.size()); + for (const ZPoint &pt : path) + dst.emplace_back(pt.x(), pt.y(), pt.z()); + } + return out; +} + +static void append_zpaths(const C2::Paths64 &paths, ZPaths &out) +{ + out.reserve(out.size() + paths.size()); + for (const C2::Path64 &path : paths) { + ZPath &dst = out.emplace_back(); + dst.reserve(path.size()); + for (const C2::Point64 &pt : path) + dst.emplace_back(pt.x, pt.y, pt.z); + } +} + +double area(const ZPath &path) +{ + const size_t size = path.size(); + if (size < 3) + return 0.; + double a = 0.; + for (size_t i = 0, j = size - 1; i < size; j = i ++) + a += (double(path[j].x()) + path[i].x()) * (double(path[j].y()) - path[i].y()); + return -a * 0.5; +} + +ZPaths clip_zpaths(ClipType clip_type, const ZPaths &subject, bool subject_open, const ZPaths &clip, const ZFillCallback &zfill, bool preserve_collinear) +{ + C2::Clipper64 clipper; + clipper.PreserveCollinear(preserve_collinear); + if (zfill) + clipper.SetZCallback([&zfill](const C2::Point64 &e1bot, const C2::Point64 &e1top, const C2::Point64 &e2bot, const C2::Point64 &e2top, C2::Point64 &pt) { + // Clipper2 already copied Z from a coincident input vertex. + auto coincident = [&pt](const C2::Point64 &p) { return p.x == pt.x && p.y == pt.y; }; + if (coincident(e1bot) || coincident(e1top) || coincident(e2bot) || coincident(e2top)) + return; + ZPoint zpt(pt.x, pt.y, pt.z); + zfill(ZPoint(e1bot.x, e1bot.y, e1bot.z), ZPoint(e1top.x, e1top.y, e1top.z), + ZPoint(e2bot.x, e2bot.y, e2bot.z), ZPoint(e2top.x, e2top.y, e2top.z), zpt); + pt.z = zpt.z(); + }); + if (subject_open) + clipper.AddOpenSubject(to_paths64(subject)); + else + clipper.AddSubject(to_paths64(subject)); + clipper.AddClip(to_paths64(clip)); + const C2::ClipType type = clip_type == ctIntersection ? C2::ClipType::Intersection : + clip_type == ctUnion ? C2::ClipType::Union : + clip_type == ctDifference ? C2::ClipType::Difference : C2::ClipType::Xor; + C2::Paths64 closed, open; + clipper.Execute(type, C2::FillRule::NonZero, closed, open); + ZPaths out; + append_zpaths(closed, out); + append_zpaths(open, out); + return out; +} + +} // namespace ClipperZUtils +} // namespace Slic3r diff --git a/src/libslic3r/ClipperZUtils.hpp b/src/libslic3r/ClipperZUtils.hpp index 7465bd31a4..781357caa5 100644 --- a/src/libslic3r/ClipperZUtils.hpp +++ b/src/libslic3r/ClipperZUtils.hpp @@ -1,10 +1,16 @@ #ifndef slic3r_ClipperZUtils_hpp_ #define slic3r_ClipperZUtils_hpp_ +#include "libslic3r.h" +#include +#include +#include +#include #include +#include #include -#include +#include #include #include @@ -12,10 +18,13 @@ namespace Slic3r { namespace ClipperZUtils { -using ZPoint = ClipperLib_Z::IntPoint; -using ZPoints = ClipperLib_Z::Path; -using ZPath = ClipperLib_Z::Path; -using ZPaths = ClipperLib_Z::Paths; +using ZPoint = Vec3crd; +using ZPoints = std::vector>; +using ZPath = ZPoints; +using ZPaths = std::vector>; + +// Sets Z of an intersection point from the edges crossing there. +using ZFillCallback = std::function; inline bool zpoint_lower(const ZPoint &l, const ZPoint &r) { @@ -101,6 +110,12 @@ inline VecOfPoints from_zpaths(const ZPaths &paths) return out; } +// Signed area, positive for a CCW path. +double area(const ZPath &path); + +// Non-zero rule boolean, the subject may be open. zfill only sees intersections off the input vertices. +ZPaths clip_zpaths(ClipType clip_type, const ZPaths &subject, bool subject_open, const ZPaths &clip, const ZFillCallback &zfill, bool preserve_collinear = false); + class ClipperZIntersectionVisitor { public: using Intersection = std::pair; @@ -126,8 +141,8 @@ public: } } } - ClipperLib_Z::ZFillCallback clipper_callback() { - return [this](const ZPoint &e1bot, const ZPoint &e1top, + ZFillCallback clipper_callback() { + return [this](const ZPoint &e1bot, const ZPoint &e1top, const ZPoint &e2bot, const ZPoint &e2top, ZPoint &pt) { return (*this)(e1bot, e1top, e2bot, e2top, pt); }; } diff --git a/src/libslic3r/Color.cpp b/src/libslic3r/Color.cpp index d7208d40fc..bb08b7c75b 100644 --- a/src/libslic3r/Color.cpp +++ b/src/libslic3r/Color.cpp @@ -1,7 +1,15 @@ #include "libslic3r.h" #include "Color.hpp" +#include +#include +#include +#include +#include +#include #include +#include +#include static const float INV_255 = 1.0f / 255.0f; diff --git a/src/libslic3r/ColorDecomposeRecipe.cpp b/src/libslic3r/ColorDecomposeRecipe.cpp index f2ceb1860a..6aa09f01d2 100644 --- a/src/libslic3r/ColorDecomposeRecipe.cpp +++ b/src/libslic3r/ColorDecomposeRecipe.cpp @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include namespace Slic3r { namespace { diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index df2030b575..38c5b30118 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -1,4 +1,6 @@ #include "Config.hpp" +#include "Exception.hpp" +#include "Point.hpp" #include "format.hpp" #include "Utils.hpp" #include "LocalesUtils.hpp" @@ -6,7 +8,20 @@ #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -26,8 +41,15 @@ #include #include #include +#include #include +#include +#include +#include +#include //BBS: add json support +#include "libslic3r.h" +#include "libslic3r_version.h" #include "nlohmann/json.hpp" using namespace nlohmann; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 9818887c1d..9d76262ec6 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -3,6 +3,11 @@ #include #include +#include +#include +#include +#include +#include #include #include #include @@ -10,10 +15,15 @@ #include #include #include +#include #include +#include +#include #include #include +#include #include +#include "LocalesUtils.hpp" #include "libslic3r.h" #include "clonable_ptr.hpp" #include "Exception.hpp" diff --git a/src/libslic3r/ContourZ.cpp b/src/libslic3r/ContourZ.cpp index f4a5fc049a..8751bcca58 100644 --- a/src/libslic3r/ContourZ.cpp +++ b/src/libslic3r/ContourZ.cpp @@ -2,14 +2,18 @@ #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" #include "Layer.hpp" +#include "Line.hpp" #include "Point.hpp" #include "Print.hpp" #include "SLA/IndexedMesh.hpp" #include "libslic3r.h" +#include #include #include #include +#include #include +#include namespace Slic3r { diff --git a/src/libslic3r/CustomGCode.cpp b/src/libslic3r/CustomGCode.cpp index acd7089c05..a78bc2a111 100644 --- a/src/libslic3r/CustomGCode.cpp +++ b/src/libslic3r/CustomGCode.cpp @@ -2,6 +2,10 @@ #include "Config.hpp" #include "GCode.hpp" #include "GCodeWriter.hpp" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CustomGCode.hpp b/src/libslic3r/CustomGCode.hpp index 7d8c7d9982..a4ed244dc5 100644 --- a/src/libslic3r/CustomGCode.hpp +++ b/src/libslic3r/CustomGCode.hpp @@ -1,7 +1,10 @@ #ifndef slic3r_CustomGCode_hpp_ #define slic3r_CustomGCode_hpp_ +#include +#include #include +#include #include #include diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp index 606a5b8aaa..8967f6c2ba 100644 --- a/src/libslic3r/CutSurface.cpp +++ b/src/libslic3r/CutSurface.cpp @@ -1,4 +1,38 @@ #include "CutSurface.hpp" +#include "libslic3r/Emboss.hpp" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/ExPolygon.hpp" +#include +#include +#include +#include +#include "libslic3r/BoundingBox.hpp" +#include +#include "libslic3r/Polygon.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/AABBTreeIndirect.hpp" +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include /// models_input.obj - Check transormation of model to each others /// projection_center.obj - circle representing center of projection with correct distance @@ -3519,7 +3553,7 @@ ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &projection, { Polygons polys = unproject_loops(patch, projection, depth_range); // should not be used when no opposit triangle are counted so should not create overlaps - ClipperLib::PolyFillType fill_type = ClipperLib::PolyFillType::pftEvenOdd; + PolyFillType fill_type = pftEvenOdd; ExPolygons expolys = Slic3r::union_ex(polys, fill_type); if (expolys.size() == 1) return expolys.front(); diff --git a/src/libslic3r/CutSurface.hpp b/src/libslic3r/CutSurface.hpp index 9f4e3159cf..33b0d88697 100644 --- a/src/libslic3r/CutSurface.hpp +++ b/src/libslic3r/CutSurface.hpp @@ -1,6 +1,8 @@ #ifndef slic3r_CutSurface_hpp_ #define slic3r_CutSurface_hpp_ +#include "libslic3r/BoundingBox.hpp" +#include #include #include // indexed_triangle_set #include "ExPolygon.hpp" diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index f8b1483773..e5cb3cc6f1 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -1,13 +1,24 @@ #include "CutUtils.hpp" #include "Geometry.hpp" +#include "Point.hpp" +#include "TriangleMesh.hpp" #include "libslic3r.h" #include "Model.hpp" #include "TriangleMeshSlicer.hpp" #include "TriangleSelector.hpp" #include "ObjectID.hpp" +#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/CutUtils.hpp b/src/libslic3r/CutUtils.hpp index b7f31d7b9a..37f30308b6 100644 --- a/src/libslic3r/CutUtils.hpp +++ b/src/libslic3r/CutUtils.hpp @@ -5,6 +5,7 @@ #include "Point.hpp" #include "Model.hpp" +#include #include namespace Slic3r { diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index 93bf7d48ec..c6e003505a 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -1,10 +1,21 @@ #include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include "Polygon.hpp" +#include "Point.hpp" +#include "Polyline.hpp" +#include "ExPolygon.hpp" +#include "Line.hpp" #include "libslic3r.h" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 6bbed1e9fa..971d23ead6 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -1,12 +1,24 @@ #ifndef slic3r_EdgeGrid_hpp_ #define slic3r_EdgeGrid_hpp_ +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include "Line.hpp" #include "Point.hpp" #include "BoundingBox.hpp" #include "ExPolygon.hpp" +#include "libslic3r.h" +#include "Polygon.hpp" +#include "Polyline.hpp" namespace Slic3r { namespace EdgeGrid { diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index 0adff1ba4e..40b856ee4b 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -1,5 +1,6 @@ -#include "clipper/clipper_z.hpp" - +#include "Point.hpp" +#include "BoundingBox.hpp" +#include "Polygon.hpp" #include "libslic3r.h" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" @@ -10,8 +11,14 @@ #include "SVG.hpp" #include "Utils.hpp" +#include #include #include +#include +#include +#include +#include +#include // #define CONTOUR_DISTANCE_DEBUG_SVG diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index 38c035806c..ae13cbf54e 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -1,12 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "Emboss.hpp" +#include #include #include #include #include #include #include // union_ex + for boldness(polygon extend(offset)) +#include "ExPolygon.hpp" +#include +#include "AABBTreeIndirect.hpp" +#include +#include "EmbossShape.hpp" +#include #include "IntersectionPoints.hpp" +#include "Polygon.hpp" +#include "TextConfiguration.hpp" +#include "Point.hpp" #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "imgui/imstb_truetype.h" // stbtt_fontinfo @@ -404,18 +427,89 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist return true; } +// Clipper1's CleanPolygon(): removes vertices closer than `distance` to a neighbour or to the line through their neighbours. +static void clean_polygon(Points &points, double distance) +{ + auto points_are_close = [](const Point &a, const Point &b, double dist2) { + const double dx = double(a.x() - b.x()), dy = double(a.y() - b.y()); + return dx * dx + dy * dy <= dist2; + }; + auto distance_from_line2 = [](const Point &pt, const Point &ln1, const Point &ln2) { + const double A = double(ln1.y() - ln2.y()); + const double B = double(ln2.x() - ln1.x()); + const double C = A * pt.x() + B * pt.y() - (A * ln1.x() + B * ln1.y()); + return (C * C) / (A * A + B * B); + }; + auto slopes_near_collinear = [&distance_from_line2](const Point &pt1, const Point &pt2, const Point &pt3, double dist2) { + if (std::abs(pt1.x() - pt2.x()) > std::abs(pt1.y() - pt2.y())) { + if ((pt1.x() > pt2.x()) == (pt1.x() < pt3.x())) + return distance_from_line2(pt1, pt2, pt3) < dist2; + if ((pt2.x() > pt1.x()) == (pt2.x() < pt3.x())) + return distance_from_line2(pt2, pt1, pt3) < dist2; + return distance_from_line2(pt3, pt1, pt2) < dist2; + } + if ((pt1.y() > pt2.y()) == (pt1.y() < pt3.y())) + return distance_from_line2(pt1, pt2, pt3) < dist2; + if ((pt2.y() > pt1.y()) == (pt2.y() < pt3.y())) + return distance_from_line2(pt2, pt1, pt3) < dist2; + return distance_from_line2(pt3, pt1, pt2) < dist2; + }; + + size_t size = points.size(); + if (size == 0) + return; + std::vector next(size), prev(size); + std::vector done(size, 0); + for (size_t i = 0; i < size; ++i) { + next[i] = (i + 1) % size; + prev[next[i]] = i; + } + auto exclude = [&next, &prev, &done](size_t op) { + const size_t result = prev[op]; + next[result] = next[op]; + prev[next[op]] = result; + done[result] = 0; + return result; + }; + const double dist2 = distance * distance; + size_t op = 0; + while (! done[op] && next[op] != prev[op]) { + if (points_are_close(points[op], points[prev[op]], dist2)) { + op = exclude(op); + -- size; + } else if (points_are_close(points[prev[op]], points[next[op]], dist2)) { + exclude(next[op]); + op = exclude(op); + size -= 2; + } else if (slopes_near_collinear(points[prev[op]], points[op], points[next[op]], dist2)) { + op = exclude(op); + -- size; + } else { + done[op] = 1; + op = next[op]; + } + } + if (size < 3) + size = 0; + Points out; + out.reserve(size); + for (size_t i = 0; i < size; ++i) { + out.emplace_back(points[op]); + op = next[op]; + } + points = std::move(out); +} + HealedExPolygons Emboss::heal_polygons(const Polygons &shape, bool is_non_zero, unsigned int max_iteration) { const double clean_distance = 1.415; // little grater than sqrt(2) - ClipperLib::PolyFillType fill_type = is_non_zero ? - ClipperLib::pftNonZero : ClipperLib::pftEvenOdd; + PolyFillType fill_type = is_non_zero ? pftNonZero : pftEvenOdd; // When edit this code check that font 'ALIENATE.TTF' and glyph 'i' still work // fix of self intersections - // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/SimplifyPolygon.htm - ClipperLib::Paths paths = ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(shape), fill_type); - ClipperLib::CleanPolygons(paths, clean_distance); - Polygons polygons = to_polygons(paths); + Polygons polygons = union_(shape, fill_type); + for (Polygon &polygon : polygons) + clean_polygon(polygon.points, clean_distance); polygons.erase(std::remove_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return p.size() < 3; }), polygons.end()); diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 506e703b2a..9b7beafec7 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -1,11 +1,19 @@ #ifndef slic3r_Emboss_hpp_ #define slic3r_Emboss_hpp_ +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include // indexed_triangle_set +#include "Point.hpp" #include "Polygon.hpp" #include "ExPolygon.hpp" #include "EmbossShape.hpp" // ExPolygonsWithIds @@ -165,7 +173,7 @@ namespace Emboss /// Fix duplicit points and self intersections in polygons. /// Also try to reduce amount of points and remove useless polygon parts /// - /// Fill type ClipperLib::pftNonZero for overlapping otherwise + /// Fill type pftNonZero for overlapping otherwise /// Look at heal_expolygon()::max_iteration /// Healed shapes with flag is fully healed HealedExPolygons heal_polygons(const Polygons &shape, bool is_non_zero = true, unsigned max_iteration = 10); diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 3e4a950037..490844bdef 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -9,9 +9,11 @@ #include #include #include +#include #include "Point.hpp" // Transform3d #include "ExPolygon.hpp" #include "ExPolygonSerialize.hpp" +#include "libslic3r.h" #include "nanosvg/nanosvg.h" // NSVGimage namespace Slic3r { diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 185e925084..f34b07b7cb 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -2,13 +2,23 @@ #include "ExPolygon.hpp" #include "Exception.hpp" #include "Geometry/MedialAxis.hpp" +#include "Point.hpp" +#include "MultiPoint.hpp" #include "Polygon.hpp" #include "Line.hpp" #include "ClipperUtils.hpp" +#include "Polyline.hpp" #include "SVG.hpp" +#include "libslic3r.h" #include #include +#include +#include +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index ce7ebe892f..d695171d1e 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -1,10 +1,17 @@ #ifndef slic3r_ExPolygon_hpp_ #define slic3r_ExPolygon_hpp_ +#include "Line.hpp" #include "Point.hpp" #include "libslic3r.h" #include "Polygon.hpp" #include "Polyline.hpp" +#include +#include +#include +#include +#include +#include #include namespace Slic3r { diff --git a/src/libslic3r/ExPolygonCollection.hpp b/src/libslic3r/ExPolygonCollection.hpp index 35e1eef4eb..ecef053ebc 100644 --- a/src/libslic3r/ExPolygonCollection.hpp +++ b/src/libslic3r/ExPolygonCollection.hpp @@ -1,10 +1,13 @@ #ifndef slic3r_ExPolygonCollection_hpp_ #define slic3r_ExPolygonCollection_hpp_ +#include "Point.hpp" +#include "Polygon.hpp" #include "libslic3r.h" #include "ExPolygon.hpp" #include "Line.hpp" #include "Polyline.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/ExPolygonSerialize.hpp b/src/libslic3r/ExPolygonSerialize.hpp index 712d4706d5..58d12093e6 100644 --- a/src/libslic3r/ExPolygonSerialize.hpp +++ b/src/libslic3r/ExPolygonSerialize.hpp @@ -3,6 +3,7 @@ #include "ExPolygon.hpp" #include "Point.hpp" // Cereal serialization of Point +#include "Polygon.hpp" #include #include diff --git a/src/libslic3r/ExPolygonsIndex.cpp b/src/libslic3r/ExPolygonsIndex.cpp index 976531799f..296d43a198 100644 --- a/src/libslic3r/ExPolygonsIndex.cpp +++ b/src/libslic3r/ExPolygonsIndex.cpp @@ -1,4 +1,10 @@ #include "ExPolygonsIndex.hpp" +#include "ExPolygon.hpp" +#include +#include +#include +#include +#include using namespace Slic3r; // IMPROVE: use one dimensional vector for polygons offset with searching by std::lower_bound diff --git a/src/libslic3r/ExPolygonsIndex.hpp b/src/libslic3r/ExPolygonsIndex.hpp index b46fd50890..317fb5f731 100644 --- a/src/libslic3r/ExPolygonsIndex.hpp +++ b/src/libslic3r/ExPolygonsIndex.hpp @@ -2,6 +2,8 @@ #define slic3r_ExPolygonsIndex_hpp_ #include "ExPolygon.hpp" +#include +#include namespace Slic3r { /// diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index d271a25052..5297af8ff2 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -1,7 +1,9 @@ #ifndef _libslic3r_Exception_h_ #define _libslic3r_Exception_h_ +#include #include +#include #include namespace Slic3r { diff --git a/src/libslic3r/Execution/Execution.hpp b/src/libslic3r/Execution/Execution.hpp index 62e49cfeb3..9620d9b11d 100644 --- a/src/libslic3r/Execution/Execution.hpp +++ b/src/libslic3r/Execution/Execution.hpp @@ -1,6 +1,7 @@ #ifndef EXECUTION_HPP #define EXECUTION_HPP +#include #include #include #include diff --git a/src/libslic3r/Execution/ExecutionSeq.hpp b/src/libslic3r/Execution/ExecutionSeq.hpp index 321d65631b..56afa6aaf4 100644 --- a/src/libslic3r/Execution/ExecutionSeq.hpp +++ b/src/libslic3r/Execution/ExecutionSeq.hpp @@ -1,6 +1,9 @@ #ifndef EXECUTIONSEQ_HPP #define EXECUTIONSEQ_HPP +#include +#include "libslic3r/libslic3r.h" +#include #ifdef PRUSASLICER_USE_EXECUTION_STD // Conflicts with our version of TBB #include #endif diff --git a/src/libslic3r/Execution/ExecutionTBB.hpp b/src/libslic3r/Execution/ExecutionTBB.hpp index 2250b8e322..4881c7b59c 100644 --- a/src/libslic3r/Execution/ExecutionTBB.hpp +++ b/src/libslic3r/Execution/ExecutionTBB.hpp @@ -1,14 +1,17 @@ #ifndef EXECUTIONTBB_HPP #define EXECUTIONTBB_HPP +#include #include #include #include #include #include +#include #include "Execution.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp index b1b6ca347a..bffdf6771c 100644 --- a/src/libslic3r/Extruder.cpp +++ b/src/libslic3r/Extruder.cpp @@ -1,5 +1,11 @@ #include "Extruder.hpp" +#include "Exception.hpp" #include "PrintConfig.hpp" +#include +#include "libslic3r.h" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index aa023ea040..94e083c86b 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -3,6 +3,7 @@ #include "libslic3r.h" #include "Point.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index bd45150a15..a3590814f7 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -4,10 +4,23 @@ #include "ClipperUtils.hpp" #include "Extruder.hpp" #include "Flow.hpp" +#include +#include #include +#include +#include #include #include +#include "Point.hpp" +#include "Polyline.hpp" +#include "Polygon.hpp" +#include +#include +#include "Line.hpp" +#include +#include #include "Utils.hpp" +#include "libslic3r.h" #define L(s) (s) diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index de80247bce..d7dac99364 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -1,13 +1,19 @@ #ifndef slic3r_ExtrusionEntity_hpp_ #define slic3r_ExtrusionEntity_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include "Polygon.hpp" #include "Polyline.hpp" #include +#include +#include +#include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index 9a37ff3ac1..0141e3d5e8 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -1,7 +1,12 @@ #include "ExtrusionEntityCollection.hpp" +#include "ExtrusionEntity.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "ShortestPath.hpp" #include #include +#include +#include #include namespace Slic3r { diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp index 13727869fe..664ad1ddcd 100644 --- a/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/src/libslic3r/ExtrusionEntityCollection.hpp @@ -1,9 +1,16 @@ #ifndef slic3r_ExtrusionEntityCollection_hpp_ #define slic3r_ExtrusionEntityCollection_hpp_ +#include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" #include "libslic3r.h" #include "Exception.hpp" #include "ExtrusionEntity.hpp" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ExtrusionSimulator.cpp b/src/libslic3r/ExtrusionSimulator.cpp index 4bf54edea9..bb9179a7e2 100644 --- a/src/libslic3r/ExtrusionSimulator.cpp +++ b/src/libslic3r/ExtrusionSimulator.cpp @@ -3,6 +3,9 @@ //#undef SLIC3R_DEBUG //#define NDEBUG +#include +#include +#include #include #include @@ -12,7 +15,14 @@ #include #include +#include +#include +#include +#include +#include "Point.hpp" +#include "BoundingBox.hpp" +#include "ExtrusionEntity.hpp" #include "libslic3r.h" #include "ExtrusionSimulator.hpp" diff --git a/src/libslic3r/ExtrusionSimulator.hpp b/src/libslic3r/ExtrusionSimulator.hpp index 040406766d..33629d79e6 100644 --- a/src/libslic3r/ExtrusionSimulator.hpp +++ b/src/libslic3r/ExtrusionSimulator.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_ExtrusionSimulator_hpp_ #define slic3r_ExtrusionSimulator_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include "ExtrusionEntity.hpp" #include "BoundingBox.hpp" diff --git a/src/libslic3r/FaceDetector.cpp b/src/libslic3r/FaceDetector.cpp index 5eb5ca762c..a631822d9e 100644 --- a/src/libslic3r/FaceDetector.cpp +++ b/src/libslic3r/FaceDetector.cpp @@ -1,8 +1,13 @@ #include "FaceDetector.hpp" +#include "BoundingBox.hpp" #include "TriangleMesh.hpp" #include "SLA/IndexedMesh.hpp" #include "Model.hpp" +#include +#include #include +#include +#include namespace Slic3r { static const double BBOX_OFFSET = 2.0; diff --git a/src/libslic3r/FaceDetector.hpp b/src/libslic3r/FaceDetector.hpp index b4d9d78985..190877ecec 100644 --- a/src/libslic3r/FaceDetector.hpp +++ b/src/libslic3r/FaceDetector.hpp @@ -2,6 +2,7 @@ #define slic3r_FaceDetector_hpp_ #include "Point.hpp" +#include namespace Slic3r { class ModelObject; diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp index be86e92245..c580cc3c0f 100644 --- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp +++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.cpp @@ -1,5 +1,19 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Surface.hpp" #include "libslic3r/Algorithm/LineSplit.hpp" #include "libslic3r/Arachne/utils/ExtrusionJunction.hpp" #include "libslic3r/Arachne/utils/ExtrusionLine.hpp" diff --git a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.hpp b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.hpp index ab0c491b38..ec5069a49c 100644 --- a/src/libslic3r/Feature/FuzzySkin/FuzzySkin.hpp +++ b/src/libslic3r/Feature/FuzzySkin/FuzzySkin.hpp @@ -1,9 +1,13 @@ #ifndef libslic3r_FuzzySkin_hpp_ #define libslic3r_FuzzySkin_hpp_ +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" #include "libslic3r/Arachne/utils/ExtrusionJunction.hpp" #include "libslic3r/Arachne/utils/ExtrusionLine.hpp" #include "libslic3r/PerimeterGenerator.hpp" +#include namespace Slic3r::Feature::FuzzySkin { diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp index 726ee2ffd8..9e2fb7fa47 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.cpp @@ -2,8 +2,22 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "InterlockingGenerator.hpp" +#include "libslic3r/Feature/Interlocking/VoxelUtils.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/ExPolygon.hpp" #include "libslic3r/ClipperUtils.hpp" #include "Layer.hpp" +#include +#include +#include +#include +#include +#include namespace std { template<> struct hash diff --git a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp index e6b79f9bc8..b06c8a10c8 100644 --- a/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp +++ b/src/libslic3r/Feature/Interlocking/InterlockingGenerator.hpp @@ -4,8 +4,16 @@ #ifndef INTERLOCKING_GENERATOR_HPP #define INTERLOCKING_GENERATOR_HPP +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include "libslic3r/ExPolygon.hpp" #include "libslic3r/Print.hpp" #include "VoxelUtils.hpp" +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Feature/Interlocking/VoxelUtils.cpp b/src/libslic3r/Feature/Interlocking/VoxelUtils.cpp index 303473ae48..6e33ddaca7 100644 --- a/src/libslic3r/Feature/Interlocking/VoxelUtils.cpp +++ b/src/libslic3r/Feature/Interlocking/VoxelUtils.cpp @@ -2,9 +2,21 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "VoxelUtils.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Polyline.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/Fill/FillRectilinear.hpp" #include "libslic3r/Surface.hpp" +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Feature/Interlocking/VoxelUtils.hpp b/src/libslic3r/Feature/Interlocking/VoxelUtils.hpp index 0348b69598..dc571c06ea 100644 --- a/src/libslic3r/Feature/Interlocking/VoxelUtils.hpp +++ b/src/libslic3r/Feature/Interlocking/VoxelUtils.hpp @@ -4,8 +4,13 @@ #ifndef UTILS_VOXEL_UTILS_H #define UTILS_VOXEL_UTILS_H +#include +#include #include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Polygon.hpp" #include "libslic3r/ExPolygon.hpp" diff --git a/src/libslic3r/FilamentGroup.cpp b/src/libslic3r/FilamentGroup.cpp index 07a4cc2449..5536a13282 100644 --- a/src/libslic3r/FilamentGroup.cpp +++ b/src/libslic3r/FilamentGroup.cpp @@ -1,11 +1,34 @@ #include "FilamentGroup.hpp" +#include "FilamentGroupUtils.hpp" #include "GCode/ToolOrderUtils.hpp" #include "FlushVolPredictor.hpp" +#include "MultiNozzleUtils.hpp" +#include "PrintConfig.hpp" +#include "libslic3r.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/FilamentGroup.hpp b/src/libslic3r/FilamentGroup.hpp index 9172685bee..b090a22fe0 100644 --- a/src/libslic3r/FilamentGroup.hpp +++ b/src/libslic3r/FilamentGroup.hpp @@ -2,14 +2,21 @@ #define FILAMENT_GROUP_HPP #include +#include #include #include +#include #include #include +#include +#include +#include #include #include #include "GCode/ToolOrderUtils.hpp" #include "FilamentGroupUtils.hpp" +#include "PrintConfig.hpp" +#include "MultiNozzleUtils.hpp" const static int DEFAULT_CLUSTER_SIZE = 16; diff --git a/src/libslic3r/FilamentGroupUtils.cpp b/src/libslic3r/FilamentGroupUtils.cpp index c0cd747025..7402341806 100644 --- a/src/libslic3r/FilamentGroupUtils.cpp +++ b/src/libslic3r/FilamentGroupUtils.cpp @@ -1,6 +1,22 @@ #include "FilamentGroupUtils.hpp" +#include +#include +#include +#include +#include +#include "PrintConfig.hpp" +#include "Config.hpp" +#include +#include +#include "libslic3r.h" +#include "MultiNozzleUtils.hpp" #include +#include #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/FilamentGroupUtils.hpp b/src/libslic3r/FilamentGroupUtils.hpp index f0865a93c6..a73a562e90 100644 --- a/src/libslic3r/FilamentGroupUtils.hpp +++ b/src/libslic3r/FilamentGroupUtils.hpp @@ -1,6 +1,9 @@ #ifndef FILAMENT_GROUP_UTILS_HPP #define FILAMENT_GROUP_UTILS_HPP +#include +#include +#include #include #include #include diff --git a/src/libslic3r/FilamentMixer.cpp b/src/libslic3r/FilamentMixer.cpp index 66640498e6..51952c94c9 100644 --- a/src/libslic3r/FilamentMixer.cpp +++ b/src/libslic3r/FilamentMixer.cpp @@ -5,12 +5,17 @@ #include #include #include +#include #include +#include #include #include #include #include +#include +#include +#include #include "ColorDecomposeRecipe.hpp" #include "FilamentMixerModel.hpp" diff --git a/src/libslic3r/FilamentMixer.hpp b/src/libslic3r/FilamentMixer.hpp index 81ddd29e46..5ea4484437 100644 --- a/src/libslic3r/FilamentMixer.hpp +++ b/src/libslic3r/FilamentMixer.hpp @@ -1,6 +1,7 @@ #ifndef SLIC3R_FILAMENT_MIXER_HPP #define SLIC3R_FILAMENT_MIXER_HPP +#include #include #include #include diff --git a/src/libslic3r/FileParserError.hpp b/src/libslic3r/FileParserError.hpp index b7e63d84e0..4777ee8a79 100644 --- a/src/libslic3r/FileParserError.hpp +++ b/src/libslic3r/FileParserError.hpp @@ -1,8 +1,10 @@ #ifndef slic3r_FileParserError_hpp_ #define slic3r_FileParserError_hpp_ +#include "Exception.hpp" #include "libslic3r.h" +#include #include #include #include diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index a09c69fc5e..505081ab79 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -1,6 +1,19 @@ +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include #include "../ClipperUtils.hpp" #include "../Geometry.hpp" @@ -10,14 +23,23 @@ #include "../Surface.hpp" #include "AABBTreeLines.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/BoundingBox.hpp" #include "ExtrusionEntity.hpp" #include "Fill.hpp" +#include "libslic3r/Fill/FillBase.hpp" #include "FillRectilinear.hpp" #include "FillLightning.hpp" #include "FillConcentricInternal.hpp" #include "FillTpmsD.hpp" #include "FillTpmsFK.hpp" #include "FillConcentric.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Polyline.hpp" #include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/Fill/Fill.hpp b/src/libslic3r/Fill/Fill.hpp index b183cf0253..138321fd0a 100644 --- a/src/libslic3r/Fill/Fill.hpp +++ b/src/libslic3r/Fill/Fill.hpp @@ -1,9 +1,11 @@ #ifndef slic3r_Fill_hpp_ #define slic3r_Fill_hpp_ +#include #include #include #include +#include #include "../libslic3r.h" #include "../PrintConfig.hpp" diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/src/libslic3r/Fill/Fill3DHoneycomb.cpp index ad5f8918fd..5a390fa517 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -1,8 +1,20 @@ #include "../ClipperUtils.hpp" #include "../ShortestPath.hpp" #include "../Surface.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/BoundingBox.hpp" #include "FillBase.hpp" #include "FillCornerSmoothing.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include +#include "libslic3r/Polyline.hpp" +#include #include "Fill3DHoneycomb.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/Fill3DHoneycomb.hpp b/src/libslic3r/Fill/Fill3DHoneycomb.hpp index 2d6664ddf4..2ad6f79a7c 100644 --- a/src/libslic3r/Fill/Fill3DHoneycomb.hpp +++ b/src/libslic3r/Fill/Fill3DHoneycomb.hpp @@ -2,10 +2,14 @@ #define slic3r_Fill3DHoneycomb_hpp_ #include +#include #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp index 809eddb218..927e2c86a3 100644 --- a/src/libslic3r/Fill/FillAdaptive.cpp +++ b/src/libslic3r/Fill/FillAdaptive.cpp @@ -6,18 +6,40 @@ #include "../Layer.hpp" #include "../Print.hpp" #include "../ShortestPath.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Fill/FillBase.hpp" #include "FillAdaptive.hpp" // for indexed_triangle_set +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include #include +#include #include +#include +#include // Boost pool: Don't use mutexes to synchronize memory allocation. #define BOOST_POOL_NO_MT diff --git a/src/libslic3r/Fill/FillAdaptive.hpp b/src/libslic3r/Fill/FillAdaptive.hpp index de0768b26e..9b424133a2 100644 --- a/src/libslic3r/Fill/FillAdaptive.hpp +++ b/src/libslic3r/Fill/FillAdaptive.hpp @@ -11,7 +11,17 @@ #ifndef slic3r_FillAdaptive_hpp_ #define slic3r_FillAdaptive_hpp_ +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Line.hpp" struct indexed_triangle_set; diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index f4615dc640..91a3bb42af 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -1,9 +1,17 @@ +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include #include "../ClipperUtils.hpp" -#include "../Clipper2Utils.hpp" #include "../EdgeGrid.hpp" #include "../Geometry.hpp" #include "../Geometry/Circle.hpp" @@ -14,6 +22,12 @@ #include "../VariableWidth.hpp" #include "FillBase.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" +#include "libslic3r/BoundingBox.hpp" #include "FillConcentric.hpp" #include "FillSpiralInset.hpp" #include "FillHoneycomb.hpp" @@ -29,6 +43,11 @@ // BBS: new infill pattern header #include "FillConcentricInternal.hpp" #include "FillCrossHatch.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/ShortestPath.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Utils.hpp" // #define INFILL_DEBUG_OUTPUT namespace Slic3r { @@ -2734,11 +2753,8 @@ void multiline_fill(Polylines& polylines, const FillParams& params, float spacin if (polylines.empty()) return; - // Convert source polylines to Clipper2 paths - Clipper2Lib::Paths64 subject_paths = Slic3rPolylines_to_Paths64(polylines); - const double miter_limit = 2.0; - const int rings = n_lines / 2; + const int rings = n_lines / 2; // Compute offsets (in units of spacing) std::vector offsets; @@ -2757,10 +2773,6 @@ void multiline_fill(Polylines& polylines, const FillParams& params, float spacin offsets.push_back(start + i * spacing); } - // Process each offset - Clipper2Lib::ClipperOffset offsetter(miter_limit); - offsetter.AddPaths(subject_paths, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Round); - for (double t : offsets) { if (t == 0.0) { // Center line (only applies when n_lines is odd) @@ -2768,22 +2780,11 @@ void multiline_fill(Polylines& polylines, const FillParams& params, float spacin continue; } - // ClipperOffset with current offset distance (union is not needed here) - Clipper2Lib::Paths64 offset_paths; - offsetter.Execute(scale_(t), offset_paths); - if (offset_paths.empty()) - continue; - - // Convert back to polylines - Polylines new_polylines = Paths64_to_polylines(offset_paths); - - for (Polyline& pl : new_polylines) { - if (pl.points.size() < 3) - continue; - if (pl.points.front() != pl.points.back()) - pl.points.push_back(pl.points.front()); - all_polylines.emplace_back(std::move(pl)); - } + const float delta = float(scale_(t)); + // Arc tolerance of 1/500 of the offset, Clipper2's default. + for (const Polygon &ring : offset(polylines, delta, jtRound, 0.002 * delta, etOpenRound)) + if (ring.size() >= 3) + all_polylines.emplace_back(ring.split_at_first_point()); } polylines = std::move(all_polylines); diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index d50c29b332..0ccce102ad 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -2,12 +2,18 @@ #define slic3r_FillBase_hpp_ #include +#include +#include +#include #include #include #include #include +#include #include +#include +#include #include "../libslic3r.h" #include "../BoundingBox.hpp" @@ -20,6 +26,8 @@ #include "../ExtrusionEntity.hpp" #include "../ExtrusionEntityCollection.hpp" #include "../ShortestPath.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Polygon.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 044fee042e..6a70200b34 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -5,8 +5,21 @@ #include "Arachne/WallToolPaths.hpp" #include "FillConcentric.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Arachne/utils/ExtrusionLine.hpp" #include "FillCornerSmoothing.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include +#include "libslic3r/PrintConfig.hpp" +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Fill/FillConcentric.hpp b/src/libslic3r/Fill/FillConcentric.hpp index 56040d848d..43273131db 100644 --- a/src/libslic3r/Fill/FillConcentric.hpp +++ b/src/libslic3r/Fill/FillConcentric.hpp @@ -1,7 +1,11 @@ #ifndef slic3r_FillConcentric_hpp_ #define slic3r_FillConcentric_hpp_ +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillConcentricInternal.cpp b/src/libslic3r/Fill/FillConcentricInternal.cpp index d565992ea1..49b21935f3 100644 --- a/src/libslic3r/Fill/FillConcentricInternal.cpp +++ b/src/libslic3r/Fill/FillConcentricInternal.cpp @@ -3,9 +3,22 @@ #include "../Surface.hpp" #include "../VariableWidth.hpp" #include "Arachne/WallToolPaths.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Arachne/utils/ExtrusionLine.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" #include "FillConcentricInternal.hpp" +#include +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Fill/FillConcentricInternal.hpp b/src/libslic3r/Fill/FillConcentricInternal.hpp index 2c93eb5ee9..f78e9e1cb1 100644 --- a/src/libslic3r/Fill/FillConcentricInternal.hpp +++ b/src/libslic3r/Fill/FillConcentricInternal.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_FillConcentricInternal_hpp_ #define slic3r_FillConcentricInternal_hpp_ +#include "libslic3r/ExtrusionEntity.hpp" #include "FillBase.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillCornerSmoothing.cpp b/src/libslic3r/Fill/FillCornerSmoothing.cpp index dbce39d572..f87de98293 100644 --- a/src/libslic3r/Fill/FillCornerSmoothing.cpp +++ b/src/libslic3r/Fill/FillCornerSmoothing.cpp @@ -1,6 +1,16 @@ +#include #include +#include +#include +#include +#include +#include #include "FillCornerSmoothing.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Polygon.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillCornerSmoothing.hpp b/src/libslic3r/Fill/FillCornerSmoothing.hpp index 7f2ead229a..b59cf26237 100644 --- a/src/libslic3r/Fill/FillCornerSmoothing.hpp +++ b/src/libslic3r/Fill/FillCornerSmoothing.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "../libslic3r.h" diff --git a/src/libslic3r/Fill/FillCrossHatch.cpp b/src/libslic3r/Fill/FillCrossHatch.cpp index 98be5ef46b..c70a8a5320 100644 --- a/src/libslic3r/Fill/FillCrossHatch.cpp +++ b/src/libslic3r/Fill/FillCrossHatch.cpp @@ -1,9 +1,17 @@ #include "../ClipperUtils.hpp" #include "../ShortestPath.hpp" #include "../Surface.hpp" +#include #include +#include +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/BoundingBox.hpp" #include "FillBase.hpp" #include "FillCornerSmoothing.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" #include "FillCrossHatch.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillCrossHatch.hpp b/src/libslic3r/Fill/FillCrossHatch.hpp index 34c46116eb..0fdc16644a 100644 --- a/src/libslic3r/Fill/FillCrossHatch.hpp +++ b/src/libslic3r/Fill/FillCrossHatch.hpp @@ -2,10 +2,14 @@ #define slic3r_FillCrossHatch_hpp_ #include +#include #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp index c9a108573d..de748d4893 100644 --- a/src/libslic3r/Fill/FillGyroid.cpp +++ b/src/libslic3r/Fill/FillGyroid.cpp @@ -4,9 +4,19 @@ #include "../Surface.hpp" #include #include +#include #include #include +#include "libslic3r/BoundingBox.hpp" +#include +#include "libslic3r/Execution/ExecutionTBB.hpp" +#include +#include +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" #include "FillGyroid.hpp" // --------------------------------------------------------------------------- diff --git a/src/libslic3r/Fill/FillGyroid.hpp b/src/libslic3r/Fill/FillGyroid.hpp index 751a7c2570..2599662403 100644 --- a/src/libslic3r/Fill/FillGyroid.hpp +++ b/src/libslic3r/Fill/FillGyroid.hpp @@ -3,7 +3,11 @@ #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillHoneycomb.cpp b/src/libslic3r/Fill/FillHoneycomb.cpp index 82679541da..594ff3fbba 100644 --- a/src/libslic3r/Fill/FillHoneycomb.cpp +++ b/src/libslic3r/Fill/FillHoneycomb.cpp @@ -2,7 +2,17 @@ #include "../ShortestPath.hpp" #include "../Surface.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/BoundingBox.hpp" #include "FillCornerSmoothing.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include #include "FillHoneycomb.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillHoneycomb.hpp b/src/libslic3r/Fill/FillHoneycomb.hpp index 55be423854..fd1fe039de 100644 --- a/src/libslic3r/Fill/FillHoneycomb.hpp +++ b/src/libslic3r/Fill/FillHoneycomb.hpp @@ -1,11 +1,17 @@ #ifndef slic3r_FillHoneycomb_hpp_ #define slic3r_FillHoneycomb_hpp_ +#include #include +#include +#include #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillLightning.cpp b/src/libslic3r/Fill/FillLightning.cpp index 77031b42e0..9f6200a88e 100644 --- a/src/libslic3r/Fill/FillLightning.cpp +++ b/src/libslic3r/Fill/FillLightning.cpp @@ -1,10 +1,18 @@ #include "../ClipperUtils.hpp" #include "../Print.hpp" #include "../ShortestPath.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Fill/Lightning/Layer.hpp" #include "FillBase.hpp" #include "FillCornerSmoothing.hpp" #include "FillLightning.hpp" #include "Lightning/Generator.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" +#include +#include namespace Slic3r::FillLightning { diff --git a/src/libslic3r/Fill/FillLightning.hpp b/src/libslic3r/Fill/FillLightning.hpp index 74aa159b0b..8ad15b5c2a 100644 --- a/src/libslic3r/Fill/FillLightning.hpp +++ b/src/libslic3r/Fill/FillLightning.hpp @@ -1,7 +1,13 @@ #ifndef slic3r_FillLightning_hpp_ #define slic3r_FillLightning_hpp_ +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillLine.cpp b/src/libslic3r/Fill/FillLine.cpp index 5d548e5dbb..f46c102131 100644 --- a/src/libslic3r/Fill/FillLine.cpp +++ b/src/libslic3r/Fill/FillLine.cpp @@ -2,6 +2,17 @@ #include "../ExPolygon.hpp" #include "../ShortestPath.hpp" #include "../Surface.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Line.hpp" +#include +#include +#include #include "FillLine.hpp" diff --git a/src/libslic3r/Fill/FillLine.hpp b/src/libslic3r/Fill/FillLine.hpp index 4ad9ca49a4..73633716dc 100644 --- a/src/libslic3r/Fill/FillLine.hpp +++ b/src/libslic3r/Fill/FillLine.hpp @@ -3,7 +3,12 @@ #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Line.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index 577aef0600..2ee2b1ef3a 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -2,7 +2,21 @@ #include "../ShortestPath.hpp" #include "../Surface.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/ExtrusionEntity.hpp" #include "FillCornerSmoothing.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Polyline.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include #include "FillPlanePath.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index a1e9068ca9..d24d9df9f4 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -1,11 +1,17 @@ #ifndef slic3r_FillPlanePath_hpp_ #define slic3r_FillPlanePath_hpp_ +#include +#include #include +#include #include "../libslic3r.h" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 998cfd9a7e..5951e154e9 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -1,3 +1,8 @@ +#include +#include +#include +#include +#include #include #include @@ -10,6 +15,9 @@ #include #include #include +#include +#include +#include #include "../ClipperUtils.hpp" #include "../ExPolygon.hpp" @@ -18,7 +26,17 @@ #include "../ShortestPath.hpp" #include "../VariableWidth.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" #include "FillCornerSmoothing.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Flow.hpp" #include "FillRectilinear.hpp" // #define SLIC3R_DEBUG @@ -417,9 +435,9 @@ public: // bool sticks_removed = remove_sticks(polygons_src); // if (sticks_removed) BOOST_LOG_TRIVIAL(error) << "Sticks removed!"; - polygons_outer = aoffset1 == 0 ? to_polygons(polygons_src) : offset(polygons_src, float(aoffset1), ClipperLib::jtMiter, miterLimit); + polygons_outer = aoffset1 == 0 ? to_polygons(polygons_src) : offset(polygons_src, float(aoffset1), jtMiter, miterLimit); if (aoffset2 < 0) - polygons_inner = shrink(polygons_outer, float(aoffset1 - aoffset2), ClipperLib::jtMiter, miterLimit); + polygons_inner = shrink(polygons_outer, float(aoffset1 - aoffset2), jtMiter, miterLimit); // Filter out contours with zero area or small area, contours with 2 points only. const double min_area_threshold = 0.01 * aoffset2 * aoffset2; remove_small(polygons_outer, min_area_threshold); diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index adb9ef5131..a4453ad2d0 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -3,7 +3,18 @@ #include "../libslic3r.h" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include "libslic3r/Polyline.hpp" +#include +#include +#include +#include +#include "libslic3r/Flow.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillSpiralInset.cpp b/src/libslic3r/Fill/FillSpiralInset.cpp index e6323c2572..8f663df340 100644 --- a/src/libslic3r/Fill/FillSpiralInset.cpp +++ b/src/libslic3r/Fill/FillSpiralInset.cpp @@ -3,12 +3,25 @@ #include "../Surface.hpp" #include "../VariableWidth.hpp" #include "Arachne/WallToolPaths.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Arachne/utils/ExtrusionLine.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/BoundingBox.hpp" #include "FillSpiralInset.hpp" #include +#include #include +#include #include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Fill/FillSpiralInset.hpp b/src/libslic3r/Fill/FillSpiralInset.hpp index eb799ec2f3..8b95657b4b 100644 --- a/src/libslic3r/Fill/FillSpiralInset.hpp +++ b/src/libslic3r/Fill/FillSpiralInset.hpp @@ -1,7 +1,11 @@ #ifndef slic3r_FillSpiralInset_hpp_ #define slic3r_FillSpiralInset_hpp_ +#include "libslic3r/ExPolygon.hpp" #include "FillBase.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Fill/FillTpmsD.cpp b/src/libslic3r/Fill/FillTpmsD.cpp index 06e0302e8d..bb1a338691 100644 --- a/src/libslic3r/Fill/FillTpmsD.cpp +++ b/src/libslic3r/Fill/FillTpmsD.cpp @@ -1,10 +1,15 @@ #include #include +#include +#include +#include #include //#include #include "../ClipperUtils.hpp" #include "../ShortestPath.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/ExPolygon.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/Fill/FillBase.hpp" #include "libslic3r/Point.hpp" diff --git a/src/libslic3r/Fill/FillTpmsFK.cpp b/src/libslic3r/Fill/FillTpmsFK.cpp index 66ed1cbc84..a48a63f3d0 100644 --- a/src/libslic3r/Fill/FillTpmsFK.cpp +++ b/src/libslic3r/Fill/FillTpmsFK.cpp @@ -1,8 +1,17 @@ #include "../ClipperUtils.hpp" #include "../MarchingSquares.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Execution/ExecutionTBB.hpp" +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/ExPolygon.hpp" #include "FillTpmsFK.hpp" #include #include +#include +#include #include #include #include diff --git a/src/libslic3r/Fill/Lightning/DistanceField.cpp b/src/libslic3r/Fill/Lightning/DistanceField.cpp index 65da94b839..73d74cef03 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.cpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.cpp @@ -4,8 +4,22 @@ #include "DistanceField.hpp" //Class we're implementing. #include "../FillRectilinear.hpp" #include "../../ClipperUtils.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include +#include +#include +#include +#include +#include +#include #include +#include #ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT #include "../../SVG.hpp" diff --git a/src/libslic3r/Fill/Lightning/DistanceField.hpp b/src/libslic3r/Fill/Lightning/DistanceField.hpp index 007ac235e5..737c432824 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.hpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.hpp @@ -7,6 +7,13 @@ #include "../../BoundingBox.hpp" #include "../../Point.hpp" #include "../../Polygon.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include //#define LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index c638610aa5..c35eb3250f 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -2,6 +2,15 @@ //CuraEngine is released under the terms of the AGPLv3 or higher. #include "Generator.hpp" +#include "libslic3r/SVG.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/Fill/Lightning/Layer.hpp" +#include "libslic3r/EdgeGrid.hpp" #include "TreeNode.hpp" #include "../../ClipperUtils.hpp" @@ -9,6 +18,18 @@ #include "../../Print.hpp" #include "ExPolygon.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include /* Possible future tasks/optimizations,etc.: * - Improve connecting heuristic to favor connecting to shorter trees diff --git a/src/libslic3r/Fill/Lightning/Generator.hpp b/src/libslic3r/Fill/Lightning/Generator.hpp index 79110fb8dd..18be848b9e 100644 --- a/src/libslic3r/Fill/Lightning/Generator.hpp +++ b/src/libslic3r/Fill/Lightning/Generator.hpp @@ -4,8 +4,12 @@ #ifndef LIGHTNING_GENERATOR_H #define LIGHTNING_GENERATOR_H +#include "libslic3r/BoundingBox.hpp" #include "Layer.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/libslic3r.h" +#include #include #include #include diff --git a/src/libslic3r/Fill/Lightning/Layer.cpp b/src/libslic3r/Fill/Lightning/Layer.cpp index 4a30a95f45..f461888a14 100644 --- a/src/libslic3r/Fill/Lightning/Layer.cpp +++ b/src/libslic3r/Fill/Lightning/Layer.cpp @@ -3,16 +3,31 @@ #include "Layer.hpp" //The class we're implementing. +#include "libslic3r/BoundingBox.hpp" #include "DistanceField.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/EdgeGrid.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Polyline.hpp" #include "TreeNode.hpp" #include "../../ClipperUtils.hpp" #include "../../Geometry.hpp" #include "Utils.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include namespace Slic3r::FillLightning { diff --git a/src/libslic3r/Fill/Lightning/Layer.hpp b/src/libslic3r/Fill/Lightning/Layer.hpp index e8c0a38b4d..378dc354b2 100644 --- a/src/libslic3r/Fill/Lightning/Layer.hpp +++ b/src/libslic3r/Fill/Lightning/Layer.hpp @@ -6,7 +6,12 @@ #include "../../EdgeGrid.hpp" #include "../../Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polyline.hpp" +#include #include #include #include diff --git a/src/libslic3r/Fill/Lightning/TreeNode.cpp b/src/libslic3r/Fill/Lightning/TreeNode.cpp index 3d57ebae4a..9a08242392 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.cpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.cpp @@ -4,6 +4,22 @@ #include "TreeNode.hpp" #include "../../Geometry.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include +#include +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/EdgeGrid.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/Line.hpp" +#include "libslic3r/Polyline.hpp" +#include +#include namespace Slic3r::FillLightning { @@ -143,14 +159,7 @@ NodeSPtr Node::closestNode(const Point& loc) bool inside(const Polygons &polygons, const Point &p) { - int poly_count_inside = 0; - for (const Polygon &poly : polygons) { - const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly.points); - if (is_inside_this_poly == -1) - return true; - poly_count_inside += is_inside_this_poly; - } - return (poly_count_inside % 2) == 1; + return contains(polygons, p, true); } bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeGrid::Grid& outline_locator, Point& result, const coord_t within_max_dist) diff --git a/src/libslic3r/Fill/Lightning/TreeNode.hpp b/src/libslic3r/Fill/Lightning/TreeNode.hpp index 95559524ba..c82ca3f2b6 100644 --- a/src/libslic3r/Fill/Lightning/TreeNode.hpp +++ b/src/libslic3r/Fill/Lightning/TreeNode.hpp @@ -4,6 +4,8 @@ #ifndef LIGHTNING_TREE_NODE_H #define LIGHTNING_TREE_NODE_H +#include +#include #include #include #include @@ -12,7 +14,11 @@ #include "../../EdgeGrid.hpp" #include "../../Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/BoundingBox.hpp" #include "SVG.hpp" +#include "libslic3r/libslic3r.h" //#define LIGHTNING_TREE_NODE_DEBUG_OUTPUT diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 80912362ce..13ee73973e 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -1,10 +1,15 @@ #include "Flow.hpp" +#include "Exception.hpp" +#include "Config.hpp" #include "I18N.hpp" #include "Print.hpp" +#include "libslic3r.h" #include #include #include +#include +#include // Mark string for localization and translate. #define L(s) Slic3r::I18N::translate(s) diff --git a/src/libslic3r/Flow.hpp b/src/libslic3r/Flow.hpp index 79cb1b324d..14d20a41c7 100644 --- a/src/libslic3r/Flow.hpp +++ b/src/libslic3r/Flow.hpp @@ -5,6 +5,8 @@ #include "Config.hpp" #include "Exception.hpp" #include "ExtrusionEntity.hpp" +#include +#include namespace Slic3r { diff --git a/src/libslic3r/FlushVolCalc.cpp b/src/libslic3r/FlushVolCalc.cpp index 635328f5ab..daeaf587c6 100644 --- a/src/libslic3r/FlushVolCalc.cpp +++ b/src/libslic3r/FlushVolCalc.cpp @@ -1,5 +1,8 @@ +#include #include #include +#include +#include "FlushVolPredictor.hpp" #include "slic3r/Utils/ColorSpaceConvert.hpp" #include "Utils.hpp" #include "FlushVolCalc.hpp" diff --git a/src/libslic3r/FlushVolPredictor.cpp b/src/libslic3r/FlushVolPredictor.cpp index dc39284b5f..e18b726c1f 100644 --- a/src/libslic3r/FlushVolPredictor.cpp +++ b/src/libslic3r/FlushVolPredictor.cpp @@ -1,9 +1,19 @@ #include "FlushVolPredictor.hpp" #include "Utils.hpp" +#include +#include +#include #include +#include +#include +#include #include #include #include +#include +#include +#include +#include namespace FlushPredict { diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 738f1f5f6f..2f457f634d 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -10,10 +10,37 @@ #include "../Time.hpp" #include "../I18N.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/SLA/Hollowing.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r_version.h" +#include "libslic3r/PrintConfig.hpp" #include "3mf.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include #include @@ -28,6 +55,9 @@ #include #include #include +#include +#include +#include namespace pt = boost::property_tree; #include diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp index c46b4e5533..ec59aff307 100644 --- a/src/libslic3r/Format/3mf.hpp +++ b/src/libslic3r/Format/3mf.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_Format_3mf_hpp_ #define slic3r_Format_3mf_hpp_ #include +#include namespace Slic3r { // PrusaFileParser is used to check 3mf file is from Prusa diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index c5c9904e87..abf6953855 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -1,4 +1,10 @@ +#include +#include +#include +#include +#include #include +#include #include #include #include @@ -16,11 +22,16 @@ #include "../Geometry.hpp" #include "../CustomGCode.hpp" #include "../LocalesUtils.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "AMF.hpp" #include #include +#include +#include namespace pt = boost::property_tree; #include diff --git a/src/libslic3r/Format/AMF.hpp b/src/libslic3r/Format/AMF.hpp index e48e424748..335d47d6fb 100644 --- a/src/libslic3r/Format/AMF.hpp +++ b/src/libslic3r/Format/AMF.hpp @@ -5,6 +5,7 @@ namespace Slic3r { class Model; class DynamicPrintConfig; +struct ConfigSubstitutionContext; // Load the content of an amf file into the given model and configuration. extern bool load_amf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, bool* use_inches); diff --git a/src/libslic3r/Format/AssimpImport.cpp b/src/libslic3r/Format/AssimpImport.cpp index f0ae99506a..0ab728f305 100644 --- a/src/libslic3r/Format/AssimpImport.cpp +++ b/src/libslic3r/Format/AssimpImport.cpp @@ -4,21 +4,30 @@ #include "ResourcePathUtils.hpp" #include +#include #include #include +#include #include #include +#include +#include +#include #include #include +#include #include #include #include +#include #include +#include #include #include #include +#include #include namespace Slic3r { diff --git a/src/libslic3r/Format/DRC.cpp b/src/libslic3r/Format/DRC.cpp index c07655f69b..1cf9c13565 100644 --- a/src/libslic3r/Format/DRC.cpp +++ b/src/libslic3r/Format/DRC.cpp @@ -1,3 +1,15 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -9,6 +21,7 @@ #include #include #include +#include using namespace draco; #include "libslic3r/Model.hpp" diff --git a/src/libslic3r/Format/OBJ.cpp b/src/libslic3r/Format/OBJ.cpp index 8242f2c0c9..db24ebec0b 100644 --- a/src/libslic3r/Format/OBJ.cpp +++ b/src/libslic3r/Format/OBJ.cpp @@ -2,15 +2,27 @@ #include "../Model.hpp" #include "../TriangleMesh.hpp" #include "../TexturePainting.hpp" +#include "libslic3r/Color.hpp" +#include "libslic3r/Point.hpp" #include "ResourcePathUtils.hpp" #include "OBJ.hpp" #include "objparser.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #ifdef _WIN32 #define DIR_SEPARATOR '\\' diff --git a/src/libslic3r/Format/OBJ.hpp b/src/libslic3r/Format/OBJ.hpp index c103326af6..0767ddd87d 100644 --- a/src/libslic3r/Format/OBJ.hpp +++ b/src/libslic3r/Format/OBJ.hpp @@ -2,7 +2,14 @@ #define slic3r_Format_OBJ_hpp_ #include "libslic3r/Color.hpp" #include "objparser.hpp" +#include "libslic3r/Point.hpp" +#include +#include +#include +#include +#include #include +#include namespace Slic3r { class TriangleMesh; diff --git a/src/libslic3r/Format/ResourcePathUtils.hpp b/src/libslic3r/Format/ResourcePathUtils.hpp index d82b92bd45..eccfcba84f 100644 --- a/src/libslic3r/Format/ResourcePathUtils.hpp +++ b/src/libslic3r/Format/ResourcePathUtils.hpp @@ -2,6 +2,9 @@ #define slic3r_Format_ResourcePathUtils_hpp_ #include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 5796c108e5..15589e79b4 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -1,13 +1,34 @@ #include "SL1.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Config.hpp" #include "GCode/ThumbnailData.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Utils.hpp" #include "libslic3r/Time.hpp" +#include +#include +#include +#include #include #include #include "libslic3r/Zipper.hpp" #include "libslic3r/SLAPrint.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "libslic3r/Exception.hpp" @@ -20,10 +41,15 @@ #include "libslic3r/miniz_extension.hpp" #include "libslic3r/PNGReadWrite.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "libslic3r_version.h" #include #include #include +#include +#include +#include +#include namespace marchsq { diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index 6fb4405c90..ad6b51f7d9 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -1,8 +1,17 @@ #ifndef ARCHIVETRAITS_HPP #define ARCHIVETRAITS_HPP +#include +#include +#include #include +#include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Exception.hpp" #include "libslic3r/Zipper.hpp" #include "libslic3r/SLAPrint.hpp" diff --git a/src/libslic3r/Format/STEP.cpp b/src/libslic3r/Format/STEP.cpp index 8305174e73..611648bc5a 100644 --- a/src/libslic3r/Format/STEP.cpp +++ b/src/libslic3r/Format/STEP.cpp @@ -1,10 +1,30 @@ #include "../libslic3r.h" #include "../Model.hpp" #include "../TriangleMesh.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Point.hpp" #include "libslic3r/Thread.hpp" #include "STEP.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -12,6 +32,8 @@ #include #include +#include +#include #ifdef _WIN32 #define DIR_SEPARATOR '\\' diff --git a/src/libslic3r/Format/STEP.hpp b/src/libslic3r/Format/STEP.hpp index 336fd79766..5563a690c8 100644 --- a/src/libslic3r/Format/STEP.hpp +++ b/src/libslic3r/Format/STEP.hpp @@ -3,16 +3,26 @@ #include "XCAFDoc_DocumentTool.hxx" #include "XCAFApp_Application.hxx" #include "XCAFDoc_ShapeTool.hxx" +#include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include namespace fs = boost::filesystem; namespace Slic3r { class TriangleMesh; +class Model; class ModelObject; // load step stage diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp index 1888f5cd18..55489af976 100644 --- a/src/libslic3r/Format/STL.cpp +++ b/src/libslic3r/Format/STL.cpp @@ -4,7 +4,9 @@ #include "STL.hpp" +#include #include +#include #ifdef _WIN32 #define DIR_SEPARATOR '\\' diff --git a/src/libslic3r/Format/ZipperArchiveImport.cpp b/src/libslic3r/Format/ZipperArchiveImport.cpp index 657e420bbc..3f690e42da 100644 --- a/src/libslic3r/Format/ZipperArchiveImport.cpp +++ b/src/libslic3r/Format/ZipperArchiveImport.cpp @@ -1,12 +1,25 @@ #include "ZipperArchiveImport.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/LocalesUtils.hpp" #include "libslic3r/miniz_extension.hpp" #include "libslic3r/Exception.hpp" #include "libslic3r/PrintConfig.hpp" +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Format/ZipperArchiveImport.hpp b/src/libslic3r/Format/ZipperArchiveImport.hpp index adddcacd40..18cbb78209 100644 --- a/src/libslic3r/Format/ZipperArchiveImport.hpp +++ b/src/libslic3r/Format/ZipperArchiveImport.hpp @@ -1,12 +1,14 @@ #ifndef ZIPPERARCHIVEIMPORT_HPP #define ZIPPERARCHIVEIMPORT_HPP +#include #include #include #include #include +#include "libslic3r/Config.hpp" #include "libslic3r/PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 160c169d69..fb4c877a04 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -12,10 +12,61 @@ #include "../Time.hpp" #include "../I18N.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/GCode/GCodeProcessor.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/MultiNozzleUtils.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/ObjectID.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/BrimEarsPoint.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/CustomGCode.hpp" +#include "libslic3r_version.h" #include "bbs_3mf.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -39,6 +90,10 @@ #include #include #include +#include +#include +#include +#include namespace pt = boost::property_tree; diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index 768ae7bcfe..489870b8fc 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -2,9 +2,21 @@ #define BBS_3MF_hpp_ #include "../GCode/ThumbnailData.hpp" +#include "libslic3r/MultiNozzleUtils.hpp" +#include "libslic3r/Semver.hpp" #include "libslic3r/ProjectTask.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { class Model; diff --git a/src/libslic3r/Format/objparser.cpp b/src/libslic3r/Format/objparser.cpp index c5f33a7d0a..5146a21e80 100644 --- a/src/libslic3r/Format/objparser.cpp +++ b/src/libslic3r/Format/objparser.cpp @@ -1,8 +1,16 @@ +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include #include "objparser.hpp" diff --git a/src/libslic3r/Format/objparser.hpp b/src/libslic3r/Format/objparser.hpp index e711bdf6f4..b34c0f3bf2 100644 --- a/src/libslic3r/Format/objparser.hpp +++ b/src/libslic3r/Format/objparser.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace ObjParser { diff --git a/src/libslic3r/Format/svg.cpp b/src/libslic3r/Format/svg.cpp index 7b720e62ef..7521afddb9 100644 --- a/src/libslic3r/Format/svg.cpp +++ b/src/libslic3r/Format/svg.cpp @@ -1,3 +1,5 @@ +#include "libslic3r/Point.hpp" +#include "libslic3r/Format/STEP.hpp" #include "libslic3r/ClipperUtils.hpp" #include "../libslic3r.h" #include "../Model.hpp" @@ -6,9 +8,23 @@ #include "svg.hpp" #include "nanosvg/nanosvg.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include "BRepBuilderAPI_MakeWire.hxx" #include "BRepBuilderAPI_MakeEdge.hxx" @@ -20,7 +36,6 @@ #include "TopExp_Explorer.hxx" #include "TopoDS.hxx" #include "BRepExtrema_SelfIntersection.hxx" -#include "libslic3r/clipper.hpp" #include "libslic3r/Polygon.hpp" namespace Slic3r { @@ -211,26 +226,15 @@ bool get_svg_profile(const char *path, std::vector &element_infos, Polygons polygons; bool close_polygon = false; for (int i = 0; i < path_line_points.size(); ++i) { - ClipperLib::Path pt_path; - for (auto line_point : path_line_points[i]) { - pt_path.push_back(ClipperLib::IntPoint(line_point.first.X() * scale_size, line_point.first.Y() * scale_size)); + Polyline pt_path; + for (auto line_point : path_line_points[i]) { + pt_path.points.push_back(Point(line_point.first.X() * scale_size, line_point.first.Y() * scale_size)); } - pt_path.push_back(ClipperLib::IntPoint(path_line_points[i].back().second.X() * scale_size, path_line_points[i].back().second.Y() * scale_size)); + pt_path.points.push_back(Point(path_line_points[i].back().second.X() * scale_size, path_line_points[i].back().second.Y() * scale_size)); - ClipperLib::Paths out_paths; - ClipperLib::ClipperOffset co; - if (pt_path.front() == pt_path.back()) { - co.AddPath(pt_path, ClipperLib::jtMiter, ClipperLib::etClosedLine); - close_polygon = true; - } else { - co.AddPath(pt_path, ClipperLib::jtMiter, ClipperLib::etOpenSquare); - close_polygon = false; - } - co.Execute(out_paths, stroke_width / 2); - - for (auto out_path : out_paths) { - polygons.emplace_back(Polygon(out_path)); - } + close_polygon = pt_path.points.front() == pt_path.points.back(); + if (stroke_width > 0) + append(polygons, offset(pt_path, stroke_width / 2, jtMiter, 2., close_polygon ? etClosedLine : etOpenSquare)); } if (!close_polygon) diff --git a/src/libslic3r/Format/svg.hpp b/src/libslic3r/Format/svg.hpp index 095251c32a..cf6c35137f 100644 --- a/src/libslic3r/Format/svg.hpp +++ b/src/libslic3r/Format/svg.hpp @@ -1,4 +1,7 @@ #pragma once + +#include + namespace Slic3r { class Model; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 4c02cae7b4..2b0f254b43 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1,9 +1,31 @@ +#include "ArcFitter.hpp" #include "BoundingBox.hpp" +#include "Circle.hpp" #include "Config.hpp" +#include "GCode/GCodeProcessor.hpp" +#include "Flow.hpp" +#include "GCode/ThumbnailData.hpp" +#include "GCode/ToolOrdering.hpp" +#include "GCode/SpiralVase.hpp" +#include "GCode/PressureEqualizer.hpp" +#include "GCode/SmallAreaInfillFlowCompensator.hpp" +#include "GCode/CoolingBuffer.hpp" +#include "GCode/AdaptivePAProcessor.hpp" +#include "CustomGCode.hpp" +#include "GCode/TimelapsePosPicker.hpp" +#include "ExPolygon.hpp" #include "GCode/WipePathHelpers.hpp" +#include "GCodeReader.hpp" #include "GCodeWriter.hpp" +#include "Point.hpp" +#include "Line.hpp" +#include "ObjectID.hpp" +#include "Layer.hpp" #include "Polygon.hpp" +#include "Polyline.hpp" +#include "PrintBase.hpp" #include "PrintConfig.hpp" +#include "enum_bitmask.hpp" #include "libslic3r.h" #include "I18N.hpp" #include "GCode.hpp" @@ -26,16 +48,39 @@ #include "libslic3r/format.hpp" #include "Time.hpp" #include "GCode/ExtrusionProcessor.hpp" +#include +#include #include +#include +#include +#include +#include #include #include +#include +#include +#include #include #include +#include +#include +#include +#include #include #include +#include +#include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include #include @@ -54,7 +99,9 @@ #include "SVG.hpp" #include +#include #include "calib.hpp" +#include "libslic3r_version.h" // Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332. // We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB. #if ! defined(TBB_VERSION_MAJOR) @@ -4334,9 +4381,9 @@ size_t GCode::get_extruder_id(unsigned int filament_id) const size_t GCode::get_filament_config_index(int filament_id) const { - if (m_print) { - return m_print->get_filament_config_indx(filament_id, m_cur_layer_idx); - } + if (m_print) + return m_filament_index_cache.get(filament_id, m_cur_layer_idx, m_print->config_index_generation(), + [&] { return m_print->get_filament_config_indx(filament_id, m_cur_layer_idx); }); // Orca: without a Print the filament-indexed arrays are unexpanded, so the // filament id itself is the only meaningful column. return filament_id; @@ -4350,9 +4397,9 @@ size_t GCode::get_filament_config_index(int filament_id, size_t layer_id) const size_t GCode::get_nozzle_config_index(int filament_id) const { - if (m_print) { - return m_print->get_nozzle_config_index(filament_id, m_cur_layer_idx); - } + if (m_print) + return m_nozzle_index_cache.get(filament_id, m_cur_layer_idx, m_print->config_index_generation(), + [&] { return m_print->get_nozzle_config_index(filament_id, m_cur_layer_idx); }); // Orca: same reasoning; degenerate to the filament's extruder column. return get_extruder_id(filament_id); } @@ -8059,28 +8106,36 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, unsigned int acceleration_i = 0; double jerk = 0; // adjust acceleration - if (NOZZLE_CONFIG(default_acceleration) > 0) { + const size_t nozzle = get_nozzle_config_index(m_writer.filament()->id()); + if (m_config.default_acceleration.get_at(nozzle) > 0) { + const ExtrusionRole role = path.role(); + const double bridge_acceleration = is_bridge(role) ? + m_config.bridge_acceleration.get_at(nozzle).get_abs_value(m_config.outer_wall_acceleration.get_at(nozzle)) : 0.; + const double sparse_infill_acceleration = role == erInternalInfill ? + m_config.sparse_infill_acceleration.get_at(nozzle).get_abs_value(m_config.default_acceleration.get_at(nozzle)) : 0.; + const double internal_solid_infill_acceleration = role == erSolidInfill ? + m_config.internal_solid_infill_acceleration.get_at(nozzle).get_abs_value(m_config.default_acceleration.get_at(nozzle)) : 0.; double acceleration; - if (this->on_first_layer() && NOZZLE_CONFIG(initial_layer_acceleration) > 0) { - acceleration = NOZZLE_CONFIG(initial_layer_acceleration); + if (this->on_first_layer() && m_config.initial_layer_acceleration.get_at(nozzle) > 0) { + acceleration = m_config.initial_layer_acceleration.get_at(nozzle); #if 0 } else if (this->object_layer_over_raft() && m_config.first_layer_acceleration_over_raft.value > 0) { acceleration = m_config.first_layer_acceleration_over_raft.value; #endif - } else if (m_config.get_abs_value_at("bridge_acceleration", get_nozzle_config_index(m_writer.filament()->id())) > 0 && is_bridge(path.role())) { - acceleration = m_config.get_abs_value_at("bridge_acceleration", get_nozzle_config_index(m_writer.filament()->id())); - } else if (m_config.get_abs_value_at("sparse_infill_acceleration", get_nozzle_config_index(m_writer.filament()->id())) > 0 && (path.role() == erInternalInfill)) { - acceleration = m_config.get_abs_value_at("sparse_infill_acceleration", get_nozzle_config_index(m_writer.filament()->id())); - } else if (m_config.get_abs_value_at("internal_solid_infill_acceleration", get_nozzle_config_index(m_writer.filament()->id())) > 0 && (path.role() == erSolidInfill)) { - acceleration = m_config.get_abs_value_at("internal_solid_infill_acceleration", get_nozzle_config_index(m_writer.filament()->id())); - } else if (NOZZLE_CONFIG(outer_wall_acceleration) > 0 && is_external_perimeter(path.role())) { - acceleration = NOZZLE_CONFIG(outer_wall_acceleration); - } else if (NOZZLE_CONFIG(inner_wall_acceleration) > 0 && is_internal_perimeter(path.role())) { - acceleration = NOZZLE_CONFIG(inner_wall_acceleration); - } else if (NOZZLE_CONFIG(top_surface_acceleration) > 0 && is_top_surface(path.role())) { - acceleration = NOZZLE_CONFIG(top_surface_acceleration); + } else if (bridge_acceleration > 0) { + acceleration = bridge_acceleration; + } else if (sparse_infill_acceleration > 0) { + acceleration = sparse_infill_acceleration; + } else if (internal_solid_infill_acceleration > 0) { + acceleration = internal_solid_infill_acceleration; + } else if (m_config.outer_wall_acceleration.get_at(nozzle) > 0 && is_external_perimeter(role)) { + acceleration = m_config.outer_wall_acceleration.get_at(nozzle); + } else if (m_config.inner_wall_acceleration.get_at(nozzle) > 0 && is_internal_perimeter(role)) { + acceleration = m_config.inner_wall_acceleration.get_at(nozzle); + } else if (m_config.top_surface_acceleration.get_at(nozzle) > 0 && is_top_surface(role)) { + acceleration = m_config.top_surface_acceleration.get_at(nozzle); } else { - acceleration = NOZZLE_CONFIG(default_acceleration); + acceleration = m_config.default_acceleration.get_at(nozzle); } acceleration_i = (unsigned int)floor(acceleration + 0.5); } @@ -8181,7 +8236,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, speed = std::min(speed, m_config.scarf_joint_speed.get_abs_value(speed)); } } else if(path.role() == erInternalBridgeInfill) { - speed = m_config.get_abs_value_at("internal_bridge_speed", get_nozzle_config_index(m_writer.filament()->id())); + speed = m_config.internal_bridge_speed.get_at(nozzle).get_abs_value(m_config.bridge_speed.get_at(nozzle)); } else if (path.role() == erOverhangPerimeter || path.role() == erSupportTransition || path.role() == erBridgeInfill) { speed = NOZZLE_CONFIG(bridge_speed); } else if (path.role() == erInternalInfill) { @@ -8193,7 +8248,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } else if (path.role() == erIroning) { const size_t filament_idx = get_filament_config_index(m_writer.filament()->id()); speed = m_config.filament_ironing_speed.is_nil(filament_idx) - ? m_config.get_abs_value("ironing_speed") + ? m_config.ironing_speed.value : m_config.filament_ironing_speed.get_at(filament_idx); } else if (path.role() == erBottomSurface) { speed = NOZZLE_CONFIG(initial_layer_infill_speed); @@ -8254,7 +8309,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } // Override skirt speed if set if (path.role() == erSkirt) { - const double skirt_speed = m_config.get_abs_value("skirt_speed"); + const double skirt_speed = m_config.skirt_speed.value; if (skirt_speed > 0.0) speed = skirt_speed; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 29a8ae5a34..0172fcf8c0 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -1,6 +1,11 @@ #ifndef slic3r_GCode_hpp_ #define slic3r_GCode_hpp_ +#include "ExtrusionEntity.hpp" +#include "Polygon.hpp" +#include "Config.hpp" +#include "ExtrusionEntityCollection.hpp" +#include "Print.hpp" #include "libslic3r.h" #include "ExPolygon.hpp" #include "GCodeWriter.hpp" @@ -28,12 +33,20 @@ #include "GCode/AdaptivePAProcessor.hpp" #include "GCode/TimelapsePosPicker.hpp" +#include "libslic3r_version.h" +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include namespace Slic3r { @@ -301,6 +314,24 @@ public: size_t get_filament_config_index(int filament_id, size_t layer_id) const; size_t get_nozzle_config_index(int filament_id) const; + // Holds the last slot a resolver returned without locking, so only the G-code generator may + // call the resolvers. + struct ConfigIndexCache + { + bool valid{false}; + int filament_id{0}; + size_t layer_idx{0}; + size_t generation{0}; + size_t index{0}; + + template size_t get(int filament, size_t layer, size_t gen, Lookup &&lookup) + { + if (!valid || filament_id != filament || layer_idx != layer || generation != gen) + *this = {true, filament, layer, gen, size_t(lookup())}; + return index; + } + }; + // Object and support extrusions of the same PrintObject at the same print_z. // public, so that it could be accessed by free helper functions from GCode.cpp struct LayerToPrint @@ -784,6 +815,8 @@ private: // Object layer id of the layer being generated; keys the per-filament config-slot // resolvers. Distinct from m_layer_index (an export progress counter starting at -1). size_t m_cur_layer_idx{0}; + mutable ConfigIndexCache m_filament_index_cache; + mutable ConfigIndexCache m_nozzle_index_cache; std::set m_initial_layer_extruders; std::vector> m_sorted_layer_filaments; diff --git a/src/libslic3r/GCode/AdaptivePAInterpolator.cpp b/src/libslic3r/GCode/AdaptivePAInterpolator.cpp index 2681ab13b2..5d86420ad2 100644 --- a/src/libslic3r/GCode/AdaptivePAInterpolator.cpp +++ b/src/libslic3r/GCode/AdaptivePAInterpolator.cpp @@ -4,10 +4,16 @@ // Implementation file for the AdaptivePAInterpolator class, providing methods to parse data and perform PA interpolation. #include "AdaptivePAInterpolator.hpp" +#include +#include "libslic3r/GCode/PchipInterpolatorHelper.hpp" +#include #include #include #include #include +#include +#include +#include /** * @brief Parses the input data and sets up the interpolators. diff --git a/src/libslic3r/GCode/AdaptivePAProcessor.cpp b/src/libslic3r/GCode/AdaptivePAProcessor.cpp index 8145db3b9f..21bd308853 100644 --- a/src/libslic3r/GCode/AdaptivePAProcessor.cpp +++ b/src/libslic3r/GCode/AdaptivePAProcessor.cpp @@ -4,11 +4,20 @@ // Implementation of the AdaptivePAProcessor class, responsible for processing G-code layers with adaptive pressure advance. #include "../GCode.hpp" +#include "libslic3r/GCode/AdaptivePAInterpolator.hpp" +#include "libslic3r/libslic3r.h" #include "AdaptivePAProcessor.hpp" +#include +#include +#include +#include +#include +#include #include #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/AdaptivePAProcessor.hpp b/src/libslic3r/GCode/AdaptivePAProcessor.hpp index 01aa2f1104..c662191536 100644 --- a/src/libslic3r/GCode/AdaptivePAProcessor.hpp +++ b/src/libslic3r/GCode/AdaptivePAProcessor.hpp @@ -11,12 +11,14 @@ #include #include #include +#include #include "AdaptivePAInterpolator.hpp" namespace Slic3r { // Forward declaration of GCode class class GCode; +class PrintConfig; /** * @brief Class for processing G-code layers with adaptive pressure advance. diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index 21f02b3462..62c2ae61fd 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -7,11 +7,30 @@ #include "../Geometry.hpp" #include "../ClipperUtils.hpp" #include "../SVG.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/Config.hpp" #include "AvoidCrossingPerimeters.hpp" +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp index a348eed786..53e2942d3b 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp @@ -4,6 +4,10 @@ #include "../libslic3r.h" #include "../ExPolygon.hpp" #include "../EdgeGrid.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/BoundingBox.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp index e8f533be7c..70b58423fa 100644 --- a/src/libslic3r/GCode/ConflictChecker.cpp +++ b/src/libslic3r/GCode/ConflictChecker.cpp @@ -1,11 +1,28 @@ #include "ConflictChecker.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/ExtrusionEntityCollection.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Layer.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/GCode/GCodeProcessor.hpp" +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/ConflictChecker.hpp b/src/libslic3r/GCode/ConflictChecker.hpp index a10b969431..50a126b89a 100644 --- a/src/libslic3r/GCode/ConflictChecker.hpp +++ b/src/libslic3r/GCode/ConflictChecker.hpp @@ -5,8 +5,18 @@ #include "../Model.hpp" #include "../Print.hpp" #include "../Layer.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" +#include "libslic3r/GCode/GCodeProcessor.hpp" #include +#include +#include +#include +#include #include #include diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 7f6e9c67d5..6524b3ce38 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -1,12 +1,26 @@ #include "../GCode.hpp" +#include "libslic3r/Extruder.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Circle.hpp" #include "CoolingBuffer.hpp" +#include #include #include #include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include +#include +#include #if 0 #define DEBUG diff --git a/src/libslic3r/GCode/CoolingBuffer.hpp b/src/libslic3r/GCode/CoolingBuffer.hpp index 742b8f78b7..0f7e27b14f 100644 --- a/src/libslic3r/GCode/CoolingBuffer.hpp +++ b/src/libslic3r/GCode/CoolingBuffer.hpp @@ -2,14 +2,18 @@ #define slic3r_CoolingBuffer_hpp_ #include "../libslic3r.h" +#include "../Point.hpp" +#include #include #include #include +#include namespace Slic3r { class GCode; class Layer; +class PrintConfig; struct PerExtruderAdjustments; // A standalone G-code filter, to control cooling of the print. diff --git a/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp b/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp index cac53637a5..1b086e4f47 100644 --- a/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp +++ b/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp @@ -1,10 +1,13 @@ #include "GCodeProcessor.hpp" +#include "libslic3r/GCodeReader.hpp" #include "libslic3r/libslic3r.h" #include #include #include +#include +#include #include namespace Slic3r { diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index 8ed829aa6e..7cc886bfe9 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -15,7 +15,10 @@ #include "../ClipperUtils.hpp" #include "../Flow.hpp" #include "../Config.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExPolygon.hpp" +#include #include #include #include diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp index 9d77d1d04c..cb5fc310ee 100644 --- a/src/libslic3r/GCode/FanMover.cpp +++ b/src/libslic3r/GCode/FanMover.cpp @@ -1,10 +1,25 @@ #include "FanMover.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/ExtrusionEntity.hpp" #include "GCodeReader.hpp" +#include +#include +#include +#include +#include +#include +#include +#include #include /* +#include +#include +#include #include +#include #include #include @@ -12,8 +27,12 @@ #include "../PrintConfig.hpp" #include "../Utils.hpp" #include "Print.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" #include +#include +#include */ diff --git a/src/libslic3r/GCode/FanMover.hpp b/src/libslic3r/GCode/FanMover.hpp index 17addd855c..b3a6fcb309 100644 --- a/src/libslic3r/GCode/FanMover.hpp +++ b/src/libslic3r/GCode/FanMover.hpp @@ -9,7 +9,12 @@ #include "../Point.hpp" #include "../GCodeReader.hpp" #include "../GCodeWriter.hpp" +#include +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index e03be228d0..760a04eb4d 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1,14 +1,30 @@ +#include "libslic3r/Config.hpp" +#include "libslic3r/CustomGCode.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/CommonDefs.hpp" +#include "libslic3r/ArcFitter.hpp" #include "ExtrusionEntity.hpp" +#include "libslic3r/GCodeReader.hpp" #include "GCodeWriter.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/PrintBase.hpp" +#include "libslic3r/Polygon.hpp" #include "PrintConfig.hpp" +#include "libslic3r/TriangleSelector.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "libslic3r/Print.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/format.hpp" +#include "libslic3r_version.h" #include "GCodeProcessor.hpp" +#include +#include +#include +#include #include #include #include @@ -16,15 +32,38 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include +#include #include +#include +#include +#include +#include #if __has_include() #include diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 192a80a43d..cde789cb6c 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -1,6 +1,11 @@ #ifndef slic3r_GCodeProcessor_hpp_ #define slic3r_GCodeProcessor_hpp_ +#include "libslic3r/CommonDefs.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/ArcFitter.hpp" #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/ExtrusionEntity.hpp" @@ -8,8 +13,17 @@ #include "libslic3r/CustomGCode.hpp" #include "libslic3r/MultiNozzleUtils.hpp" +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/GCode/OrderingStrategies.cpp b/src/libslic3r/GCode/OrderingStrategies.cpp index 2ba9ae5490..73cb90f461 100644 --- a/src/libslic3r/GCode/OrderingStrategies.cpp +++ b/src/libslic3r/GCode/OrderingStrategies.cpp @@ -4,9 +4,14 @@ #include "OrderingStrategies.hpp" #include "../Geometry.hpp" #include "../ShortestPath.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/PrintConfig.hpp" #include #include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/GCode/OrderingStrategies.hpp b/src/libslic3r/GCode/OrderingStrategies.hpp index 598eac8130..4e6d766b37 100644 --- a/src/libslic3r/GCode/OrderingStrategies.hpp +++ b/src/libslic3r/GCode/OrderingStrategies.hpp @@ -5,6 +5,8 @@ #include "../libslic3r.h" #include "../Point.hpp" +#include +#include "libslic3r/PrintConfig.hpp" #ifndef SLIC3R_TEST_HARNESS #include "../Print.hpp" diff --git a/src/libslic3r/GCode/PchipInterpolatorHelper.cpp b/src/libslic3r/GCode/PchipInterpolatorHelper.cpp index 44baa6cbf7..b01a23edb5 100644 --- a/src/libslic3r/GCode/PchipInterpolatorHelper.cpp +++ b/src/libslic3r/GCode/PchipInterpolatorHelper.cpp @@ -4,9 +4,13 @@ // Implementation file for the PchipInterpolatorHelper class #include "PchipInterpolatorHelper.hpp" +#include +#include #include #include #include +#include +#include /** * @brief Constructs the PCHIP interpolator with given data points. diff --git a/src/libslic3r/GCode/PreciseSeam.cpp b/src/libslic3r/GCode/PreciseSeam.cpp index 378ab2d2d3..b8eb5ea270 100644 --- a/src/libslic3r/GCode/PreciseSeam.cpp +++ b/src/libslic3r/GCode/PreciseSeam.cpp @@ -1,9 +1,23 @@ #include "PreciseSeam.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/ClipperUtils.hpp" #include "SeamPlacer.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/BoundingBox.hpp" #include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include namespace Slic3r { namespace PreciseSeam { diff --git a/src/libslic3r/GCode/PreciseSeam.hpp b/src/libslic3r/GCode/PreciseSeam.hpp index d5c1e98952..f4f75c37bf 100644 --- a/src/libslic3r/GCode/PreciseSeam.hpp +++ b/src/libslic3r/GCode/PreciseSeam.hpp @@ -2,9 +2,11 @@ #define slic3r_PreciseSeam_hpp_ #include +#include #include #include #include +#include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/Polyline.hpp" #include "libslic3r/Model.hpp" diff --git a/src/libslic3r/GCode/PressureEqualizer.cpp b/src/libslic3r/GCode/PressureEqualizer.cpp index 3db54ca2af..44ca576933 100644 --- a/src/libslic3r/GCode/PressureEqualizer.cpp +++ b/src/libslic3r/GCode/PressureEqualizer.cpp @@ -1,8 +1,17 @@ +#include +#include +#include +#include +#include +#include #include +#include +#include #include #include #include #include +#include #include "../libslic3r.h" #include "../PrintConfig.hpp" @@ -10,6 +19,8 @@ #include "../GCode.hpp" #include "PressureEqualizer.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Exception.hpp" #include "fast_float/fast_float.h" #include "GCodeWriter.hpp" diff --git a/src/libslic3r/GCode/PressureEqualizer.hpp b/src/libslic3r/GCode/PressureEqualizer.hpp index 2f2982860e..be8e0e77fe 100644 --- a/src/libslic3r/GCode/PressureEqualizer.hpp +++ b/src/libslic3r/GCode/PressureEqualizer.hpp @@ -2,7 +2,14 @@ #define slic3r_GCode_PressureEqualizer_hpp_ #include "../libslic3r.h" +#include "../ExtrusionEntity.hpp" #include "../PrintConfig.hpp" +#include +#include +#include +#include +#include +#include #include diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index 9008adaa9a..71bc826258 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -10,7 +10,16 @@ #include "../Print.hpp" #include "PrintExtents.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/Geometry.hpp" #include "WipeTower.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp b/src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp index 776091adfb..32994741d4 100644 --- a/src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/RetractWhenCrossingPerimeters.cpp @@ -1,6 +1,15 @@ #include "../ClipperUtils.hpp" #include "../Layer.hpp" #include "../Polyline.hpp" +#include "libslic3r/Surface.hpp" +#include +#include "libslic3r/AABBTreeIndirect.hpp" +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/Polygon.hpp" #include "RetractWhenCrossingPerimeters.hpp" diff --git a/src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp b/src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp index fb624d7f90..e6029ce7f1 100644 --- a/src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp +++ b/src/libslic3r/GCode/RetractWhenCrossingPerimeters.hpp @@ -4,6 +4,7 @@ #include #include "../AABBTreeIndirect.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index d527ec6aa9..720339f746 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1,15 +1,38 @@ #include "SeamPlacer.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/AABBTreeIndirect.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExPolygon.hpp" #include "Polygon.hpp" +#include "libslic3r/PrintBase.hpp" #include "PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/TriangleSelector.hpp" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" #include "tbb/parallel_reduce.h" +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include +#include #include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/KDTreeIndirect.hpp" diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 9855b4f4aa..cbf2c73fbe 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -1,12 +1,17 @@ #ifndef libslic3r_SeamPlacer_hpp_ #define libslic3r_SeamPlacer_hpp_ +#include +#include #include #include +#include +#include #include #include #include +#include "libslic3r/Point.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/Polygon.hpp" diff --git a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp index 20377cfe8d..fec0e4aa88 100644 --- a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp +++ b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp @@ -6,16 +6,26 @@ // Based on original work by Alexander Þór licensed under the GPLv3: // https://github.com/Alexander-T-Moss/Small-Area-Flow-Comp +#include +#include +#include #include #include #include +#include +#include #include #include "../libslic3r.h" #include "../PrintConfig.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/GCode/PchipInterpolatorHelper.hpp" +#include "libslic3r/ExtrusionEntity.hpp" #include "SmallAreaInfillFlowCompensator.hpp" #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp index de1df98170..2139e7f438 100644 --- a/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp +++ b/src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp @@ -6,6 +6,7 @@ #include "../ExtrusionEntity.hpp" #include "PchipInterpolatorHelper.hpp" #include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/SpiralVase.cpp b/src/libslic3r/GCode/SpiralVase.cpp index 2c39bda4f7..d96f99de4f 100644 --- a/src/libslic3r/GCode/SpiralVase.cpp +++ b/src/libslic3r/GCode/SpiralVase.cpp @@ -1,8 +1,13 @@ #include "SpiralVase.hpp" #include "GCode.hpp" +#include "libslic3r/libslic3r.h" +#include +#include #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/SpiralVase.hpp b/src/libslic3r/GCode/SpiralVase.hpp index f28b4c5f55..b1e7c79f7e 100644 --- a/src/libslic3r/GCode/SpiralVase.hpp +++ b/src/libslic3r/GCode/SpiralVase.hpp @@ -3,6 +3,10 @@ #include "../libslic3r.h" #include "../GCodeReader.hpp" +#include "libslic3r/PrintConfig.hpp" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/ThumbnailData.cpp b/src/libslic3r/GCode/ThumbnailData.cpp index d895c0d95f..a86d10c4a4 100644 --- a/src/libslic3r/GCode/ThumbnailData.cpp +++ b/src/libslic3r/GCode/ThumbnailData.cpp @@ -1,4 +1,5 @@ #include "ThumbnailData.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp index bc37ad40c4..f112000273 100644 --- a/src/libslic3r/GCode/ThumbnailData.hpp +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -1,7 +1,10 @@ #ifndef slic3r_ThumbnailData_hpp_ #define slic3r_ThumbnailData_hpp_ +#include +#include #include +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" #include "nlohmann/json.hpp" diff --git a/src/libslic3r/GCode/Thumbnails.cpp b/src/libslic3r/GCode/Thumbnails.cpp index 526ba82498..9d32b0b63b 100644 --- a/src/libslic3r/GCode/Thumbnails.cpp +++ b/src/libslic3r/GCode/Thumbnails.cpp @@ -1,11 +1,27 @@ #include "Thumbnails.hpp" #include "../miniz_extension.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/enum_bitmask.hpp" #include "format.hpp" #include #include +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libslic3r/GCode/Thumbnails.hpp b/src/libslic3r/GCode/Thumbnails.hpp index bcee02fea1..fd72973bac 100644 --- a/src/libslic3r/GCode/Thumbnails.hpp +++ b/src/libslic3r/GCode/Thumbnails.hpp @@ -4,9 +4,13 @@ #include "../Point.hpp" #include "../PrintConfig.hpp" #include "../enum_bitmask.hpp" +#include "libslic3r/Config.hpp" #include "ThumbnailData.hpp" #include "../enum_bitmask.hpp" +#include +#include +#include #include #include #include diff --git a/src/libslic3r/GCode/TimelapsePosPicker.cpp b/src/libslic3r/GCode/TimelapsePosPicker.cpp index 364624a88c..fded08c1ce 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.cpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.cpp @@ -1,6 +1,23 @@ #include "ClipperUtils.hpp" #include "TimelapsePosPicker.hpp" +#include "libslic3r/ExPolygon.hpp" #include "Layer.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/PrintConfig.hpp" +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include +#include +#include "libslic3r/Print.hpp" +#include +#include +#include +#include "libslic3r/Utils.hpp" +#include "libslic3r/Polyline.hpp" constexpr int FILTER_THRESHOLD = 5; constexpr int MAX_CANDIDATE_SIZE = 5; diff --git a/src/libslic3r/GCode/TimelapsePosPicker.hpp b/src/libslic3r/GCode/TimelapsePosPicker.hpp index 9ed6b14fc7..af102e6340 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.hpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.hpp @@ -1,7 +1,11 @@ #ifndef TIMELAPSE_POS_PICKER_HPP #define TIMELAPSE_POS_PICKER_HPP +#include +#include #include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/BoundingBox.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/ExPolygon.hpp" #include "libslic3r/Print.hpp" diff --git a/src/libslic3r/GCode/ToolOrderUtils.cpp b/src/libslic3r/GCode/ToolOrderUtils.cpp index 4a67477d24..b64042a23f 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.cpp +++ b/src/libslic3r/GCode/ToolOrderUtils.cpp @@ -1,9 +1,23 @@ #include "ToolOrderUtils.hpp" +#include "libslic3r/MultiNozzleUtils.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/ToolOrderUtils.hpp b/src/libslic3r/GCode/ToolOrderUtils.hpp index 7b103531b1..db24545f33 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.hpp +++ b/src/libslic3r/GCode/ToolOrderUtils.hpp @@ -1,6 +1,7 @@ #ifndef TOOL_ORDER_UTILS_HPP #define TOOL_ORDER_UTILS_HPP +#include #include #include #include diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 5026323d54..38532a2f67 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -1,4 +1,9 @@ +#include "libslic3r/Exception.hpp" +#include "libslic3r/CustomGCode.hpp" +#include "libslic3r/Config.hpp" #include "ExtrusionEntity.hpp" +#include "libslic3r/ObjectID.hpp" +#include "libslic3r/FilamentGroup.hpp" #include "Print.hpp" #include "ToolOrdering.hpp" #include "Layer.hpp" @@ -9,11 +14,23 @@ #include "MultiNozzleUtils.hpp" #include "FilamentMixer.hpp" #include "LocalesUtils.hpp" +#include "libslic3r/PrintConfig.hpp" #include "Utils.hpp" #include "format.hpp" #include "I18N.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // #define SLIC3R_DEBUG diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 1b8ce190d7..70b55fdb33 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -5,11 +5,19 @@ #include "../libslic3r.h" +#include +#include +#include #include #include +#include +#include +#include +#include #include #include +#include #include "../FilamentGroup.hpp" #include "../FilamentMixer.hpp" #include "../MultiNozzleUtils.hpp" diff --git a/src/libslic3r/GCode/WipePathHelpers.cpp b/src/libslic3r/GCode/WipePathHelpers.cpp index d785a16a8c..2c2ef7ff74 100644 --- a/src/libslic3r/GCode/WipePathHelpers.cpp +++ b/src/libslic3r/GCode/WipePathHelpers.cpp @@ -1,12 +1,19 @@ #include "WipePathHelpers.hpp" #include "../AABBTreeLines.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include #include #include +#include #include +#include #include +#include namespace Slic3r { diff --git a/src/libslic3r/GCode/WipePathHelpers.hpp b/src/libslic3r/GCode/WipePathHelpers.hpp index 616e5dc88b..17c0dfa238 100644 --- a/src/libslic3r/GCode/WipePathHelpers.hpp +++ b/src/libslic3r/GCode/WipePathHelpers.hpp @@ -5,6 +5,7 @@ #include "../ExtrusionEntity.hpp" #include "../Polyline.hpp" #include "../Line.hpp" +#include "libslic3r/Point.hpp" namespace Slic3r { diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index a700ada09f..cef86313ba 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1,16 +1,39 @@ #include "WipeTower.hpp" +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include "libslic3r/Circle.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ArcFitter.hpp" #include "GCodeProcessor.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" +#include "libslic3r/Line.hpp" #include "LocalesUtils.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/MultiNozzleUtils.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "Triangulation.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 8ea7f848ef..dd000737c7 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -2,16 +2,23 @@ #define WipeTower_ #include +#include +#include +#include +#include #include #include +#include #include #include +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" #include "libslic3r/Polyline.hpp" #include "libslic3r/TriangleMesh.hpp" #include +#include #include "libslic3r/MultiNozzleUtils.hpp" namespace Slic3r { diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index a576172a39..9b92f4c26a 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -1,22 +1,44 @@ // Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger. #include "WipeTower2.hpp" +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include #include #include #include +#include "libslic3r/Circle.hpp" +#include "libslic3r/ArcFitter.hpp" #include "ClipperUtils.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/GCode/WipeTower.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Fill/FillBase.hpp" #include "GCodeProcessor.hpp" #include "BoundingBox.hpp" +#include "libslic3r/Line.hpp" #include "LocalesUtils.hpp" #include "Geometry.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" #include "PrintConfig.hpp" #include "Surface.hpp" #include "Fill/FillRectilinear.hpp" +#include "libslic3r/libslic3r.h" #include diff --git a/src/libslic3r/GCode/WipeTower2.hpp b/src/libslic3r/GCode/WipeTower2.hpp index 02ce15672b..408a5f6607 100644 --- a/src/libslic3r/GCode/WipeTower2.hpp +++ b/src/libslic3r/GCode/WipeTower2.hpp @@ -4,10 +4,14 @@ #define WipeTower2_ #include +#include +#include +#include #include #include #include #include +#include #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" diff --git a/src/libslic3r/GCode/WipeTowerEstimate.cpp b/src/libslic3r/GCode/WipeTowerEstimate.cpp index ac1508d9c0..223850d4f0 100644 --- a/src/libslic3r/GCode/WipeTowerEstimate.cpp +++ b/src/libslic3r/GCode/WipeTowerEstimate.cpp @@ -1,5 +1,6 @@ #include "WipeTowerEstimate.hpp" +#include "libslic3r/Polygon.hpp" #include "WipeTower.hpp" #include "WipeTower2.hpp" #include "../Config.hpp" @@ -8,7 +9,9 @@ #include #include +#include #include +#include namespace Slic3r { diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp index 17510800c5..10c3be600f 100644 --- a/src/libslic3r/GCodeReader.cpp +++ b/src/libslic3r/GCodeReader.cpp @@ -1,18 +1,30 @@ #include "GCodeReader.hpp" +#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include +#include "PrintConfig.hpp" #include "Utils.hpp" #include "LocalesUtils.hpp" +#include "libslic3r.h" #include #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp index 12b9dc98e2..591fe41e6b 100644 --- a/src/libslic3r/GCodeReader.hpp +++ b/src/libslic3r/GCodeReader.hpp @@ -3,10 +3,14 @@ #include "libslic3r.h" #include +#include #include +#include #include #include #include +#include +#include #include "PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/GCodeSender.hpp b/src/libslic3r/GCodeSender.hpp index 3a2055e54f..e9f97e2a29 100644 --- a/src/libslic3r/GCodeSender.hpp +++ b/src/libslic3r/GCodeSender.hpp @@ -3,9 +3,17 @@ #include "libslic3r.h" #include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include #include diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 0e80cc1fb7..667271bcd1 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -1,16 +1,36 @@ #include "GCodeWriter.hpp" +#include "Config.hpp" #include "CustomGCode.hpp" +#include "Extruder.hpp" #include "I18N.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "PrintConfig.hpp" #include "ClipperUtils.hpp" #include "Geometry/ArcWelder.hpp" #include "Line.hpp" +#include "libslic3r.h" #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include #ifdef __APPLE__ #include diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 8247ab757a..a07765a873 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -2,8 +2,14 @@ #define slic3r_GCodeWriter_hpp_ #include "libslic3r.h" +#include +#include +#include +#include +#include #include #include +#include #include "Extruder.hpp" #include "Point.hpp" #include "Polygon.hpp" diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 69aff57c9a..6c097428f4 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1,17 +1,29 @@ +#include "Point.hpp" +#include "Polygon.hpp" +#include "MultiPoint.hpp" +#include "BoundingBox.hpp" #include "libslic3r.h" #include "Exception.hpp" #include "Geometry.hpp" #include "ClipperUtils.hpp" #include "ExPolygon.hpp" #include "Line.hpp" -#include "clipper.hpp" +#include +#include +#include #include +#include +#include #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index e610a9ed4f..cb148e596a 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -9,7 +9,18 @@ #include "Polyline.hpp" // Serialization through the Cereal library +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Geometry/ArcWelder.hpp b/src/libslic3r/Geometry/ArcWelder.hpp index 184a2d6c7c..aee893fae6 100644 --- a/src/libslic3r/Geometry/ArcWelder.hpp +++ b/src/libslic3r/Geometry/ArcWelder.hpp @@ -1,7 +1,9 @@ #ifndef slic3r_Geometry_ArcWelder_hpp_ #define slic3r_Geometry_ArcWelder_hpp_ +#include #include +#include #include #include #include diff --git a/src/libslic3r/Geometry/Bicubic.hpp b/src/libslic3r/Geometry/Bicubic.hpp index 98c6f8bb29..2121947e94 100644 --- a/src/libslic3r/Geometry/Bicubic.hpp +++ b/src/libslic3r/Geometry/Bicubic.hpp @@ -1,7 +1,9 @@ #ifndef BICUBIC_HPP #define BICUBIC_HPP +#include #include +#include #include #include diff --git a/src/libslic3r/Geometry/Circle.cpp b/src/libslic3r/Geometry/Circle.cpp index 6796671954..f8dc0d273d 100644 --- a/src/libslic3r/Geometry/Circle.cpp +++ b/src/libslic3r/Geometry/Circle.cpp @@ -1,10 +1,19 @@ #include "Circle.hpp" #include "../Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include #include #include #include +#include namespace Slic3r { namespace Geometry { diff --git a/src/libslic3r/Geometry/Circle.hpp b/src/libslic3r/Geometry/Circle.hpp index 653102e2ab..8f8655df65 100644 --- a/src/libslic3r/Geometry/Circle.hpp +++ b/src/libslic3r/Geometry/Circle.hpp @@ -2,8 +2,13 @@ #define slic3r_Geometry_Circle_hpp_ #include "../Point.hpp" +#include "libslic3r/libslic3r.h" +#include #include +#include +#include +#include namespace Slic3r { namespace Geometry { diff --git a/src/libslic3r/Geometry/ConvexHull.cpp b/src/libslic3r/Geometry/ConvexHull.cpp index b8bf5eb696..80617c0caf 100644 --- a/src/libslic3r/Geometry/ConvexHull.cpp +++ b/src/libslic3r/Geometry/ConvexHull.cpp @@ -1,9 +1,19 @@ +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" #include "libslic3r.h" #include "ConvexHull.hpp" #include "BoundingBox.hpp" #include "../Geometry.hpp" +#include +#include #include +#include +#include +#include +#include +#include namespace Slic3r { namespace Geometry { diff --git a/src/libslic3r/Geometry/ConvexHull.hpp b/src/libslic3r/Geometry/ConvexHull.hpp index eb0be4fe1f..f8bac380e8 100644 --- a/src/libslic3r/Geometry/ConvexHull.hpp +++ b/src/libslic3r/Geometry/ConvexHull.hpp @@ -1,9 +1,12 @@ #ifndef slic3r_Geometry_ConvexHull_hpp_ #define slic3r_Geometry_ConvexHull_hpp_ +#include #include #include "../Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" namespace Slic3r { diff --git a/src/libslic3r/Geometry/Curves.hpp b/src/libslic3r/Geometry/Curves.hpp index f4a5a0067e..e9c4bef40c 100644 --- a/src/libslic3r/Geometry/Curves.hpp +++ b/src/libslic3r/Geometry/Curves.hpp @@ -4,7 +4,13 @@ #include "libslic3r/Point.hpp" #include "Bicubic.hpp" +#include +#include +#include +#include #include +#include +#include //#define LSQR_DEBUG diff --git a/src/libslic3r/Geometry/MedialAxis.cpp b/src/libslic3r/Geometry/MedialAxis.cpp index 7fece75e63..9d05ec9867 100644 --- a/src/libslic3r/Geometry/MedialAxis.cpp +++ b/src/libslic3r/Geometry/MedialAxis.cpp @@ -5,7 +5,11 @@ #include #include #include +#include +#include +#include "libslic3r/Line.hpp" +#include "libslic3r/Polyline.hpp" #include "VoronoiOffset.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ExPolygon.hpp" diff --git a/src/libslic3r/Geometry/Voronoi.cpp b/src/libslic3r/Geometry/Voronoi.cpp index 4f7173e5c2..7d59e2d2b8 100644 --- a/src/libslic3r/Geometry/Voronoi.cpp +++ b/src/libslic3r/Geometry/Voronoi.cpp @@ -2,7 +2,12 @@ #include #include +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Arachne/utils/PolygonsSegmentIndex.hpp" #include "libslic3r/Geometry/VoronoiUtils.hpp" #include "libslic3r/Geometry/VoronoiUtilsCgal.hpp" diff --git a/src/libslic3r/Geometry/VoronoiOffset.cpp b/src/libslic3r/Geometry/VoronoiOffset.cpp index 70c45dfb25..aeaf883c72 100644 --- a/src/libslic3r/Geometry/VoronoiOffset.cpp +++ b/src/libslic3r/Geometry/VoronoiOffset.cpp @@ -8,7 +8,11 @@ #include #include #include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/Polygon.hpp" #include "libslic3r/Geometry.hpp" #include "VoronoiOffset.hpp" #include "libslic3r/libslic3r.h" diff --git a/src/libslic3r/Geometry/VoronoiUtils.cpp b/src/libslic3r/Geometry/VoronoiUtils.cpp index f140782891..d0ad07cc7e 100644 --- a/src/libslic3r/Geometry/VoronoiUtils.cpp +++ b/src/libslic3r/Geometry/VoronoiUtils.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -10,6 +11,10 @@ #include #include "VoronoiUtils.hpp" +#include "libslic3r/Geometry/Voronoi.hpp" +#include "libslic3r/Arachne/utils/PolygonsPointIndex.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/Exception.hpp" #include "libslic3r/Line.hpp" diff --git a/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp b/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp index 28a648851d..e1ae432f36 100644 --- a/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp +++ b/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp @@ -1,9 +1,18 @@ // Needed since the CGAL headers are not self-contained. +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include diff --git a/src/libslic3r/Geometry/VoronoiVisualUtils.hpp b/src/libslic3r/Geometry/VoronoiVisualUtils.hpp index c89d59bf9a..a27645c159 100644 --- a/src/libslic3r/Geometry/VoronoiVisualUtils.hpp +++ b/src/libslic3r/Geometry/VoronoiVisualUtils.hpp @@ -1,14 +1,26 @@ #ifndef slic3r_VoronoiVisualUtils_hpp_ #define slic3r_VoronoiVisualUtils_hpp_ +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include +#include +#include "libslic3r/Geometry/Voronoi.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" #include "VoronoiOffset.hpp" +#include "libslic3r/libslic3r.h" namespace boost { namespace polygon { diff --git a/src/libslic3r/InstanceLock.cpp b/src/libslic3r/InstanceLock.cpp index 1fa71b572a..7cacdef0cb 100644 --- a/src/libslic3r/InstanceLock.cpp +++ b/src/libslic3r/InstanceLock.cpp @@ -1,7 +1,11 @@ #include "InstanceLock.hpp" +#include +#include #include #include +#include +#include #include #include diff --git a/src/libslic3r/IntersectionPoints.cpp b/src/libslic3r/IntersectionPoints.cpp index 888285f834..7db77d0787 100644 --- a/src/libslic3r/IntersectionPoints.cpp +++ b/src/libslic3r/IntersectionPoints.cpp @@ -1,5 +1,10 @@ #include "IntersectionPoints.hpp" +#include #include +#include "libslic3r/Line.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ExPolygon.hpp" //NOTE: using CGAL SweepLines is slower !!! (example in git history) diff --git a/src/libslic3r/IntersectionPoints.hpp b/src/libslic3r/IntersectionPoints.hpp index 49694c8a8e..89b36224df 100644 --- a/src/libslic3r/IntersectionPoints.hpp +++ b/src/libslic3r/IntersectionPoints.hpp @@ -2,6 +2,11 @@ #define slic3r_IntersectionPoints_hpp_ #include "ExPolygon.hpp" +#include +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Line.hpp" +#include "libslic3r/Polygon.hpp" namespace Slic3r { diff --git a/src/libslic3r/JumpPointSearch.hpp b/src/libslic3r/JumpPointSearch.hpp index 86eeb9ce6a..b5fbf6aaf0 100644 --- a/src/libslic3r/JumpPointSearch.hpp +++ b/src/libslic3r/JumpPointSearch.hpp @@ -1,4 +1,5 @@ #pragma once +#include "Line.hpp" #ifndef SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ #define SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ diff --git a/src/libslic3r/KDTreeIndirect.hpp b/src/libslic3r/KDTreeIndirect.hpp index 37c10827b1..d334a2ad64 100644 --- a/src/libslic3r/KDTreeIndirect.hpp +++ b/src/libslic3r/KDTreeIndirect.hpp @@ -4,10 +4,15 @@ #define slic3r_KDTreeIndirect_hpp_ #include +#include +#include +#include #include +#include #include #include "Utils.hpp" // for next_highest_power_of_2() +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/LayOnFace.cpp b/src/libslic3r/LayOnFace.cpp index 1112f9d2fe..3cc5c2fdce 100644 --- a/src/libslic3r/LayOnFace.cpp +++ b/src/libslic3r/LayOnFace.cpp @@ -3,11 +3,17 @@ #include "Geometry.hpp" #include "Geometry/ConvexHull.hpp" #include "Model.hpp" +#include "Point.hpp" #include "TriangleMesh.hpp" +#include "libslic3r.h" +#include #include #include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/LayOnFace.hpp b/src/libslic3r/LayOnFace.hpp index 1a5e92a15e..6a9242e5c6 100644 --- a/src/libslic3r/LayOnFace.hpp +++ b/src/libslic3r/LayOnFace.hpp @@ -2,6 +2,7 @@ #include "Point.hpp" +#include #include namespace Slic3r { diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 7bdef5a4ff..7f27012dc4 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -1,12 +1,28 @@ #include "Layer.hpp" #include "ClipperUtils.hpp" +#include "Polygon.hpp" +#include "Point.hpp" +#include "ExPolygon.hpp" +#include "ExtrusionEntity.hpp" +#include "Exception.hpp" +#include "Flow.hpp" #include "Print.hpp" #include "Fill/Fill.hpp" +#include "PrintConfig.hpp" #include "ShortestPath.hpp" #include "SVG.hpp" #include "BoundingBox.hpp" +#include "Surface.hpp" +#include "libslic3r.h" +#include "Utils.hpp" +#include #include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 9be6b86139..600e4c4062 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -1,12 +1,21 @@ #ifndef slic3r_Layer_hpp_ #define slic3r_Layer_hpp_ +#include "Polyline.hpp" +#include "Polygon.hpp" +#include "ExtrusionEntity.hpp" +#include "Line.hpp" #include "libslic3r.h" #include "BoundingBox.hpp" #include "Flow.hpp" #include "SurfaceCollection.hpp" #include "ExtrusionEntityCollection.hpp" #include "BoundingBox.hpp" +#include +#include +#include +#include +#include namespace Slic3r { class ExPolygon; diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 6f868ba095..3132dd348d 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -1,20 +1,44 @@ +#include "Flow.hpp" +#include "Config.hpp" +#include "ExPolygon.hpp" +#include "ExtrusionEntity.hpp" +#include "Exception.hpp" #include "Layer.hpp" #include "BridgeDetector.hpp" #include "ClipperUtils.hpp" #include "Geometry.hpp" +#include "Line.hpp" #include "PerimeterGenerator.hpp" #include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" #include "Print.hpp" +#include "PrintConfig.hpp" #include "Surface.hpp" #include "BoundingBox.hpp" #include "SVG.hpp" #include "Algorithm/RegionExpansion.hpp" +#include "libslic3r.h" +#include "Utils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include namespace Slic3r { @@ -627,9 +651,9 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly } #else -//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. -//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5 -#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS jtMiter, 3. +//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS jtMiter, 1.5 +#define EXTERNAL_SURFACES_OFFSET_PARAMETERS jtSquare, 0. void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered) { diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index 94453e18f7..5c40e48e63 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -1,8 +1,13 @@ #include "Geometry.hpp" #include "Line.hpp" +#include "Point.hpp" #include "Polyline.hpp" +#include +#include "libslic3r.h" #include #include +#include +#include #include namespace Slic3r { diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index d8240702b2..f75ef7fc66 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -4,7 +4,10 @@ #include "libslic3r.h" #include "Point.hpp" +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/LocalesUtils.cpp b/src/libslic3r/LocalesUtils.cpp index 9c81511dc5..ead94faeb4 100644 --- a/src/libslic3r/LocalesUtils.cpp +++ b/src/libslic3r/LocalesUtils.cpp @@ -1,4 +1,10 @@ #include "LocalesUtils.hpp" +#include +#include +#include +#include +#include +#include #ifdef _WIN32 #include diff --git a/src/libslic3r/LocalesUtils.hpp b/src/libslic3r/LocalesUtils.hpp index d7e59f5ded..c212a72e69 100644 --- a/src/libslic3r/LocalesUtils.hpp +++ b/src/libslic3r/LocalesUtils.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_LocalesUtils_hpp_ #define slic3r_LocalesUtils_hpp_ +#include #include #include #include diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index ab99ea5f68..b1099e1439 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -1,7 +1,9 @@ #ifndef MTUTILS_HPP #define MTUTILS_HPP +#include #include // for std::atomic_flag and memory orders +#include #include // for std::lock_guard #include // for std::function #include // for std::forward diff --git a/src/libslic3r/MarchingSquares.hpp b/src/libslic3r/MarchingSquares.hpp index 7eb0b25806..e123dd14e0 100644 --- a/src/libslic3r/MarchingSquares.hpp +++ b/src/libslic3r/MarchingSquares.hpp @@ -2,11 +2,17 @@ #define MARCHINGSQUARES_HPP #include "Execution/ExecutionTBB.hpp" +#include +#include "libslic3r/Execution/Execution.hpp" +#include +#include #include #include #include #include #include +#include +#include // Marching squares // diff --git a/src/libslic3r/MaterialType.cpp b/src/libslic3r/MaterialType.cpp index dc65b6d23c..18e27dbe46 100644 --- a/src/libslic3r/MaterialType.cpp +++ b/src/libslic3r/MaterialType.cpp @@ -1,6 +1,8 @@ #include "MaterialType.hpp" #include +#include +#include namespace Slic3r { namespace { diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ad34752685..e2ef912f37 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -1,3 +1,5 @@ +#include "Point.hpp" +#include "TriangleMesh.hpp" #include "libslic3r/libslic3r.h" #include "Measure.hpp" #include "MeasureUtils.hpp" @@ -6,8 +8,28 @@ #include "libslic3r/SurfaceMesh.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include +#include +#include #define DEBUG_EXTRACT_ALL_FEATURES_AT_ONCE 0 diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 0374c5d4aa..2980afe324 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -1,10 +1,17 @@ #ifndef Slic3r_Measure_hpp_ #define Slic3r_Measure_hpp_ +#include +#include +#include #include #include +#include +#include +#include #include "Point.hpp" +#include "libslic3r.h" struct indexed_triangle_set; diff --git a/src/libslic3r/MeasureUtils.hpp b/src/libslic3r/MeasureUtils.hpp index 2fdac52443..5e34c6fdf8 100644 --- a/src/libslic3r/MeasureUtils.hpp +++ b/src/libslic3r/MeasureUtils.hpp @@ -1,7 +1,14 @@ #ifndef Slic3r_MeasureUtils_hpp_ #define Slic3r_MeasureUtils_hpp_ +#include +#include +#include +#include #include +#include + +#include "Point.hpp" namespace Slic3r { namespace Measure { diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index 4d9dda0c2e..2a05378f58 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -3,6 +3,37 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TryCatchSignal.hpp" #include "libslic3r/format.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #undef PI #include diff --git a/src/libslic3r/MeshBoolean.hpp b/src/libslic3r/MeshBoolean.hpp index c307d1528b..6ced9b4646 100644 --- a/src/libslic3r/MeshBoolean.hpp +++ b/src/libslic3r/MeshBoolean.hpp @@ -1,9 +1,13 @@ #ifndef libslic3r_MeshBoolean_hpp_ #define libslic3r_MeshBoolean_hpp_ +#include +#include "libslic3r/Point.hpp" #include #include #include +#include +#include #include #include diff --git a/src/libslic3r/MeshSplitImpl.hpp b/src/libslic3r/MeshSplitImpl.hpp index 9fa87d2a9e..1805dc36ba 100644 --- a/src/libslic3r/MeshSplitImpl.hpp +++ b/src/libslic3r/MeshSplitImpl.hpp @@ -2,6 +2,15 @@ #define MESHSPLITIMPL_HPP // Disable meaningless boost warning on MSVC +#include +#include "Point.hpp" +#include +#include +#include +#include +#include +#include "libslic3r.h" +#include #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4805 ) diff --git a/src/libslic3r/MinAreaBoundingBox.cpp b/src/libslic3r/MinAreaBoundingBox.cpp index 51fd8a45e7..ccc2eb981b 100644 --- a/src/libslic3r/MinAreaBoundingBox.cpp +++ b/src/libslic3r/MinAreaBoundingBox.cpp @@ -1,5 +1,12 @@ #include "MinAreaBoundingBox.hpp" +#include "Point.hpp" +#include "libslic3r.h" +#include +#include "libnest2d/common.hpp" +#include +#include +#include "libnest2d/geometry_traits.hpp" #include #if defined(_MSC_VER) && defined(__clang__) diff --git a/src/libslic3r/MinimumSpanningTree.cpp b/src/libslic3r/MinimumSpanningTree.cpp index 88555e70ee..0134c6b1a3 100644 --- a/src/libslic3r/MinimumSpanningTree.cpp +++ b/src/libslic3r/MinimumSpanningTree.cpp @@ -1,7 +1,12 @@ #include "MinimumSpanningTree.hpp" +#include #include #include +#include "Point.hpp" +#include +#include +#include #include "libslic3r.h" namespace Slic3r diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index fbc299cf72..24a77ce716 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1,4 +1,21 @@ #include "Model.hpp" +#include "calib.hpp" +#include "Format/STEP.hpp" +#include "TriangleMesh.hpp" +#include "Semver.hpp" +#include "Format/OBJ.hpp" +#include "Config.hpp" +#include "Format/STL.hpp" +#include "Format/objparser.hpp" +#include "CustomGCode.hpp" +#include "PrintConfig.hpp" +#include "ObjectID.hpp" +#include "BoundingBox.hpp" +#include "Point.hpp" +#include "Utils.hpp" +#include "Polygon.hpp" +#include "SLA/SupportPoint.hpp" +#include "TextureDisplacement.hpp" #include "libslic3r.h" #include "BuildVolume.hpp" #include "TexturePainting.hpp" @@ -23,7 +40,17 @@ #include "libslic3r/Geometry/ConvexHull.hpp" +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -35,6 +62,21 @@ #include "SVG.hpp" #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "GCodeWriter.hpp" // BBS: for segment diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 895ea30d09..6ef00c8587 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_Model_hpp_ #define slic3r_Model_hpp_ +#include "BoundingBox.hpp" +#include "Polygon.hpp" +#include "Semver.hpp" #include "libslic3r.h" #include "enum_bitmask.hpp" #include "Geometry.hpp" @@ -30,6 +33,13 @@ #include "Format/OBJ.hpp" #include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 95167565aa..df95b92b99 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -1,9 +1,19 @@ #include "ModelArrange.hpp" +#include +#include +#include #include #include #include +#include "Arrange.hpp" +#include +#include "Config.hpp" +#include +#include #include "MTUtils.hpp" +#include "Point.hpp" +#include "PrintConfig.hpp" namespace Slic3r { diff --git a/src/libslic3r/ModelArrange.hpp b/src/libslic3r/ModelArrange.hpp index e389eea5f0..b7a31dea8d 100644 --- a/src/libslic3r/ModelArrange.hpp +++ b/src/libslic3r/ModelArrange.hpp @@ -1,7 +1,13 @@ #ifndef MODELARRANGE_HPP #define MODELARRANGE_HPP +#include +#include #include +#include +#include "Exception.hpp" +#include +#include "Point.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/Model.hpp" diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 464740768d..9119498a1e 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1,13 +1,40 @@ +#include "MultiMaterialSegmentation.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" +#include "Config.hpp" #include "EdgeGrid.hpp" +#include "Geometry/VoronoiOffset.hpp" +#include "Geometry/Voronoi.hpp" +#include "Flow.hpp" +#include "ExPolygon.hpp" #include "Layer.hpp" +#include "Point.hpp" +#include "Polygon.hpp" +#include "Line.hpp" +#include "Model.hpp" #include "Print.hpp" #include "Geometry/VoronoiVisualUtils.hpp" #include "Geometry/VoronoiUtils.hpp" #include "MutablePolygon.hpp" +#include "Utils.hpp" +#include "PrintConfig.hpp" +#include "TriangleSelector.hpp" +#include "TriangleMeshSlicer.hpp" +#include "Surface.hpp" #include "format.hpp" +#include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -15,6 +42,8 @@ #include #include #include +#include +#include //#define MM_SEGMENTATION_DEBUG_GRAPH //#define MM_SEGMENTATION_DEBUG_REGIONS diff --git a/src/libslic3r/MultiMaterialSegmentation.hpp b/src/libslic3r/MultiMaterialSegmentation.hpp index ee7b07c0d8..6b230e8cad 100644 --- a/src/libslic3r/MultiMaterialSegmentation.hpp +++ b/src/libslic3r/MultiMaterialSegmentation.hpp @@ -1,9 +1,17 @@ #ifndef slic3r_MultiMaterialSegmentation_hpp_ #define slic3r_MultiMaterialSegmentation_hpp_ +#include +#include #include #include +#include + +#include "Line.hpp" +#include "Point.hpp" +#include "libslic3r.h" + namespace Slic3r { class ExPolygon; diff --git a/src/libslic3r/MultiNozzleUtils.cpp b/src/libslic3r/MultiNozzleUtils.cpp index d5ce550536..5fc3d3de17 100644 --- a/src/libslic3r/MultiNozzleUtils.cpp +++ b/src/libslic3r/MultiNozzleUtils.cpp @@ -1,12 +1,22 @@ #include "MultiNozzleUtils.hpp" +#include "PrintConfig.hpp" +#include "Config.hpp" #include "Utils.hpp" #include "ProjectTask.hpp" // Slic3r::FilamentInfo (StaticNozzleGroupResult / load_nozzle_infos_with_compatibility) #include +#include +#include #include +#include +#include +#include #include +#include #include #include #include +#include +#include // Multi-nozzle support. diff --git a/src/libslic3r/MultiNozzleUtils.hpp b/src/libslic3r/MultiNozzleUtils.hpp index 5ae56e497d..f59dad6761 100644 --- a/src/libslic3r/MultiNozzleUtils.hpp +++ b/src/libslic3r/MultiNozzleUtils.hpp @@ -1,6 +1,8 @@ #ifndef MULTI_NOZZLE_UTILS_HPP #define MULTI_NOZZLE_UTILS_HPP +#include +#include #include #include #include diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp index 694d3ea9d0..cda57c6cd8 100644 --- a/src/libslic3r/MultiPoint.cpp +++ b/src/libslic3r/MultiPoint.cpp @@ -1,5 +1,16 @@ #include "MultiPoint.hpp" #include "BoundingBox.hpp" +#include "Point.hpp" +#include "libslic3r.h" +#include +#include "Line.hpp" +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp index 096230d22c..82d6d5884b 100644 --- a/src/libslic3r/MultiPoint.hpp +++ b/src/libslic3r/MultiPoint.hpp @@ -3,6 +3,10 @@ #include "libslic3r.h" #include +#include +#include +#include +#include #include #include "Line.hpp" #include "Point.hpp" diff --git a/src/libslic3r/MutablePolygon.cpp b/src/libslic3r/MutablePolygon.cpp index bdc2d91376..60484dc3aa 100644 --- a/src/libslic3r/MutablePolygon.cpp +++ b/src/libslic3r/MutablePolygon.cpp @@ -1,6 +1,11 @@ #include "MutablePolygon.hpp" #include "Line.hpp" +#include "Point.hpp" #include "libslic3r.h" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/MutablePolygon.hpp b/src/libslic3r/MutablePolygon.hpp index e4741186ff..31322583e3 100644 --- a/src/libslic3r/MutablePolygon.hpp +++ b/src/libslic3r/MutablePolygon.hpp @@ -4,6 +4,13 @@ #include "Point.hpp" #include "Polygon.hpp" #include "ExPolygon.hpp" +#include +#include +#include +#include +#include +#include +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/MutablePriorityQueue.hpp b/src/libslic3r/MutablePriorityQueue.hpp index 2565f417f8..f06acaa93e 100644 --- a/src/libslic3r/MutablePriorityQueue.hpp +++ b/src/libslic3r/MutablePriorityQueue.hpp @@ -2,7 +2,11 @@ #define slic3r_MutablePriorityQueue_hpp_ #include +#include +#include #include +#include +#include constexpr auto InvalidQueueID = std::numeric_limits::max(); template class MutablePriorityQueue diff --git a/src/libslic3r/NSVGUtils.cpp b/src/libslic3r/NSVGUtils.cpp index e27a6738e2..5274ffad4f 100644 --- a/src/libslic3r/NSVGUtils.cpp +++ b/src/libslic3r/NSVGUtils.cpp @@ -1,11 +1,24 @@ #include "NSVGUtils.hpp" #include +#include #include // to_chars #include #include +#include +#include +#include +#include +#include +#include +#include #include "ClipperUtils.hpp" #include "Emboss.hpp" // heal for shape +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "EmbossShape.hpp" +#include "Point.hpp" +#include "libslic3r.h" namespace { using namespace Slic3r; // Polygon @@ -500,26 +513,26 @@ Polylines to_dashes(const Polyline &polyline, const DashesParam& param) HealedExPolygons stroke_to_expolygons(const LinesPath &lines_path, const NSVGshape &shape, const NSVGLineParams ¶m) { // convert stroke to polygon - ClipperLib::JoinType join_type = ClipperLib::JoinType::jtSquare; + JoinType join_type = jtSquare; switch (static_cast(shape.strokeLineJoin)) { - case NSVGlineJoin::NSVG_JOIN_BEVEL: join_type = ClipperLib::JoinType::jtSquare; break; - case NSVGlineJoin::NSVG_JOIN_MITER: join_type = ClipperLib::JoinType::jtMiter; break; - case NSVGlineJoin::NSVG_JOIN_ROUND: join_type = ClipperLib::JoinType::jtRound; break; + case NSVGlineJoin::NSVG_JOIN_BEVEL: join_type = jtSquare; break; + case NSVGlineJoin::NSVG_JOIN_MITER: join_type = jtMiter; break; + case NSVGlineJoin::NSVG_JOIN_ROUND: join_type = jtRound; break; } double mitter = shape.miterLimit * param.scale; - if (join_type == ClipperLib::JoinType::jtRound) { + if (join_type == jtRound) { // mitter is used as ArcTolerance // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/Properties/ArcTolerance.htm mitter = std::pow(param.tesselation_tolerance, 1/3.); } float stroke_width = static_cast(shape.strokeWidth * param.scale); - ClipperLib::EndType end_type = ClipperLib::EndType::etOpenButt; + EndType end_type = etOpenButt; switch (static_cast(shape.strokeLineCap)) { - case NSVGlineCap::NSVG_CAP_BUTT: end_type = ClipperLib::EndType::etOpenButt; break; - case NSVGlineCap::NSVG_CAP_ROUND: end_type = ClipperLib::EndType::etOpenRound; break; - case NSVGlineCap::NSVG_CAP_SQUARE: end_type = ClipperLib::EndType::etOpenSquare; break; + case NSVGlineCap::NSVG_CAP_BUTT: end_type = etOpenButt; break; + case NSVGlineCap::NSVG_CAP_ROUND: end_type = etOpenRound; break; + case NSVGlineCap::NSVG_CAP_SQUARE: end_type = etOpenSquare; break; } Polygons result; diff --git a/src/libslic3r/NSVGUtils.hpp b/src/libslic3r/NSVGUtils.hpp index 8d6a3bc3ef..846c4adfb8 100644 --- a/src/libslic3r/NSVGUtils.hpp +++ b/src/libslic3r/NSVGUtils.hpp @@ -1,12 +1,16 @@ #ifndef slic3r_NSVGUtils_hpp_ #define slic3r_NSVGUtils_hpp_ +#include +#include #include #include #include +#include "Point.hpp" #include "Polygon.hpp" #include "ExPolygon.hpp" #include "EmbossShape.hpp" // ExPolygonsWithIds +#include "libslic3r.h" #include "nanosvg/nanosvg.h" // load SVG file // Helper function to work with nano svg diff --git a/src/libslic3r/NormalUtils.cpp b/src/libslic3r/NormalUtils.cpp index 8619b749a2..1499d25f22 100644 --- a/src/libslic3r/NormalUtils.cpp +++ b/src/libslic3r/NormalUtils.cpp @@ -1,4 +1,9 @@ #include "NormalUtils.hpp" +#include "Point.hpp" +#include +#include +#include +#include using namespace Slic3r; diff --git a/src/libslic3r/NormalUtils.hpp b/src/libslic3r/NormalUtils.hpp index 8dcd0c0290..1811957381 100644 --- a/src/libslic3r/NormalUtils.hpp +++ b/src/libslic3r/NormalUtils.hpp @@ -3,6 +3,7 @@ #include "Point.hpp" #include "Model.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/ObjColorUtils.cpp b/src/libslic3r/ObjColorUtils.cpp index 3761267401..536078a083 100644 --- a/src/libslic3r/ObjColorUtils.cpp +++ b/src/libslic3r/ObjColorUtils.cpp @@ -1,4 +1,6 @@ #include "ObjColorUtils.hpp" +#include +#include "Color.hpp" bool obj_color_deal_algo(std::vector & input_colors, std::vector & cluster_colors_from_algo, diff --git a/src/libslic3r/ObjColorUtils.hpp b/src/libslic3r/ObjColorUtils.hpp index b587c80848..46163c8b44 100644 --- a/src/libslic3r/ObjColorUtils.hpp +++ b/src/libslic3r/ObjColorUtils.hpp @@ -1,6 +1,13 @@ #pragma once +#include +#include #include #include +#include +#include +#include +#include +#include #include "opencv2/opencv.hpp" #include "libslic3r/Color.hpp" diff --git a/src/libslic3r/ObjectID.cpp b/src/libslic3r/ObjectID.cpp index 7177c47fec..c8f4f5409f 100644 --- a/src/libslic3r/ObjectID.cpp +++ b/src/libslic3r/ObjectID.cpp @@ -1,4 +1,5 @@ #include "ObjectID.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/ObjectID.hpp b/src/libslic3r/ObjectID.hpp index 56042bbaa3..6adc1078f0 100644 --- a/src/libslic3r/ObjectID.hpp +++ b/src/libslic3r/ObjectID.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/OpenVDBUtils.cpp b/src/libslic3r/OpenVDBUtils.cpp index c72607f14f..d4ac09781d 100644 --- a/src/libslic3r/OpenVDBUtils.cpp +++ b/src/libslic3r/OpenVDBUtils.cpp @@ -1,6 +1,19 @@ #ifndef NOMINMAX #define NOMINMAX #endif + +#include +#include +#include +#include "Point.hpp" +#include +#include +#include +#include "TriangleMesh.hpp" +#include +#include "libslic3r.h" +#include +#include #include "OpenVDBUtils.hpp" #ifdef _MSC_VER diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp index f4441ba964..badd19d377 100644 --- a/src/libslic3r/OpenVDBUtils.hpp +++ b/src/libslic3r/OpenVDBUtils.hpp @@ -1,7 +1,10 @@ #ifndef OPENVDBUTILS_HPP #define OPENVDBUTILS_HPP +#include "Point.hpp" #include +#include +#include #ifdef _MSC_VER // Suppress warning C4146 in include/gmp.h(2177,31): unary minus operator applied to unsigned type, result still unsigned diff --git a/src/libslic3r/Optimize/BruteforceOptimizer.hpp b/src/libslic3r/Optimize/BruteforceOptimizer.hpp index 2daef538e7..6aa4308f99 100644 --- a/src/libslic3r/Optimize/BruteforceOptimizer.hpp +++ b/src/libslic3r/Optimize/BruteforceOptimizer.hpp @@ -1,7 +1,12 @@ #ifndef BRUTEFORCEOPTIMIZER_HPP #define BRUTEFORCEOPTIMIZER_HPP +#include +#include +#include +#include #include +#include namespace Slic3r { namespace opt { diff --git a/src/libslic3r/Optimize/NLoptOptimizer.hpp b/src/libslic3r/Optimize/NLoptOptimizer.hpp index f5d3140463..6e1649f701 100644 --- a/src/libslic3r/Optimize/NLoptOptimizer.hpp +++ b/src/libslic3r/Optimize/NLoptOptimizer.hpp @@ -1,6 +1,12 @@ #ifndef NLOPTOPTIMIZER_HPP #define NLOPTOPTIMIZER_HPP +#include +#include +#include +#include +#include +#include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4244) diff --git a/src/libslic3r/Optimize/Optimizer.hpp b/src/libslic3r/Optimize/Optimizer.hpp index 8ae55c61c5..ce5bb5bad6 100644 --- a/src/libslic3r/Optimize/Optimizer.hpp +++ b/src/libslic3r/Optimize/Optimizer.hpp @@ -1,6 +1,7 @@ #ifndef OPTIMIZER_HPP #define OPTIMIZER_HPP +#include #include #include #include diff --git a/src/libslic3r/Orient.cpp b/src/libslic3r/Orient.cpp index 7d54048176..b72401f36b 100644 --- a/src/libslic3r/Orient.cpp +++ b/src/libslic3r/Orient.cpp @@ -1,10 +1,30 @@ #include "Orient.hpp" #include "Geometry.hpp" +#include +#include +#include +#include "TriangleMesh.hpp" +#include "Point.hpp" +#include +#include +#include "libslic3r.h" +#include +#include +#include +#include +#include "Model.hpp" +#include "PrintConfig.hpp" #include #include #include #include +#include +#include +#include #include +#include +#include +#include #if defined(_MSC_VER) && defined(__clang__) #define BOOST_NO_CXX17_HDR_STRING_VIEW diff --git a/src/libslic3r/Orient.hpp b/src/libslic3r/Orient.hpp index 370f23d4fb..6839665e01 100644 --- a/src/libslic3r/Orient.hpp +++ b/src/libslic3r/Orient.hpp @@ -1,7 +1,14 @@ #ifndef ORIENT_HPP #define ORIENT_HPP +#include "TriangleMesh.hpp" +#include "Point.hpp" +#include "PrintConfig.hpp" #include "libslic3r/Model.hpp" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/PNGReadWrite.cpp b/src/libslic3r/PNGReadWrite.cpp index 9f6a8b739d..1f29de646b 100644 --- a/src/libslic3r/PNGReadWrite.cpp +++ b/src/libslic3r/PNGReadWrite.cpp @@ -1,5 +1,9 @@ #include "PNGReadWrite.hpp" +#include +#include +#include +#include #include #include @@ -8,6 +12,8 @@ #include #include #include +#include +#include namespace Slic3r { namespace png { diff --git a/src/libslic3r/PNGReadWrite.hpp b/src/libslic3r/PNGReadWrite.hpp index 9a27fed490..c2d2149e1f 100644 --- a/src/libslic3r/PNGReadWrite.hpp +++ b/src/libslic3r/PNGReadWrite.hpp @@ -1,6 +1,8 @@ #ifndef PNGREAD_HPP #define PNGREAD_HPP +#include +#include #include #include #include diff --git a/src/libslic3r/ParameterUtils.cpp b/src/libslic3r/ParameterUtils.cpp index 2e7b0d1d3c..f2f3669124 100644 --- a/src/libslic3r/ParameterUtils.cpp +++ b/src/libslic3r/ParameterUtils.cpp @@ -1,5 +1,10 @@ #include "ParameterUtils.hpp" +#include "PrintConfig.hpp" #include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ParameterUtils.hpp b/src/libslic3r/ParameterUtils.hpp index 795e7ff619..bf475c16bd 100644 --- a/src/libslic3r/ParameterUtils.hpp +++ b/src/libslic3r/ParameterUtils.hpp @@ -1,6 +1,8 @@ #ifndef slic3r_Parameter_Utils_hpp_ #define slic3r_Parameter_Utils_hpp_ +#include +#include #include #include #include "PrintConfig.hpp" diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1f1f1289e5..5b775f7e25 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -1,22 +1,41 @@ #include "PerimeterGenerator.hpp" #include "AABBTreeLines.hpp" +#include "Arachne/utils/ExtrusionLine.hpp" +#include "Arachne/utils/ExtrusionJunction.hpp" #include "BridgeDetector.hpp" #include "ClipperUtils.hpp" +#include "ClipperZUtils.hpp" +#include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" #include "Feature/FuzzySkin/FuzzySkin.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "Point.hpp" +#include "Flow.hpp" #include "PrintConfig.hpp" #include "ShortestPath.hpp" +#include "Surface.hpp" #include "VariableWidth.hpp" #include "Arachne/WallToolPaths.hpp" #include "Geometry/ConvexHull.hpp" #include "ExPolygonCollection.hpp" #include "Geometry.hpp" #include "Line.hpp" +#include #include #include +#include +#include +#include +#include +#include +#include #include #include +#include +#include "libslic3r.h" +#include #include "libslic3r/AABBTreeLines.hpp" #include "Print.hpp" static const int overhang_sampling_number = 6; @@ -296,13 +315,12 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime return out; } -static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, const ClipperLib_Z::Paths& clip, ClipperLib_Z::ClipType clipType) +static ClipperZUtils::ZPaths clip_extrusion(const ClipperZUtils::ZPath& subject, const ClipperZUtils::ZPaths& clip, ClipType clipType) { - ClipperLib_Z::Clipper clipper; - clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, - const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) { - ClipperLib_Z::IntPoint start = e1bot; - ClipperLib_Z::IntPoint end = e1top; + auto zfill = [](const ClipperZUtils::ZPoint& e1bot, const ClipperZUtils::ZPoint& e1top, const ClipperZUtils::ZPoint& e2bot, + const ClipperZUtils::ZPoint& e2top, ClipperZUtils::ZPoint& pt) { + ClipperZUtils::ZPoint start = e1bot; + ClipperZUtils::ZPoint end = e1top; if (start.z() <= 0 && end.z() <= 0) { start = e2bot; @@ -317,23 +335,15 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con double t = std::sqrt(dist_sqr / length_sqr); pt.z() = start.z() + coord_t((end.z() - start.z()) * t); - }); + }; - clipper.AddPath(subject, ClipperLib_Z::ptSubject, false); - clipper.AddPaths(clip, ClipperLib_Z::ptClip, true); - - ClipperLib_Z::Paths clipped_paths; - { - ClipperLib_Z::PolyTree clipped_polytree; - clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); - ClipperLib_Z::PolyTreeToPaths(std::move(clipped_polytree), clipped_paths); - } + ClipperZUtils::ZPaths clipped_paths = ClipperZUtils::clip_zpaths(clipType, ClipperZUtils::ZPaths{ subject }, true, clip, zfill); // Clipped path could contain vertices from the clip with a Z coordinate equal to zero. // For those vertices, we must assign value based on the subject. // This happens only in sporadic cases. - for (ClipperLib_Z::Path& path : clipped_paths) - for (ClipperLib_Z::IntPoint& c_pt : path) + for (ClipperZUtils::ZPath& path : clipped_paths) + for (ClipperZUtils::ZPoint& c_pt : path) if (c_pt.z() == 0) { // Now we must find the corresponding line on with this point is located and compute line width (Z coordinate). if (subject.size() <= 2) @@ -366,8 +376,8 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con } assert([&clipped_paths = std::as_const(clipped_paths)]() -> bool { - for (const ClipperLib_Z::Path& path : clipped_paths) - for (const ClipperLib_Z::IntPoint& pt : path) + for (const ClipperZUtils::ZPath& path : clipped_paths) + for (const ClipperZUtils::ZPoint& pt : path) if (pt.z() <= 0) return false; return true; @@ -376,7 +386,7 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, con return clipped_paths; } -static double clipper_z_path_length(const ClipperLib_Z::Path &path) +static double clipper_z_path_length(const ClipperZUtils::ZPath &path) { double len = 0.; for (size_t i = 1; i < path.size(); ++ i) @@ -413,7 +423,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p ExtrusionPaths paths; // detect overhanging/bridging perimeters if (perimeter_generator.config->detect_overhang_wall && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers) { - ClipperLib_Z::Path extrusion_path; + ClipperZUtils::ZPath extrusion_path; extrusion_path.reserve(extrusion->size()); BoundingBox extrusion_path_bbox; for (const Arachne::ExtrusionJunction &ej : extrusion->junctions) { @@ -421,7 +431,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p extrusion_path_bbox.merge(Point(ej.p.x(), ej.p.y())); } - ClipperLib_Z::Paths lower_slices_paths; + ClipperZUtils::ZPaths lower_slices_paths; { lower_slices_paths.reserve(perimeter_generator.lower_slices_polygons().size()); Points clipped; @@ -431,7 +441,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p ClipperUtils::clip_clipper_polygon_with_subject_bbox(poly.points, extrusion_path_bbox, clipped); if (!clipped.empty()) { lower_slices_paths.emplace_back(); - ClipperLib_Z::Path &out = lower_slices_paths.back(); + ClipperZUtils::ZPath &out = lower_slices_paths.back(); out.reserve(clipped.size()); for (const Point &pt : clipped) out.emplace_back(pt.x(), pt.y(), 0); @@ -440,7 +450,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p } // get non-overhang paths by intersecting this loop with the grown lower slices - extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role, + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ctIntersection), role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); // Always reverse extrusion if use fuzzy skin: https://github.com/OrcaSlicer/OrcaSlicer/pull/2413#issuecomment-1769735357 @@ -481,7 +491,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p // get overhang paths by checking what parts of this loop fall // outside the grown lower slices (thus where the distance between // the loop centerline and original lower slices is >= half nozzle diameter - extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter, + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ctDifference), erOverhangPerimeter, perimeter_generator.overhang_flow); // Reapply the nearest point search for starting point. @@ -674,10 +684,10 @@ static void clip_inner_walls_over_top(std::vector & }; // Pull the cut back by half a wall width: the clip severs the centerline, but the bead's rounded end // extends half a width past its endpoint and would otherwise overlap the top fill. - ClipperLib_Z::Paths top_paths_z; + ClipperZUtils::ZPaths top_paths_z; for (const Polygon &poly : to_polygons(offset_ex(top_region, float(perimeter_width) / 2.f))) { top_paths_z.emplace_back(); - ClipperLib_Z::Path &out = top_paths_z.back(); + ClipperZUtils::ZPath &out = top_paths_z.back(); out.reserve(poly.points.size()); for (const Point &pt : poly.points) out.emplace_back(pt.x(), pt.y(), 0); @@ -695,21 +705,21 @@ static void clip_inner_walls_over_top(std::vector & } if (overlap == TopOverlap::Full) continue; // the clip below would return nothing anyway - ClipperLib_Z::Path subject; + ClipperZUtils::ZPath subject; subject.reserve(el.size()); for (const Arachne::ExtrusionJunction &j : el.junctions) subject.emplace_back(j.p.x(), j.p.y(), j.w); - ClipperLib_Z::Paths pieces = clip_extrusion(subject, top_paths_z, ClipperLib_Z::ctDifference); + ClipperZUtils::ZPaths pieces = clip_extrusion(subject, top_paths_z, ctDifference); // Clipper treats the subject as an open polyline, so it also cuts a closed loop at its (arbitrary) // start vertex and may reverse pieces. Stitch pieces sharing an endpoint back together. - auto same_pt = [](const ClipperLib_Z::IntPoint &p, const ClipperLib_Z::IntPoint &q) { + auto same_pt = [](const ClipperZUtils::ZPoint &p, const ClipperZUtils::ZPoint &q) { return std::abs(p.x() - q.x()) <= SCALED_EPSILON && std::abs(p.y() - q.y()) <= SCALED_EPSILON; }; for (size_t i = 0; i < pieces.size(); ++ i) { for (size_t j = i + 1; j < pieces.size();) { - ClipperLib_Z::Path &a = pieces[i]; - ClipperLib_Z::Path &b = pieces[j]; + ClipperZUtils::ZPath &a = pieces[i]; + ClipperZUtils::ZPath &b = pieces[j]; if (same_pt(a.front(), b.front()) || same_pt(a.front(), b.back())) std::reverse(a.begin(), a.end()); if (same_pt(a.back(), b.back())) @@ -726,7 +736,7 @@ static void clip_inner_walls_over_top(std::vector & // If the clip removed next to nothing, keep the loop untouched instead of slitting it open. The // half-width pull-back above already costs about one width per crossing, hence two widths. double kept_length = 0.; - for (const ClipperLib_Z::Path &path : pieces) + for (const ClipperZUtils::ZPath &path : pieces) kept_length += clipper_z_path_length(path); if (clipper_z_path_length(subject) - kept_length < 2. * double(perimeter_width)) { append(kept_over_top, covered_by(el)); @@ -734,10 +744,10 @@ static void clip_inner_walls_over_top(std::vector & continue; } - for (const ClipperLib_Z::Path &path : pieces) { + for (const ClipperZUtils::ZPath &path : pieces) { Arachne::ExtrusionLine clipped(el.inset_idx, el.is_odd); clipped.junctions.reserve(path.size()); - for (const ClipperLib_Z::IntPoint &pt : path) + for (const ClipperZUtils::ZPoint &pt : path) clipped.junctions.emplace_back(Point(pt.x(), pt.y()), coord_t(pt.z()), el.inset_idx); // Discard tiny leftovers that would print as zits. if (clipped.size() >= 2 && clipped.getLength() >= perimeter_width) @@ -1056,7 +1066,7 @@ ExtrusionPaths sort_extra_perimeters(const ExtrusionPaths& extra_perims, int ind return filtered; } -#define EXTRA_PERIMETER_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +#define EXTRA_PERIMETER_OFFSET_PARAMETERS jtSquare, 0. // #define EXTRA_PERIM_DEBUG_FILES // Function will generate extra perimeters clipped over nonbridgeable areas of the provided surface and returns both the new perimeters and // Polygons filled by those clipped perimeters diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index cd49b4acdd..c4d5b06095 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -1,8 +1,15 @@ #ifndef slic3r_PerimeterGenerator_hpp_ #define slic3r_PerimeterGenerator_hpp_ +#include "ExtrusionEntityCollection.hpp" +#include "Point.hpp" +#include "Surface.hpp" #include "libslic3r.h" +#include +#include +#include #include +#include #include #include "Layer.hpp" #include "Flow.hpp" diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 1d7abcd5de..8bddfc1f10 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1,12 +1,52 @@ #include "PlaceholderParser.hpp" +#include "Config.hpp" #include "Exception.hpp" #include "Flow.hpp" +#include "PrintConfig.hpp" +#include "Point.hpp" #include "Utils.hpp" +#include "libslic3r_version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include #include #include +#include +#include #ifdef _MSC_VER #include // provides **_environ #else diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp index e32a4de9dc..962517a252 100644 --- a/src/libslic3r/PlaceholderParser.hpp +++ b/src/libslic3r/PlaceholderParser.hpp @@ -1,8 +1,10 @@ #ifndef slic3r_PlaceholderParser_hpp_ #define slic3r_PlaceholderParser_hpp_ +#include "Config.hpp" #include "libslic3r.h" #include +#include #include #include #include diff --git a/src/libslic3r/Platform.cpp b/src/libslic3r/Platform.cpp index d2ca27fa96..35a30712d9 100644 --- a/src/libslic3r/Platform.cpp +++ b/src/libslic3r/Platform.cpp @@ -2,6 +2,11 @@ #include #include +#include +#include +#include +#include +#include #if defined(__APPLE__) #include diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index 9a2c2b14cd..e3ac888ede 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -5,7 +5,14 @@ #include "Polyline.hpp" #include "Int128.hpp" #include "BoundingBox.hpp" +#include +#include "libslic3r.h" #include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 21e5355fc5..6b8c1a81d7 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -2,7 +2,18 @@ #define slic3r_Point_hpp_ #include "libslic3r.h" +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 77ff30fb40..d7591ae27c 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -2,9 +2,22 @@ #include "ClipperUtils.hpp" #include "Exception.hpp" #include "Polygon.hpp" +#include "Line.hpp" +#include "Point.hpp" +#include "MultiPoint.hpp" #include "Polyline.hpp" +#include "libslic3r.h" +#include +#include +#include #include +#include +#include +#include +#include +#include +#include namespace Slic3r { @@ -70,7 +83,7 @@ double Polygon::area() const bool Polygon::is_counter_clockwise() const { - return ClipperLib::Orientation(this->points); + return this->area() >= 0.; } bool Polygon::is_clockwise() const @@ -678,7 +691,7 @@ void remove_collinear(Polygons &polys) remove_collinear(poly); } -Polygons polygons_simplify(const Polygons &source_polygons, double tolerance, bool strictly_simple /* = true */) +Polygons polygons_simplify(const Polygons &source_polygons, double tolerance) { Polygons out; out.reserve(source_polygons.size()); @@ -687,13 +700,15 @@ Polygons polygons_simplify(const Polygons &source_polygons, double tolerance, bo Points simplified = MultiPoint::_douglas_peucker(to_polyline(source_polygon).points, tolerance); // then remove the last (repeated) point. simplified.pop_back(); - // Simplify the decimated contour by ClipperLib. - bool ccw = ClipperLib::Area(simplified) > 0.; - for (Points &path : ClipperLib::SimplifyPolygons(ClipperUtils::SinglePathProvider(simplified), ClipperLib::pftNonZero, strictly_simple)) { + // Simplify the decimated contour by a union. + bool ccw = Polygon::area(simplified) > 0.; + Polygons decimated(1); + decimated.front().points = std::move(simplified); + for (Polygon &polygon : union_(decimated)) { if (! ccw) - // ClipperLib likely reoriented negative area contours to become positive. Reverse holes back to CW. - std::reverse(path.begin(), path.end()); - out.emplace_back(std::move(path)); + // The union reorients negative area contours to become positive. Reverse holes back to CW. + polygon.reverse(); + out.emplace_back(std::move(polygon)); } } return out; @@ -728,9 +743,40 @@ bool overlaps(const Polygons& polys1, const Polygons& polys2) return false; } +// Clipper1's PointInPolygon(): 1 inside, 0 outside, -1 on the boundary. +static int point_in_polygon(const Point &pt, const Points &path) +{ + int result = 0; + size_t cnt = path.size(); + if (cnt < 3) return 0; + Point ip = path[0]; + for (size_t i = 1; i <= cnt; ++i) { + Point ipNext = (i == cnt ? path[0] : path[i]); + if (ipNext.y() == pt.y() && ((ipNext.x() == pt.x()) || (ip.y() == pt.y() && ((ipNext.x() > pt.x()) == (ip.x() < pt.x()))))) + return -1; + if ((ip.y() < pt.y()) != (ipNext.y() < pt.y())) { + if (ip.x() >= pt.x()) { + if (ipNext.x() > pt.x()) + result = 1 - result; + else { + int64_t d = int64_t(ip.x() - pt.x()) * int64_t(ipNext.y() - pt.y()) - int64_t(ipNext.x() - pt.x()) * int64_t(ip.y() - pt.y()); + if (! d) return -1; + if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result; + } + } else if (ipNext.x() > pt.x()) { + int64_t d = int64_t(ip.x() - pt.x()) * int64_t(ipNext.y() - pt.y()) - int64_t(ipNext.x() - pt.x()) * int64_t(ip.y() - pt.y()); + if (! d) return -1; + if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result; + } + } + ip = ipNext; + } + return result; +} + bool contains(const Polygon &polygon, const Point &p, bool border_result) { - if (const int poly_count_inside = ClipperLib::PointInPolygon(p, polygon.points); + if (const int poly_count_inside = point_in_polygon(p, polygon.points); poly_count_inside == -1) return border_result; else @@ -741,7 +787,7 @@ bool contains(const Polygons &polygons, const Point &p, bool border_result) { int poly_count_inside = 0; for (const Polygon &poly : polygons) { - const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly.points); + const int is_inside_this_poly = point_in_polygon(p, poly.points); if (is_inside_this_poly == -1) return border_result; poly_count_inside += is_inside_this_poly; diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 34ca214cf3..ae312fd830 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -2,6 +2,13 @@ #define slic3r_Polygon_hpp_ #include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include #include #include #include "Line.hpp" @@ -159,7 +166,7 @@ inline void polygons_append(Polygons &dst, Polygons &&src) } } -Polygons polygons_simplify(const Polygons &polys, double tolerance, bool strictly_simple = true); +Polygons polygons_simplify(const Polygons &polys, double tolerance); inline void polygons_rotate(Polygons &polys, double angle) { diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp index 2c4e06fc58..a9cdafc73b 100644 --- a/src/libslic3r/PolygonTrimmer.cpp +++ b/src/libslic3r/PolygonTrimmer.cpp @@ -1,6 +1,11 @@ #include "PolygonTrimmer.hpp" #include "EdgeGrid.hpp" #include "Geometry.hpp" +#include "Polygon.hpp" +#include +#include "Point.hpp" +#include "libslic3r.h" +#include namespace Slic3r { diff --git a/src/libslic3r/PolygonTrimmer.hpp b/src/libslic3r/PolygonTrimmer.hpp index 93e94e303f..4f0608169b 100644 --- a/src/libslic3r/PolygonTrimmer.hpp +++ b/src/libslic3r/PolygonTrimmer.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_PolygonTrimmer_hpp_ #define slic3r_PolygonTrimmer_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include #include diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp index 98a5366ecf..278522bfd9 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -1,11 +1,21 @@ +#include "ArcFitter.hpp" #include "BoundingBox.hpp" #include "Polyline.hpp" #include "Exception.hpp" #include "ExPolygon.hpp" #include "Line.hpp" +#include "Point.hpp" +#include "MultiPoint.hpp" #include "Polygon.hpp" +#include +#include +#include +#include "libslic3r.h" +#include #include +#include #include +#include namespace Slic3r { diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index f52c3c9bbd..29c795db33 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -1,10 +1,16 @@ #ifndef slic3r_Polyline_hpp_ #define slic3r_Polyline_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include "Line.hpp" #include "MultiPoint.hpp" +#include +#include +#include +#include #include +#include #include //BBS: new necessary header file #include "ArcFitter.hpp" diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 9ba142dd21..5c87b6b03e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1,4 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "Config.hpp" #include "Exception.hpp" @@ -7,6 +33,9 @@ #include "AppConfig.hpp" #include "LocalesUtils.hpp" #include "ParallelResolve.hpp" +#include "Semver.hpp" +#include "PrintConfig.hpp" +#include "libslic3r_version.h" #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 0134681f9f..2b1fb372af 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -1,7 +1,13 @@ #ifndef slic3r_Preset_hpp_ #define slic3r_Preset_hpp_ +#include +#include +#include +#include #include +#include +#include #include #include #include @@ -12,10 +18,14 @@ #include #include #include +#include +#include +#include "Config.hpp" #include "PrintConfig.hpp" #include "Semver.hpp" #include "ProjectTask.hpp" +#include "libslic3r.h" //BBS: change system directories #define PRESET_SYSTEM_DIR "system" diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index c7c31918a5..87ffa1a822 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -1,16 +1,45 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "PresetBundle.hpp" +#include "Config.hpp" +#include "Exception.hpp" +#include "AppConfig.hpp" #include "ParallelResolve.hpp" +#include "Preset.hpp" #include "PresetCacheFormat.hpp" #include "PrintConfig.hpp" #include "PublishSettings.hpp" #include "FilamentMixer.hpp" +#include "Semver.hpp" #include "libslic3r.h" #include "I18N.hpp" #include "Utils.hpp" @@ -25,6 +54,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -43,6 +77,8 @@ #include #include #include +#include +#include // Mark string for localization and translate. #define L(s) Slic3r::I18N::translate(s) diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index e09ce9dcb5..46d81a9052 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -1,16 +1,23 @@ #ifndef slic3r_PresetBundle_hpp_ #define slic3r_PresetBundle_hpp_ +#include "Config.hpp" #include "Preset.hpp" #include "PresetCacheFormat.hpp" #include "AppConfig.hpp" +#include "PrintConfig.hpp" #include "PublishSettings.hpp" +#include "Semver.hpp" #include "enum_bitmask.hpp" +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -18,6 +25,8 @@ #include #include #include +#include +#include #define DEFAULT_USER_FOLDER_NAME "default" #define BUNDLE_STRUCTURE_JSON_NAME "bundle_structure.json" diff --git a/src/libslic3r/PresetCacheFormat.cpp b/src/libslic3r/PresetCacheFormat.cpp index a45bcb77ac..01e634a581 100644 --- a/src/libslic3r/PresetCacheFormat.cpp +++ b/src/libslic3r/PresetCacheFormat.cpp @@ -1,9 +1,20 @@ #include "libslic3r/PresetCacheFormat.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include #include #include @@ -14,7 +25,12 @@ #include #include #include +#include +#include "Config.hpp" +#include "PrintConfig.hpp" +#include "Semver.hpp" +#include "Preset.hpp" #include "libslic3r/Utils.hpp" namespace Slic3r { diff --git a/src/libslic3r/PresetCacheFormat.hpp b/src/libslic3r/PresetCacheFormat.hpp index 52c40bea21..8ad1c5bde5 100644 --- a/src/libslic3r/PresetCacheFormat.hpp +++ b/src/libslic3r/PresetCacheFormat.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_PresetCacheFormat_hpp_ #define slic3r_PresetCacheFormat_hpp_ +#include #include #include #include diff --git a/src/libslic3r/PrincipalComponents2D.cpp b/src/libslic3r/PrincipalComponents2D.cpp index 7bdf793157..6d88320286 100644 --- a/src/libslic3r/PrincipalComponents2D.cpp +++ b/src/libslic3r/PrincipalComponents2D.cpp @@ -1,5 +1,11 @@ #include "PrincipalComponents2D.hpp" #include "Point.hpp" +#include +#include +#include "Polygon.hpp" +#include +#include "libslic3r.h" +#include namespace Slic3r { diff --git a/src/libslic3r/PrincipalComponents2D.hpp b/src/libslic3r/PrincipalComponents2D.hpp index dc8897a7a7..adf8e77a20 100644 --- a/src/libslic3r/PrincipalComponents2D.hpp +++ b/src/libslic3r/PrincipalComponents2D.hpp @@ -3,7 +3,9 @@ #include "AABBTreeLines.hpp" #include "BoundingBox.hpp" +#include "Point.hpp" #include "libslic3r.h" +#include #include #include "Polygon.hpp" diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 5f5592cfce..bb91441c79 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -3,6 +3,56 @@ // needs the Win32 types declared already. #include #endif + +#include "PrintBase.hpp" +#include +#include +#include +#include +#include "libslic3r.h" +#include "calib.hpp" +#include +#include "CustomGCode.hpp" +#include "ObjectID.hpp" +#include +#include "Point.hpp" +#include "Polygon.hpp" +#include "Geometry.hpp" +#include +#include +#include +#include +#include "Slicing.hpp" +#include +#include "TriangleSelector.hpp" +#include "GCode/AdaptivePAProcessor.hpp" +#include +#include +#include "ExPolygon.hpp" +#include "Layer.hpp" +#include "FilamentGroup.hpp" +#include +#include "FilamentGroupUtils.hpp" +#include "MultiNozzleUtils.hpp" +#include +#include +#include "GCode/GCodeProcessor.hpp" +#include "GCode/ThumbnailData.hpp" +#include "ExtrusionEntity.hpp" +#include +#include "CommonDefs.hpp" +#include +#include +#include +#include "Surface.hpp" +#include "Circle.hpp" +#include "Polyline.hpp" +#include "ArcFitter.hpp" +#include +#include +#include +#include +#include "TriangleMesh.hpp" #include "Config.hpp" #include "Exception.hpp" #include "Print.hpp" @@ -3489,7 +3539,7 @@ void Print::_make_skirt() Polygon loop; { // Orca: the hull already represents the occupied outline used for this skirt. - Polygons loops = offset(hull, distance, ClipperLib::jtRound, float(scale_(0.1))); + Polygons loops = offset(hull, distance, jtRound, float(scale_(0.1))); Geometry::simplify_polygons(loops, scale_(0.05), &loops); if (loops.empty()) break; @@ -3526,7 +3576,7 @@ void Print::_make_skirt() } if (collect_skirt_hull) - for (Polygon &poly : offset(hull, distance + 0.5f * float(scale_(spacing)), ClipperLib::jtRound, float(scale_(0.1)))) + for (Polygon &poly : offset(hull, distance + 0.5f * float(scale_(spacing)), jtRound, float(scale_(0.1)))) append(m_skirt_convex_hull, std::move(poly.points)); }; @@ -3632,7 +3682,7 @@ void Print::_make_skirt() if (group.emits_skirt) { // Orca: If the expanded skirt outline touches another group // or obstacle, merge them and run the pass again. - Polygons envelopes = offset(envelope, grouping_offset, ClipperLib::jtRound, float(scale_(0.1))); + Polygons envelopes = offset(envelope, grouping_offset, jtRound, float(scale_(0.1))); if (envelopes.empty()) continue; envelope = std::move(envelopes.front()); @@ -4298,10 +4348,11 @@ Polygons Print::get_extruder_shared_printable_polygon() const return shared_printable_polys; } -// Narrow the stored grouping result to the layer-aware type the slicing pipeline uses. -std::shared_ptr Print::get_layered_nozzle_group_result() const +void Print::set_nozzle_group_result(std::shared_ptr result) { - return std::dynamic_pointer_cast(m_nozzle_group_result); + m_nozzle_group_result = std::move(result); + m_layered_nozzle_group_result = std::dynamic_pointer_cast(m_nozzle_group_result); + ++m_config_index_generation; } // Dynamic (per-layer selector) regroup predicate. @@ -4337,6 +4388,7 @@ int Print::get_filament_config_indx(int filament_id, int layer_id, bool use_cach void Print::update_filament_self_index_cache() { m_missing_nozzle_group_logged.clear(); // reset the per-slice get_config_index log dedupe + ++m_config_index_generation; std::vector values; if (m_full_print_config.has("filament_self_index")) { @@ -4376,7 +4428,7 @@ int Print::get_nozzle_config_index(int filament_id, int layer_id) int Print::get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, FilamentIndexMap *index_map) { - auto group_result = get_layered_nozzle_group_result(); + const MultiNozzleUtils::LayeredNozzleGroupResult *group_result = m_layered_nozzle_group_result.get(); // Orca: defensive — when no grouping producer has published a result yet, fall back to the // static identity: one filament-variant column per filament. if (!group_result) @@ -4411,7 +4463,7 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector &variant_list, const std::vector& self_index_list, PrintIndexMap &index_map) { - auto group_result = get_layered_nozzle_group_result(); + const MultiNozzleUtils::LayeredNozzleGroupResult *group_result = m_layered_nozzle_group_result.get(); // Orca: same static fallback as the filament overload; the slot degenerates to the filament's // extruder column (filament_map is 1 based, get_extruder_id guards the filament id range). if (!group_result) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index f185962b1e..2fe135a24c 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1,6 +1,14 @@ #ifndef slic3r_Print_hpp_ #define slic3r_Print_hpp_ +#include "Config.hpp" +#include "Model.hpp" +#include "Polygon.hpp" +#include "Fill/FillBase.hpp" +#include "Polyline.hpp" +#include "ExtrusionEntity.hpp" +#include "Geometry.hpp" +#include "CommonDefs.hpp" #include "PrintBase.hpp" #include "Fill/FillAdaptive.hpp" #include "Fill/FillLightning.hpp" @@ -9,7 +17,9 @@ #include "ExtrusionEntityCollection.hpp" #include "Flow.hpp" #include "Point.hpp" +#include "PrintConfig.hpp" #include "Slicing.hpp" +#include "TriangleMesh.hpp" #include "TriangleMeshSlicer.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" @@ -18,13 +28,25 @@ #include "GCode/GCodeProcessor.hpp" #include "MultiMaterialSegmentation.hpp" #include "ObjectID.hpp" +#include "TriangleSelector.hpp" #include "libslic3r.h" #include +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include #include +#include +#include #include "calib.hpp" @@ -1073,9 +1095,9 @@ public: // Logical (extruder, nozzle) grouping result produced by ToolOrdering during reorder. // Consumed by GCode via get_layered_nozzle_group_result()->get_nozzle_id(filament, layer) etc. - void set_nozzle_group_result(std::shared_ptr result) { m_nozzle_group_result = result; } + void set_nozzle_group_result(std::shared_ptr result); std::shared_ptr get_nozzle_group_result() const { return m_nozzle_group_result; } - std::shared_ptr get_layered_nozzle_group_result() const; + std::shared_ptr get_layered_nozzle_group_result() const { return m_layered_nozzle_group_result; } // True only when the project opts into the per-layer filament selector // (enable_filament_dynamic_map) in auto-for-flush mode on a multi-extruder machine. Gates the @@ -1226,6 +1248,9 @@ public: // pipeline's cooling stage, which runs concurrently with the generator stage filling it. int get_filament_config_indx(int filament_id, int layer_id, bool use_cache = true); int get_nozzle_config_index(int filament_id, int layer_id); + // Changes with the grouping result and the filament maps, so a caller may reuse a resolved slot + // until it changes. + size_t config_index_generation() const { return m_config_index_generation; } // Orca: Implement prusa's filament shrink compensation approach // Returns if all used filaments have same shrinkage compensations. @@ -1352,6 +1377,9 @@ private: // Logical (extruder, nozzle) grouping result, set by ToolOrdering during reorder. std::shared_ptr m_nozzle_group_result; + // m_nozzle_group_result narrowed to the layer-aware type; only set_nozzle_group_result() assigns + // either. + std::shared_ptr m_layered_nozzle_group_result; // Sequential (by-object) selector plans, keyed by object; see sequential_dynamic_orderings(). // Rebuilt (or cleared) on every process(). @@ -1361,6 +1389,7 @@ private: FilamentIndexMap m_filament_index_map; // Used to cache printer and process parameter information PrintIndexMap m_nozzle_index_map; + size_t m_config_index_generation{0}; // Orca: filament ids already reported as missing a nozzle-group entry this slice. get_config_index() // falls back per-filament/per-layer in the g-code hot path, so this dedupes its log to once per // filament instead of flooding thousands of identical error lines. Cleared with the caches each slice. diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 21e2251b65..6b9a559f03 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1,10 +1,35 @@ #include "ClipperUtils.hpp" +#include "Geometry.hpp" +#include "CustomGCode.hpp" +#include "Config.hpp" #include "Model.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "Print.hpp" #include "FilamentMixer.hpp" +#include "Slicing.hpp" +#include "libslic3r.h" +#include "PrintConfig.hpp" +#include "PrintBase.hpp" +#include "libslic3r_version.h" +#include "TriangleSelector.hpp" +#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { @@ -1309,7 +1334,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Reproduce that exact expansion here so an unchanged config diffs empty — the expanded // keys invalidate the wipe tower / g-code export, and the placeholder parser aliases // the full config — instead of trimming back to one slot per filament. - auto group_result = std::dynamic_pointer_cast(this->get_nozzle_group_result()); + auto group_result = this->get_layered_nozzle_group_result(); std::unordered_map> filament_variant_uses; if (group_result && group_result->is_support_dynamic_nozzle_map() && collect_filament_variant_uses(*group_result, m_ori_full_print_config, filament_variant_uses)) diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 4448c12c76..7b022c8c84 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -1,11 +1,23 @@ +#include "Config.hpp" #include "Exception.hpp" #include "PrintBase.hpp" #include +#include #include #include +#include +#include +#include +#include +#include +#include #include "I18N.hpp" +#include "Model.hpp" +#include "libslic3r.h" +#include "libslic3r_version.h" +#include "PlaceholderParser.hpp" //! macro used to mark string used at localization, //! return same string diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index f1b158e51f..7e2b17e48f 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -1,8 +1,15 @@ #ifndef slic3r_PrintBase_hpp_ #define slic3r_PrintBase_hpp_ +#include "Config.hpp" +#include "Polygon.hpp" #include "libslic3r.h" +#include +#include +#include +#include #include +#include #include #include #include diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fbd72117cd..76073b4981 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1,14 +1,35 @@ #include "PrintConfig.hpp" +#include "CommonDefs.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "PrintConfigConstants.hpp" #include "ClipperUtils.hpp" #include "Config.hpp" #include "FilamentMixer.hpp" #include "MaterialType.hpp" #include "I18N.hpp" +#include "enum_bitmask.hpp" #include "format.hpp" #include "GCode/Thumbnails.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -19,6 +40,11 @@ #include #include #include +#include +#include +#include +#include +#include namespace { std::set SplitStringAndRemoveDuplicateElement(const std::string &str, const std::string &separator) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b1c407e3b6..0a478d66dc 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -16,10 +16,13 @@ #ifndef slic3r_PrintConfig_hpp_ #define slic3r_PrintConfig_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include "CommonDefs.hpp" #include "Config.hpp" #include "Polygon.hpp" +#include +#include #include #include #include @@ -27,6 +30,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Slic3r { @@ -251,9 +267,9 @@ enum class PrintOrder enum class SlicingMode { - // Regular, applying ClipperLib::pftNonZero rule when creating ExPolygons. + // Regular, applying pftNonZero rule when creating ExPolygons. Regular, - // Compatible with 3DLabPrint models, applying ClipperLib::pftEvenOdd rule when creating ExPolygons. + // Compatible with 3DLabPrint models, applying pftEvenOdd rule when creating ExPolygons. EvenOdd, // Orienting all contours CCW, thus closing all holes. CloseHoles, diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 3b7e889472..d4201cf696 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1,15 +1,21 @@ +#include "ExPolygon.hpp" +#include "Config.hpp" #include "Exception.hpp" +#include "Line.hpp" +#include "Flow.hpp" #include "Model.hpp" #include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" #include "Print.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" -#include "Clipper2Utils.hpp" #include "ElephantFootCompensation.hpp" #include "Geometry.hpp" #include "I18N.hpp" #include "Layer.hpp" #include "MutablePolygon.hpp" +#include "PrintBase.hpp" #include "PrintConfig.hpp" #include "SLA/IndexedMesh.hpp" #include "Support/SupportMaterial.hpp" @@ -19,6 +25,7 @@ #include "Slicing.hpp" #include "Tesselate.hpp" #include "TriangleMeshSlicer.hpp" +#include "TriangleSelector.hpp" #include "Utils.hpp" #include "Fill/FillAdaptive.hpp" #include "Fill/Fill.hpp" @@ -27,16 +34,39 @@ #include "format.hpp" #include "AABBTreeIndirect.hpp" #include "AABBTreeLines.hpp" +#include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include +#include #include #include #include #include #include +#include +#include #include #include @@ -46,6 +76,7 @@ #include #include +#include using namespace std::literals; @@ -56,7 +87,7 @@ using namespace std::literals; // #define PRINT_OBJECT_TIMING #ifdef PRINT_OBJECT_TIMING - // time limit for one ClipperLib operation (union / diff / offset), in ms + // time limit for one Clipper operation (union / diff / offset), in ms #define PRINT_OBJECT_TIME_LIMIT_DEFAULT 50 #include #include "Timer.hpp" @@ -1851,7 +1882,7 @@ void PrintObject::detect_surfaces_type() // Grow, then keep only what the configured direction allows, using the top's own filled // outline (same outer edge, holes closed) to tell the two apart. - ExPolygons expanded = offset_ex_2(island_top, d, Clipper2Lib::JoinType::Miter); + ExPolygons expanded = offset_ex(island_top, float(d), jtMiter, 2.); if (direction != TopSurfaceExpansionDirection::InwardAndOutward) { ExPolygons outline; outline.reserve(island_top.size()); @@ -2558,9 +2589,9 @@ void PrintObject::discover_vertical_shells() // Open to remove (filter out) regions narrower than an infill extrusion line width. -narrow_ensure_vertical_wall_thickness_region_radius, // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill. - narrow_ensure_vertical_wall_thickness_region_radius + narrow_sparse_infill_region_radius, ClipperLib::jtSquare), + narrow_ensure_vertical_wall_thickness_region_radius + narrow_sparse_infill_region_radius, jtSquare), // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions. - narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare); + narrow_sparse_infill_region_radius - tiny_overlap_radius, jtSquare); Polygons object_volume; Polygons internal_volume; @@ -4170,7 +4201,7 @@ void PrintObject::clip_fill_surfaces() upper_internal = intersection( // Regularize the overhang regions, so that the infill areas will not become excessively jagged. smooth_outward( - closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.), + closing(upper_internal, closing_radius, jtSquare, 0.), scaled(0.1)), lower_layer_internal_surfaces); // Apply new internal infill to regions. @@ -4341,7 +4372,7 @@ void PrintObject::discover_horizontal_shells() // have the same angle, so the next shell would be grown even more and so on. Polygons too_narrow = diff( new_internal_solid, - opening(new_internal_solid, margin, margin + ClipperSafetyOffset, ClipperLib::jtMiter, 5)); + opening(new_internal_solid, margin, margin + ClipperSafetyOffset, jtMiter, 5)); if (! too_narrow.empty()) { // grow the collapsing parts and add the extra area to the neighbor layer // as well as to our original surfaces so that we support this @@ -4543,7 +4574,7 @@ void PrintObject::_generate_support_material() } // BBS -#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtSquare, 0. #define SUPPORT_MATERIAL_MARGIN 1.2 template void PrintObject::remove_bridges_from_contacts( diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 14bd65c9cf..43a9b703a0 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1,16 +1,42 @@ +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include "BoundingBox.hpp" #include "ClipperUtils.hpp" #include "ElephantFootCompensation.hpp" +#include "ExPolygon.hpp" #include "Exception.hpp" +#include "Flow.hpp" #include "I18N.hpp" #include "Layer.hpp" +#include "Model.hpp" #include "MultiMaterialSegmentation.hpp" +#include "ObjectID.hpp" +#include "Point.hpp" +#include "Polygon.hpp" #include "Print.hpp" //BBS +#include "PrintConfig.hpp" +#include "PrintBase.hpp" #include "ShortestPath.hpp" +#include "libslic3r.h" +#include "TriangleMeshSlicer.hpp" +#include "TriangleMesh.hpp" +#include "Slicing.hpp" +#include "Surface.hpp" +#include "Utils.hpp" #include "libslic3r/Feature/Interlocking/InterlockingGenerator.hpp" //! macro used to mark string used at localization, return same string diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 5c08de8b36..52018223ca 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -1,5 +1,13 @@ +#include "Config.hpp" #include "Exception.hpp" +#include "Flow.hpp" #include "Print.hpp" +#include +#include "PrintConfig.hpp" +#include "libslic3r.h" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/ProjectTask.cpp b/src/libslic3r/ProjectTask.cpp index fe5fd36a45..33be040999 100644 --- a/src/libslic3r/ProjectTask.cpp +++ b/src/libslic3r/ProjectTask.cpp @@ -4,6 +4,11 @@ #include "ProjectTask.hpp" +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libslic3r/ProjectTask.hpp b/src/libslic3r/ProjectTask.hpp index fd9dd2db3b..47eaa37dcc 100644 --- a/src/libslic3r/ProjectTask.hpp +++ b/src/libslic3r/ProjectTask.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_ProjectTask_hpp_ #define slic3r_ProjectTask_hpp_ +#include #include #include #include diff --git a/src/libslic3r/PublishSettings.cpp b/src/libslic3r/PublishSettings.cpp index 6d28cc0af3..435c8e44eb 100644 --- a/src/libslic3r/PublishSettings.cpp +++ b/src/libslic3r/PublishSettings.cpp @@ -1,5 +1,6 @@ #include "PublishSettings.hpp" +#include "Config.hpp" #include "PresetBundle.hpp" #include "Preset.hpp" #include "PrintConfig.hpp" @@ -8,8 +9,11 @@ #include #include +#include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/QuadricEdgeCollapse.cpp b/src/libslic3r/QuadricEdgeCollapse.cpp index 5d0e3c17e8..27f820e453 100644 --- a/src/libslic3r/QuadricEdgeCollapse.cpp +++ b/src/libslic3r/QuadricEdgeCollapse.cpp @@ -1,8 +1,22 @@ #include "QuadricEdgeCollapse.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include "MutablePriorityQueue.hpp" +#include "libslic3r.h" +#include "Point.hpp" #include +#include +#include using namespace Slic3r; diff --git a/src/libslic3r/SLA/AGGRaster.hpp b/src/libslic3r/SLA/AGGRaster.hpp index 7c8e71c2ae..52c95eae5b 100644 --- a/src/libslic3r/SLA/AGGRaster.hpp +++ b/src/libslic3r/SLA/AGGRaster.hpp @@ -1,7 +1,14 @@ #ifndef AGGRASTER_HPP #define AGGRASTER_HPP +#include +#include +#include +#include #include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/ExPolygon.hpp" // For rasterizing @@ -15,6 +22,8 @@ #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/SLA/BoostAdapter.hpp b/src/libslic3r/SLA/BoostAdapter.hpp index 13e0465b14..d5487808a7 100644 --- a/src/libslic3r/SLA/BoostAdapter.hpp +++ b/src/libslic3r/SLA/BoostAdapter.hpp @@ -1,10 +1,22 @@ #ifndef SLA_BOOSTADAPTER_HPP #define SLA_BOOSTADAPTER_HPP +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include namespace boost { namespace geometry { diff --git a/src/libslic3r/SLA/Clustering.cpp b/src/libslic3r/SLA/Clustering.cpp index 41ff1d4f09..010ce5d6e1 100644 --- a/src/libslic3r/SLA/Clustering.cpp +++ b/src/libslic3r/SLA/Clustering.cpp @@ -1,8 +1,16 @@ #include "Clustering.hpp" #include "boost/geometry/index/rtree.hpp" +#include +#include +#include +#include +#include +#include #include #include +#include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/Clustering.hpp b/src/libslic3r/SLA/Clustering.hpp index 269ec28822..0f1e113b22 100644 --- a/src/libslic3r/SLA/Clustering.hpp +++ b/src/libslic3r/SLA/Clustering.hpp @@ -1,6 +1,11 @@ #ifndef SLA_CLUSTERING_HPP #define SLA_CLUSTERING_HPP +#include +#include +#include +#include +#include #include #include diff --git a/src/libslic3r/SLA/ConcaveHull.cpp b/src/libslic3r/SLA/ConcaveHull.cpp index f657fce746..8d361fc5b5 100644 --- a/src/libslic3r/SLA/ConcaveHull.cpp +++ b/src/libslic3r/SLA/ConcaveHull.cpp @@ -1,3 +1,10 @@ +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include "libslic3r/Polygon.hpp" +#include +#include "libslic3r/ExPolygon.hpp" #include #include @@ -5,6 +12,8 @@ #include #include +#include +#include namespace Slic3r { namespace sla { @@ -135,7 +144,7 @@ ExPolygons offset_waffle_style_ex(const ConcaveHull &hull, coord_t delta) Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta) { auto arc_tolerance = scaled(0.01); - Polygons res = closing(hull.polygons(), 2 * delta, delta, ClipperLib::jtRound, arc_tolerance); + Polygons res = closing(hull.polygons(), 2 * delta, delta, jtRound, arc_tolerance); auto it = std::remove_if(res.begin(), res.end(), [](Polygon &p) { return p.is_clockwise(); }); res.erase(it, res.end()); diff --git a/src/libslic3r/SLA/ConcaveHull.hpp b/src/libslic3r/SLA/ConcaveHull.hpp index dccdafd18c..5c697c2595 100644 --- a/src/libslic3r/SLA/ConcaveHull.hpp +++ b/src/libslic3r/SLA/ConcaveHull.hpp @@ -1,6 +1,10 @@ #ifndef SLA_CONCAVEHULL_HPP #define SLA_CONCAVEHULL_HPP +#include "libslic3r/Polygon.hpp" +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include namespace Slic3r { diff --git a/src/libslic3r/SLA/Concurrency.hpp b/src/libslic3r/SLA/Concurrency.hpp index 7299101b31..35e30d88d7 100644 --- a/src/libslic3r/SLA/Concurrency.hpp +++ b/src/libslic3r/SLA/Concurrency.hpp @@ -3,6 +3,8 @@ // FIXME: Deprecated +#include "libslic3r/Execution/Execution.hpp" +#include #include #include diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp index f50cdbced2..d21744a026 100644 --- a/src/libslic3r/SLA/Hollowing.cpp +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -1,5 +1,20 @@ +#include "libslic3r/SLA/JobController.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include "libslic3r/ExPolygon.hpp" +#include +#include "libslic3r/SLA/Concurrency.hpp" #include +#include +#include #include +#include #include #include @@ -15,6 +30,8 @@ #include #include +#include +#include //! macro used to mark string used at localization, //! return same string diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp index f6beaadb24..fd06f93a34 100644 --- a/src/libslic3r/SLA/Hollowing.hpp +++ b/src/libslic3r/SLA/Hollowing.hpp @@ -1,9 +1,17 @@ #ifndef SLA_HOLLOWING_HPP #define SLA_HOLLOWING_HPP +#include "libslic3r/Point.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/ExPolygon.hpp" +#include #include #include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/SLA/IndexedMesh.cpp b/src/libslic3r/SLA/IndexedMesh.cpp index 65d9d90b34..d17f9497fc 100644 --- a/src/libslic3r/SLA/IndexedMesh.cpp +++ b/src/libslic3r/SLA/IndexedMesh.cpp @@ -1,10 +1,24 @@ #include "IndexedMesh.hpp" +#include "libslic3r/BoundingBox.hpp" #include "Concurrency.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include +#include #ifdef SLIC3R_HOLE_RAYCASTER #include diff --git a/src/libslic3r/SLA/IndexedMesh.hpp b/src/libslic3r/SLA/IndexedMesh.hpp index bb2dee034c..b377064115 100644 --- a/src/libslic3r/SLA/IndexedMesh.hpp +++ b/src/libslic3r/SLA/IndexedMesh.hpp @@ -1,6 +1,12 @@ #ifndef SLA_INDEXEDMESH_H #define SLA_INDEXEDMESH_H +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libslic3r/SLA/Pad.cpp b/src/libslic3r/SLA/Pad.cpp index 447a416341..887676174d 100644 --- a/src/libslic3r/SLA/Pad.cpp +++ b/src/libslic3r/SLA/Pad.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -6,6 +8,9 @@ #include "ConcaveHull.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "boost/log/trivial.hpp" #include "ClipperUtils.hpp" #include "Tesselate.hpp" @@ -19,7 +24,11 @@ #include "SVG.hpp" #include "I18N.hpp" +#include "libslic3r/libslic3r.h" #include +#include +#include +#include //! macro used to mark string used at localization, //! return same string @@ -171,24 +180,8 @@ struct PadSkeleton { ExPolygons inner, outer; }; PadSkeleton divide_blueprint(const ExPolygons &bp) { - ClipperLib::PolyTree ptree = union_pt(bp); - PadSkeleton ret; - ret.inner.reserve(size_t(ptree.Total())); - ret.outer.reserve(size_t(ptree.Total())); - - for (ClipperLib::PolyTree::PolyNode *node : ptree.Childs) { - ExPolygon poly; - poly.contour.points = std::move(node->Contour); - for (ClipperLib::PolyTree::PolyNode *child : node->Childs) { - poly.holes.emplace_back(std::move(child->Contour)); - - traverse_pt(child->Childs, &ret.inner); - } - - ret.outer.emplace_back(poly); - } - + ret.outer = top_level_expolygons(bp, &ret.inner); return ret; } @@ -257,7 +250,7 @@ public: auto model_bp_offs = offset_ex(model_blueprint, scaled(cfg.embed_object.object_gap_mm), - ClipperLib::jtMiter, 1); + jtMiter, 1); ExPolygons fullcvh = wafflized_concave_hull(support_blueprint, model_bp_offs, cfg, thr); diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp index 7240b198da..dadfa23e96 100644 --- a/src/libslic3r/SLA/RasterBase.cpp +++ b/src/libslic3r/SLA/RasterBase.cpp @@ -1,13 +1,25 @@ #ifndef SLARASTER_CPP #define SLARASTER_CPP +#include +#include +#include +#include +#include #include +#include +#include #include #include // minz image write: +#include #include +#include +#include +#include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp index 33d39eafbd..44b7c0dccd 100644 --- a/src/libslic3r/SLA/RasterBase.hpp +++ b/src/libslic3r/SLA/RasterBase.hpp @@ -1,8 +1,13 @@ #ifndef SLA_RASTERBASE_HPP #define SLA_RASTERBASE_HPP +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" #include #include +#include #include #include #include diff --git a/src/libslic3r/SLA/RasterToPolygons.cpp b/src/libslic3r/SLA/RasterToPolygons.cpp index e05a721cd8..88620831d8 100644 --- a/src/libslic3r/SLA/RasterToPolygons.cpp +++ b/src/libslic3r/SLA/RasterToPolygons.cpp @@ -1,9 +1,18 @@ #include "RasterToPolygons.hpp" #include "AGGRaster.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/libslic3r.h" #include "libslic3r/MarchingSquares.hpp" #include "MTUtils.hpp" #include "ClipperUtils.hpp" +#include +#include +#include +#include +#include namespace marchsq { diff --git a/src/libslic3r/SLA/RasterToPolygons.hpp b/src/libslic3r/SLA/RasterToPolygons.hpp index 5320887c8f..1f78865603 100644 --- a/src/libslic3r/SLA/RasterToPolygons.hpp +++ b/src/libslic3r/SLA/RasterToPolygons.hpp @@ -1,6 +1,7 @@ #ifndef RASTERTOPOLYGONS_HPP #define RASTERTOPOLYGONS_HPP +#include "libslic3r/Point.hpp" #include "libslic3r/ExPolygon.hpp" namespace Slic3r { diff --git a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp index 3ad7d62b1e..881a0a0e22 100644 --- a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp +++ b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp @@ -7,7 +7,9 @@ #include "IndexedMesh.hpp" #include "libslic3r/Model.hpp" +#include #include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 196646dc9e..8134fb1d6c 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -1,3 +1,10 @@ +#include +#include +#include +#include +#include +#include +#include #include #include @@ -8,12 +15,19 @@ #include #include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Execution/Execution.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Optimize/Optimizer.hpp" +#include "libslic3r/BoundingBox.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/PrintConfig.hpp" #include #include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/Rotfinder.hpp b/src/libslic3r/SLA/Rotfinder.hpp index d632419fb3..ba0f23b310 100644 --- a/src/libslic3r/SLA/Rotfinder.hpp +++ b/src/libslic3r/SLA/Rotfinder.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/SLA/SpatIndex.cpp b/src/libslic3r/SLA/SpatIndex.cpp index d95ba55bee..3e36b4943e 100644 --- a/src/libslic3r/SLA/SpatIndex.cpp +++ b/src/libslic3r/SLA/SpatIndex.cpp @@ -1,7 +1,15 @@ #include "SpatIndex.hpp" +#include "libslic3r/BoundingBox.hpp" // for concave hull merging decisions +#include +#include +#include +#include +#include #include +#include +#include #ifdef _MSC_VER #pragma warning(push) diff --git a/src/libslic3r/SLA/SpatIndex.hpp b/src/libslic3r/SLA/SpatIndex.hpp index ef059d3ae6..a35806800c 100644 --- a/src/libslic3r/SLA/SpatIndex.hpp +++ b/src/libslic3r/SLA/SpatIndex.hpp @@ -1,6 +1,9 @@ #ifndef SLA_SPATINDEX_HPP #define SLA_SPATINDEX_HPP +#include +#include +#include #include #include #include diff --git a/src/libslic3r/SLA/SupportPoint.hpp b/src/libslic3r/SLA/SupportPoint.hpp index 71849a3643..6c2cf88075 100644 --- a/src/libslic3r/SLA/SupportPoint.hpp +++ b/src/libslic3r/SLA/SupportPoint.hpp @@ -1,7 +1,11 @@ #ifndef SLA_SUPPORTPOINT_HPP #define SLA_SUPPORTPOINT_HPP +#include +#include +#include "libslic3r/libslic3r.h" #include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 7c6c8d1f6b..f63430bede 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -1,6 +1,15 @@ //#include "igl/random_points_on_mesh.h" //#include "igl/AABB.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "SupportPointGenerator.hpp" @@ -8,6 +17,9 @@ #include "Concurrency.hpp" #include "Model.hpp" #include "ExPolygon.hpp" +#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/Polygon.hpp" #include "SVG.hpp" #include "Point.hpp" #include "ClipperUtils.hpp" @@ -17,6 +29,9 @@ #include #include +#include +#include +#include namespace Slic3r { namespace sla { @@ -186,8 +201,8 @@ static std::vector make_layers( // Produce 2 bands around the island, a safe band for dangling overhangs // and an unsafe band for sloped overhangs. // These masks include the original island - auto dangl_mask = expand(bottom_polygons, between_layers_offset, ClipperLib::jtSquare); - auto overh_mask = expand(bottom_polygons, slope_offset, ClipperLib::jtSquare); + auto dangl_mask = expand(bottom_polygons, between_layers_offset, jtSquare); + auto overh_mask = expand(bottom_polygons, slope_offset, jtSquare); // Absolutely hopeless overhangs are those outside the unsafe band top.overhangs = diff_ex(*top.polygon, overh_mask); diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp index 17daed9f30..e48fa05335 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.hpp +++ b/src/libslic3r/SLA/SupportPointGenerator.hpp @@ -1,6 +1,13 @@ #ifndef SLA_SUPPORTPOINTGENERATOR_HPP #define SLA_SUPPORTPOINTGENERATOR_HPP +#include "libslic3r/ExPolygon.hpp" +#include +#include "libslic3r/Polygon.hpp" +#include +#include "libslic3r/libslic3r.h" +#include +#include #include #include @@ -11,6 +18,9 @@ #include #include +#include +#include +#include // #define SLA_SUPPORTPOINTGEN_DEBUG diff --git a/src/libslic3r/SLA/SupportTree.cpp b/src/libslic3r/SLA/SupportTree.cpp index a0f88ed608..4de28ca45b 100644 --- a/src/libslic3r/SLA/SupportTree.cpp +++ b/src/libslic3r/SLA/SupportTree.cpp @@ -3,6 +3,12 @@ * */ +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include #include #include #include @@ -18,6 +24,8 @@ #include #include #include +#include +#include //! macro used to mark string used at localization, //! return same string diff --git a/src/libslic3r/SLA/SupportTree.hpp b/src/libslic3r/SLA/SupportTree.hpp index a5e283b0dd..7511b0aaa5 100644 --- a/src/libslic3r/SLA/SupportTree.hpp +++ b/src/libslic3r/SLA/SupportTree.hpp @@ -1,6 +1,7 @@ #ifndef SLA_SUPPORTTREE_HPP #define SLA_SUPPORTTREE_HPP +#include #include #include #include diff --git a/src/libslic3r/SLA/SupportTreeBuilder.cpp b/src/libslic3r/SLA/SupportTreeBuilder.cpp index 4080c4fc3f..635b5452d1 100644 --- a/src/libslic3r/SLA/SupportTreeBuilder.cpp +++ b/src/libslic3r/SLA/SupportTreeBuilder.cpp @@ -2,6 +2,21 @@ #define NOMINMAX #endif +#include "libslic3r/SLA/SpatIndex.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/SLA/Pad.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/MTUtils.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/SLA/SupportTree.hpp" + #include #include #include diff --git a/src/libslic3r/SLA/SupportTreeBuilder.hpp b/src/libslic3r/SLA/SupportTreeBuilder.hpp index df5484e3dd..de0170d854 100644 --- a/src/libslic3r/SLA/SupportTreeBuilder.hpp +++ b/src/libslic3r/SLA/SupportTreeBuilder.hpp @@ -1,12 +1,18 @@ #ifndef SLA_SUPPORTTREEBUILDER_HPP #define SLA_SUPPORTTREEBUILDER_HPP +#include "libslic3r/Point.hpp" +#include +#include +#include "libslic3r/libslic3r.h" #include #include //#include #include #include #include +#include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp index cff92b5b89..923d0f924f 100644 --- a/src/libslic3r/SLA/SupportTreeBuildsteps.cpp +++ b/src/libslic3r/SLA/SupportTreeBuildsteps.cpp @@ -1,8 +1,31 @@ +#include "libslic3r/Optimize/Optimizer.hpp" +#include "libslic3r/SLA/SupportTree.hpp" +#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/SLA/SupportTreeBuilder.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include +#include +#include +#include "libslic3r/SLA/Concurrency.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/SLA/Clustering.hpp" +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/SupportTreeBuildsteps.hpp b/src/libslic3r/SLA/SupportTreeBuildsteps.hpp index 478e2df1fe..850f35bdeb 100644 --- a/src/libslic3r/SLA/SupportTreeBuildsteps.hpp +++ b/src/libslic3r/SLA/SupportTreeBuildsteps.hpp @@ -1,12 +1,30 @@ #ifndef SLASUPPORTTREEALGORITHM_H #define SLASUPPORTTREEALGORITHM_H +#include "libslic3r/Point.hpp" +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/SLA/Concurrency.hpp" +#include +#include +#include "libslic3r/SLA/SupportTree.hpp" +#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/SLA/Pad.hpp" #include +#include +#include +#include #include #include #include #include +#include +#include +#include namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/SupportTreeMesher.cpp b/src/libslic3r/SLA/SupportTreeMesher.cpp index 17f57f4578..0732a7ab23 100644 --- a/src/libslic3r/SLA/SupportTreeMesher.cpp +++ b/src/libslic3r/SLA/SupportTreeMesher.cpp @@ -1,4 +1,13 @@ #include "SupportTreeMesher.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include "libslic3r/TriangleMesh.hpp" namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLA/SupportTreeMesher.hpp b/src/libslic3r/SLA/SupportTreeMesher.hpp index 63ccc5fce3..e914bcea36 100644 --- a/src/libslic3r/SLA/SupportTreeMesher.hpp +++ b/src/libslic3r/SLA/SupportTreeMesher.hpp @@ -1,10 +1,14 @@ #ifndef SUPPORTTREEMESHER_HPP #define SUPPORTTREEMESHER_HPP +#include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" #include "libslic3r/SLA/SupportTreeBuilder.hpp" #include "libslic3r/TriangleMesh.hpp" +#include +#include +#include //#include "libslic3r/SLA/Contour3D.hpp" namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index eb37ca578c..336143c764 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1,17 +1,42 @@ #include "SLAPrint.hpp" +#include "PrintConfig.hpp" +#include "SLA/SupportTree.hpp" +#include "SLA/Pad.hpp" +#include "Point.hpp" +#include "Model.hpp" +#include "ObjectID.hpp" +#include "Config.hpp" +#include "PrintBase.hpp" +#include "SLA/SupportPoint.hpp" +#include "Polygon.hpp" +#include "ExPolygon.hpp" +#include "SLA/Hollowing.hpp" #include "SLAPrintSteps.hpp" #include "ClipperUtils.hpp" #include "Geometry.hpp" #include "MTUtils.hpp" #include "Thread.hpp" +#include "libslic3r.h" +#include "Utils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include // #define SLAPRINT_DO_BENCHMARK diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 0eaa44a754..7b863f7380 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -1,15 +1,35 @@ #ifndef slic3r_SLAPrint_hpp_ #define slic3r_SLAPrint_hpp_ +#include +#include +#include #include +#include +#include +#include #include +#include "ObjectID.hpp" +#include +#include "ExPolygon.hpp" +#include +#include "Config.hpp" +#include +#include "Polygon.hpp" +#include #include "PrintBase.hpp" +#include "PrintConfig.hpp" +#include "SLA/Hollowing.hpp" +#include "SLA/JobController.hpp" +#include "SLA/Pad.hpp" #include "SLA/RasterBase.hpp" +#include "SLA/SupportPoint.hpp" #include "SLA/SupportTree.hpp" #include "Execution/ExecutionTBB.hpp" #include "Point.hpp" #include "MTUtils.hpp" #include "Zipper.hpp" +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 04c65644d0..51c2e6ef9f 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -1,3 +1,13 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -18,8 +28,23 @@ #include #include +#include +#include +#include "ExPolygon.hpp" +#include "Execution/ExecutionTBB.hpp" #include "I18N.hpp" +#include "SLAPrint.hpp" +#include "Point.hpp" +#include "libslic3r.h" +#include "SLA/Hollowing.hpp" +#include "TriangleMesh.hpp" +#include "Line.hpp" +#include "Model.hpp" +#include "SLA/SupportPoint.hpp" +#include "SLA/JobController.hpp" +#include "SLA/SupportTree.hpp" +#include "SLA/RasterBase.hpp" //! macro used to mark string used at localization, //! return same string diff --git a/src/libslic3r/SLAPrintSteps.hpp b/src/libslic3r/SLAPrintSteps.hpp index 19b64d4a98..8d1ca12179 100644 --- a/src/libslic3r/SLAPrintSteps.hpp +++ b/src/libslic3r/SLAPrintSteps.hpp @@ -1,12 +1,15 @@ #ifndef SLAPRINTSTEPS_HPP #define SLAPRINTSTEPS_HPP +#include +#include "libslic3r.h" #include #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/SVG.cpp b/src/libslic3r/SVG.cpp index 9ccddcd4f2..ebd4343425 100644 --- a/src/libslic3r/SVG.cpp +++ b/src/libslic3r/SVG.cpp @@ -1,8 +1,28 @@ #include "SVG.hpp" +#include +#include +#include +#include +#include "BoundingBox.hpp" +#include "libslic3r.h" +#include "Line.hpp" +#include "Point.hpp" +#include +#include "ExPolygon.hpp" +#include "Polygon.hpp" +#include "Surface.hpp" +#include "Polyline.hpp" +#include "MultiPoint.hpp" +#include +#include #include #include #include +#include +#include +#include +#include namespace Slic3r { @@ -230,15 +250,15 @@ void SVG::draw(const Points &points, std::string fill, coord_t radius) this->draw(*it, fill, radius); } -void SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width) +void SVG::draw(const Points &polygon, double scale, std::string stroke, coordf_t stroke_width) { this->stroke = stroke; this->path(this->get_path_d(polygon, scale, true), false, stroke_width, 1.f); } -void SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width) +void SVG::draw(const VecOfPoints &polygons, double scale, std::string stroke, coordf_t stroke_width) { - for (ClipperLib::Paths::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) + for (VecOfPoints::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) draw(*it, scale, stroke, stroke_width); } @@ -284,11 +304,11 @@ std::string SVG::get_path_d(const MultiPoint &mp, bool closed) const return d.str(); } -std::string SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const +std::string SVG::get_path_d(const Points &path, double scale, bool closed) const { std::ostringstream d; d << "M "; - for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) { + for (Points::const_iterator p = path.begin(); p != path.end(); ++p) { d << to_svg_x(scale * p->x() - origin(0)) << " "; d << to_svg_y(scale * p->y() - origin(1)) << " "; } diff --git a/src/libslic3r/SVG.hpp b/src/libslic3r/SVG.hpp index 5f57961053..838c1cdc73 100644 --- a/src/libslic3r/SVG.hpp +++ b/src/libslic3r/SVG.hpp @@ -1,12 +1,20 @@ #ifndef slic3r_SVG_hpp_ #define slic3r_SVG_hpp_ +#include "Point.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "MultiPoint.hpp" #include "libslic3r.h" -#include "clipper.hpp" #include "ExPolygon.hpp" #include "Line.hpp" #include "TriangleMesh.hpp" #include "Surface.hpp" +#include +#include +#include +#include +#include namespace Slic3r { @@ -70,9 +78,9 @@ public: void draw(const Point &point, std::string fill = "black", coord_t radius = 0); void draw(const Points &points, std::string fill = "black", coord_t radius = 0); - // Support for rendering the ClipperLib paths - void draw(const ClipperLib::Path &polygon, double scale, std::string fill = "grey", coordf_t stroke_width = 0); - void draw(const ClipperLib::Paths &polygons, double scale, std::string fill = "grey", coordf_t stroke_width = 0); + // Paths drawn with their coordinates multiplied by scale. + void draw(const Points &polygon, double scale, std::string fill = "grey", coordf_t stroke_width = 0); + void draw(const VecOfPoints &polygons, double scale, std::string fill = "grey", coordf_t stroke_width = 0); void draw_text(const Point &pt, const char *text, const char *color, int font_size = 20); void draw_legend(const Point &pt, const char *text, const char *color); @@ -88,7 +96,7 @@ public: void path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity); std::string get_path_d(const MultiPoint &mp, bool closed = false) const; - std::string get_path_d(const ClipperLib::Path &mp, double scale, bool closed = false) const; + std::string get_path_d(const Points &mp, double scale, bool closed = false) const; public: static void export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); diff --git a/src/libslic3r/Semver.cpp b/src/libslic3r/Semver.cpp index 5d36b39f72..f052ba6bdb 100644 --- a/src/libslic3r/Semver.cpp +++ b/src/libslic3r/Semver.cpp @@ -1,4 +1,6 @@ +#include "Semver.hpp" #include "libslic3r.h" +#include "libslic3r_version.h" namespace Slic3r { diff --git a/src/libslic3r/Semver.hpp b/src/libslic3r/Semver.hpp index d3683b4eb8..7c79f404ce 100644 --- a/src/libslic3r/Semver.hpp +++ b/src/libslic3r/Semver.hpp @@ -1,12 +1,17 @@ #ifndef slic3r_Semver_hpp_ #define slic3r_Semver_hpp_ +#include +#include +#include +#include #include #include #include #include #include #include +#include #include "semver/semver.h" diff --git a/src/libslic3r/Shape/TextShape.cpp b/src/libslic3r/Shape/TextShape.cpp index 4f32b9d857..cc7a7d555d 100644 --- a/src/libslic3r/Shape/TextShape.cpp +++ b/src/libslic3r/Shape/TextShape.cpp @@ -4,13 +4,36 @@ #include "TextShape.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include "libslic3r/Point.hpp" #include "Standard_TypeDef.hxx" #include "STEPCAFControl_Reader.hxx" #include "BRepMesh_IncrementalMesh.hxx" #include "Interface_Static.hxx" +#include "libslic3r/Utils.hpp" #include "XCAFDoc_DocumentTool.hxx" #include "XCAFDoc_ShapeTool.hxx" #include "XCAFApp_Application.hxx" diff --git a/src/libslic3r/Shape/TextShape.hpp b/src/libslic3r/Shape/TextShape.hpp index d093c2da42..28abf4d7ea 100644 --- a/src/libslic3r/Shape/TextShape.hpp +++ b/src/libslic3r/Shape/TextShape.hpp @@ -2,6 +2,9 @@ #define slic3r_Text_Shape_hpp_ #include "libslic3r/TriangleMesh.hpp" +#include +#include +#include namespace Slic3r { class TriangleMesh; diff --git a/src/libslic3r/ShortEdgeCollapse.cpp b/src/libslic3r/ShortEdgeCollapse.cpp index 3397daf55c..59637b4dae 100644 --- a/src/libslic3r/ShortEdgeCollapse.cpp +++ b/src/libslic3r/ShortEdgeCollapse.cpp @@ -1,10 +1,14 @@ #include "ShortEdgeCollapse.hpp" +#include "Point.hpp" +#include "TriangleMesh.hpp" #include "libslic3r/NormalUtils.hpp" +#include #include #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/ShortEdgeCollapse.hpp b/src/libslic3r/ShortEdgeCollapse.hpp index e6f1822c89..f62a082828 100644 --- a/src/libslic3r/ShortEdgeCollapse.hpp +++ b/src/libslic3r/ShortEdgeCollapse.hpp @@ -2,6 +2,7 @@ #define SRC_LIBSLIC3R_SHORTEDGECOLLAPSE_HPP_ #include "libslic3r/TriangleMesh.hpp" +#include namespace Slic3r{ diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index 08f973e20b..0b31a66919 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -1,10 +1,24 @@ +#include "ExtrusionEntity.hpp" +#include +#include +#include +#include "Point.hpp" +#include +#include +#include +#include "ExPolygon.hpp" +#include "BoundingBox.hpp" +#include +#include "Polyline.hpp" +#include +#include "Line.hpp" +#include "libslic3r.h" #if 0 #pragma optimize("", off) #undef NDEBUG #undef assert #endif -#include "clipper.hpp" #include "ShortestPath.hpp" #include "ExtrusionEntityCollection.hpp" #include "KDTreeIndirect.hpp" @@ -2041,22 +2055,6 @@ Polylines chain_polylines(Polylines &&polylines, const Point *start_near) return out; } -template static inline T chain_path_items(const Points &points, const T &items) -{ - auto segment_end_point = [&points](size_t idx, bool /* first_point */) -> const Point& { return points[idx]; }; - std::vector> ordered = chain_segments_greedy(segment_end_point, points.size(), nullptr); - T out; - out.reserve(items.size()); - for (auto &segment_and_reversal : ordered) - out.emplace_back(items[segment_and_reversal.first]); - return out; -} - -ClipperLib::PolyNodes chain_clipper_polynodes(const Points &points, const ClipperLib::PolyNodes &items) -{ - return chain_path_items(points, items); -} - // BBS std::vector chain_print_object_instances(const std::vector& print_objects, const Point* start_near) { diff --git a/src/libslic3r/ShortestPath.hpp b/src/libslic3r/ShortestPath.hpp index c7a61d99ee..d8cd7a025f 100644 --- a/src/libslic3r/ShortestPath.hpp +++ b/src/libslic3r/ShortestPath.hpp @@ -1,21 +1,18 @@ #ifndef slic3r_ShortestPath_hpp_ #define slic3r_ShortestPath_hpp_ +#include "Polyline.hpp" #include "libslic3r.h" #include "ExtrusionEntity.hpp" #include "Point.hpp" +#include #include #include #include namespace Slic3r { - namespace ClipperLib { - class PolyNode; - using PolyNodes = std::vector>; - } - std::vector chain_points(const Points &points, const Point *start_near = nullptr); // Variant with post-processing (crossing removal + 2-opt) for object ordering. std::vector chain_points_with_postprocessing(const Points &points, const Point *start_near = nullptr); @@ -49,7 +46,6 @@ template inline void reorder_by_shortest_traverse(std::vector &po for (size_t i:order) polylines_out.emplace_back(std::move(Temp[i])); } -ClipperLib::PolyNodes chain_clipper_polynodes(const Points &points, const ClipperLib::PolyNodes &items); // Chain instances of print objects by an approximate shortest path. // Returns pairs of PrintObject idx and instance of that PrintObject. diff --git a/src/libslic3r/SlicesToTriangleMesh.cpp b/src/libslic3r/SlicesToTriangleMesh.cpp index 3b55cf066b..a536bc0d5e 100644 --- a/src/libslic3r/SlicesToTriangleMesh.cpp +++ b/src/libslic3r/SlicesToTriangleMesh.cpp @@ -1,14 +1,21 @@ +#include +#include #include #include "SlicesToTriangleMesh.hpp" //#include "libslic3r/MTUtils.hpp" +#include "Polygon.hpp" +#include "Point.hpp" +#include "TriangleMesh.hpp" +#include "Execution/Execution.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Tesselate.hpp" #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/SlicesToTriangleMesh.hpp b/src/libslic3r/SlicesToTriangleMesh.hpp index 57b540d9fb..f3177a7622 100644 --- a/src/libslic3r/SlicesToTriangleMesh.hpp +++ b/src/libslic3r/SlicesToTriangleMesh.hpp @@ -3,6 +3,7 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/ExPolygon.hpp" +#include namespace Slic3r { diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index c8c37a5a79..92bdac10e3 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -1,5 +1,13 @@ +#include +#include +#include +#include #include +#include +#include +#include +#include "Point.hpp" #include "libslic3r.h" #include "Slicing.hpp" #include "SlicingAdaptive.hpp" diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index f735ec5518..59ae27c8dd 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -3,10 +3,12 @@ #ifndef slic3r_Slicing_hpp_ #define slic3r_Slicing_hpp_ +#include #include #include #include #include +#include #include #include "libslic3r.h" diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp index 30ff67bba5..65600b4005 100644 --- a/src/libslic3r/SlicingAdaptive.cpp +++ b/src/libslic3r/SlicingAdaptive.cpp @@ -3,8 +3,14 @@ #include "TriangleMesh.hpp" #include "SlicingAdaptive.hpp" +#include #include +#include #include +#include +#include +#include +#include // Based on the work of Florens Waserfall (@platch on github) // and his paper diff --git a/src/libslic3r/SlicingAdaptive.hpp b/src/libslic3r/SlicingAdaptive.hpp index a296553d62..99479bb8b6 100644 --- a/src/libslic3r/SlicingAdaptive.hpp +++ b/src/libslic3r/SlicingAdaptive.hpp @@ -5,6 +5,9 @@ #include "Slicing.hpp" #include "admesh/stl.h" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/StreamUtils.hpp b/src/libslic3r/StreamUtils.hpp index 78a9ac7335..d3c6823a8f 100644 --- a/src/libslic3r/StreamUtils.hpp +++ b/src/libslic3r/StreamUtils.hpp @@ -6,6 +6,7 @@ #include "Polygon.hpp" #include "Polyline.hpp" #include "ExPolygon.hpp" +#include #include #include diff --git a/src/libslic3r/Support/SupportCommon.cpp b/src/libslic3r/Support/SupportCommon.cpp index e734608803..46ed7e968c 100644 --- a/src/libslic3r/Support/SupportCommon.cpp +++ b/src/libslic3r/Support/SupportCommon.cpp @@ -1,5 +1,5 @@ #include "../ClipperUtils.hpp" -// #include "../ClipperZUtils.hpp" +#include "../ClipperZUtils.hpp" #include "../ExtrusionEntityCollection.hpp" #include "../Layer.hpp" #include "../Print.hpp" @@ -7,18 +7,33 @@ #include "../MutablePolygon.hpp" #include "../Geometry.hpp" #include "../Point.hpp" -#include "clipper/clipper_z.hpp" #include #include #include #include +#include +#include +#include +#include +#include #include +#include +#include +#include #include "SupportCommon.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Polyline.hpp" #include "SupportLayer.hpp" #include "SupportParameters.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Surface.hpp" +#include "libslic3r/Utils.hpp" // #define SLIC3R_DEBUG @@ -39,9 +54,9 @@ namespace Slic3r { //FIXME this should be dependent on the nozzle diameter! #define SUPPORT_MATERIAL_MARGIN 1.5 -//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. -//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5 -#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +//#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtMiter, 3. +//#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtMiter, 1.5 +#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtSquare, 0. // Convert some of the intermediate layers into top/bottom interface layers as well as base interface layers. std::pair generate_interface_layers( @@ -280,13 +295,13 @@ SupportGeneratorLayersPtr generate_raft_base( polygons_append(brim, offset(ex, brim_object_gap)); else { if (brim_outer) - polygons_append(brim, offset(ex.contour, brim_object_gap, ClipperLib::jtRound, float(scale_(0.1)))); + polygons_append(brim, offset(ex.contour, brim_object_gap, jtRound, float(scale_(0.1)))); else brim.emplace_back(ex.contour); if (brim_inner) { Polygons holes = ex.holes; polygons_reverse(holes); - holes = shrink(holes, brim_object_gap, ClipperLib::jtRound, float(scale_(0.1))); + holes = shrink(holes, brim_object_gap, jtRound, float(scale_(0.1))); polygons_reverse(holes); polygons_append(brim, std::move(holes)); } else @@ -493,32 +508,25 @@ void tree_supports_generate_paths( // Offset expolygon inside, returns number of expolygons collected (0 or 1). // Vertices of output paths are marked with Z = source contour index of the expoly. // Vertices at the intersection of source contours are marked with Z = -1. - auto shrink_expolygon_with_contour_idx = [](const Slic3r::ExPolygon &expoly, const float delta, ClipperLib::JoinType joinType, double miterLimit, ClipperLib_Z::Paths &out) -> int + auto shrink_expolygon_with_contour_idx = [](const Slic3r::ExPolygon &expoly, const float delta, JoinType joinType, double miterLimit, ClipperZUtils::ZPaths &out) -> int { assert(delta > 0); - auto append_paths_with_z = [](ClipperLib::Paths &src, coord_t contour_idx, ClipperLib_Z::Paths &dst) { + auto append_paths_with_z = [](const Polygons &src, coord_t contour_idx, ClipperZUtils::ZPaths &dst) { dst.reserve(next_highest_power_of_2(dst.size() + src.size())); - for (const ClipperLib::Path &contour : src) { - ClipperLib_Z::Path tmp; - tmp.reserve(contour.size()); - for (const Point &p : contour) - tmp.emplace_back(p.x(), p.y(), contour_idx); - dst.emplace_back(std::move(tmp)); - } + for (const Polygon &contour : src) + dst.emplace_back(ClipperZUtils::to_zpath(contour.points, contour_idx)); + }; + // Oriented CCW, the sign of d alone decides between growing and shrinking. + auto offset_ccw = [joinType, miterLimit](Polygon polygon, float d) { + if (! polygon.is_counter_clockwise()) + polygon.reverse(); + return offset(polygon, d, joinType, miterLimit); }; // 1) Offset the outer contour. - ClipperLib_Z::Paths contours; + ClipperZUtils::ZPaths contours; { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(delta * 0.005); - co.AddPath(expoly.contour.points, joinType, ClipperLib::etClosedPolygon); - ClipperLib::Paths contours_raw; - co.Execute(contours_raw, - delta); + Polygons contours_raw = offset_ccw(expoly.contour, - delta); if (contours_raw.empty()) // No need to try to offset the holes. return 0; @@ -530,24 +538,9 @@ void tree_supports_generate_paths( append(out, std::move(contours)); } else { // 2) Offset the holes one by one, collect the offsetted holes. - ClipperLib_Z::Paths holes; - { - for (const Polygon &hole : expoly.holes) { - ClipperLib::ClipperOffset co; - if (joinType == jtRound) - co.ArcTolerance = miterLimit; - else - co.MiterLimit = miterLimit; - co.ShortestEdgeLength = double(delta * 0.005); - co.AddPath(hole.points, joinType, ClipperLib::etClosedPolygon); - ClipperLib::Paths out2; - // Execute reorients the contours so that the outer most contour has a positive area. Thus the output - // contours will be CCW oriented even though the input paths are CW oriented. - // Offset is applied after contour reorientation, thus the signum of the offset value is reversed. - co.Execute(out2, delta); - append_paths_with_z(out2, 1 + (&hole - expoly.holes.data()), holes); - } - } + ClipperZUtils::ZPaths holes; + for (const Polygon &hole : expoly.holes) + append_paths_with_z(offset_ccw(hole, delta), 1 + (&hole - expoly.holes.data()), holes); // 3) Subtract holes from the contours. if (holes.empty()) { @@ -556,16 +549,11 @@ void tree_supports_generate_paths( } else { // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. // Subtract the offsetted holes from the offsetted contours. - ClipperLib_Z::Clipper clipper; - clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) { - //pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z())); + ClipperZUtils::ZPaths output = ClipperZUtils::clip_zpaths(ctDifference, contours, false, holes, + [](const ClipperZUtils::ZPoint &, const ClipperZUtils::ZPoint &, const ClipperZUtils::ZPoint &, const ClipperZUtils::ZPoint &, ClipperZUtils::ZPoint &pt) { // Just mark the intersection. pt.z() = -1; }); - clipper.AddPaths(contours, ClipperLib_Z::ptSubject, true); - clipper.AddPaths(holes, ClipperLib_Z::ptClip, true); - ClipperLib_Z::Paths output; - clipper.Execute(ClipperLib_Z::ctDifference, output, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); if (! output.empty()) { append(out, std::move(output)); } else { @@ -582,7 +570,7 @@ void tree_supports_generate_paths( // Clip the sheath path to avoid the extruder to get exactly on the first point of the loop. const double clip_length = spacing * 0.15; const double anchor_length = spacing * 6.; - ClipperLib_Z::Paths anchor_candidates; + ClipperZUtils::ZPaths anchor_candidates; for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) { std::unique_ptr eec; ExPolygons regions_to_draw_inner_wall{expoly}; @@ -608,10 +596,10 @@ void tree_supports_generate_paths( // First genrate a 2nd perimeter loop as a source for anchor candidates. // The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection. anchor_candidates.clear(); - shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates); + shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), jtMiter, 1.2, anchor_candidates); // Orient all contours CW. for (auto &path : anchor_candidates) - if (ClipperLib_Z::Area(path) > 0) std::reverse(path.begin(), path.end()); + if (ClipperZUtils::area(path) > 0) std::reverse(path.begin(), path.end()); // Draw the perimeters. Polylines polylines; @@ -628,13 +616,13 @@ void tree_supports_generate_paths( pl.clip_end(clip_length); if (pl.size() < 2) continue; // Find the foot of the seam point on anchor_candidates. Only pick an anchor point that was created by offsetting the source contour. - ClipperLib_Z::Path *closest_contour = nullptr; - Vec2d closest_point; - int closest_point_idx = -1; - double closest_point_t = 0.; - double d2min = std::numeric_limits::max(); - Vec2d seam_pt = pl.back().cast(); - for (ClipperLib_Z::Path &path : anchor_candidates) + ClipperZUtils::ZPath *closest_contour = nullptr; + Vec2d closest_point; + int closest_point_idx = -1; + double closest_point_t = 0.; + double d2min = std::numeric_limits::max(); + Vec2d seam_pt = pl.back().cast(); + for (ClipperZUtils::ZPath &path : anchor_candidates) for (int i = 0; i < int(path.size()); ++i) { int j = next_idx_modulo(i, path); if (path[i].z() == idx_loop || path[j].z() == idx_loop) { @@ -662,14 +650,14 @@ void tree_supports_generate_paths( // Try to cut an anchor from the closest_contour. // Both closest_contour and pl are CW oriented. pl.points.emplace_back(closest_point.cast()); - const ClipperLib_Z::Path &path = *closest_contour; - double remaining_length = anchor_length - (seam_pt - closest_point).norm(); - int i = closest_point_idx; - int j = next_idx_modulo(i, *closest_contour); - Vec2d pi(path[i].x(), path[i].y()); - Vec2d pj(path[j].x(), path[j].y()); - Vec2d v = pj - pi; - double l = v.norm(); + const ClipperZUtils::ZPath &path = *closest_contour; + double remaining_length = anchor_length - (seam_pt - closest_point).norm(); + int i = closest_point_idx; + int j = next_idx_modulo(i, *closest_contour); + Vec2d pi(path[i].x(), path[i].y()); + Vec2d pj(path[j].x(), path[j].y()); + Vec2d v = pj - pi; + double l = v.norm(); if (remaining_length < (1. - closest_point_t) * l) { // Just trim the current line. pl.points.emplace_back((closest_point + v * (remaining_length / l)).cast()); diff --git a/src/libslic3r/Support/SupportCommon.hpp b/src/libslic3r/Support/SupportCommon.hpp index 531daaa0a8..e6f5b3e1ef 100644 --- a/src/libslic3r/Support/SupportCommon.hpp +++ b/src/libslic3r/Support/SupportCommon.hpp @@ -4,8 +4,16 @@ #include "../Layer.hpp" #include "../Polygon.hpp" #include "../Print.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Fill/FillBase.hpp" #include "SupportLayer.hpp" #include "SupportParameters.hpp" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Support/SupportLayer.hpp b/src/libslic3r/Support/SupportLayer.hpp index 64e3be99e7..46b41df35a 100644 --- a/src/libslic3r/Support/SupportLayer.hpp +++ b/src/libslic3r/Support/SupportLayer.hpp @@ -1,8 +1,12 @@ #ifndef slic3r_SupportLayer_hpp_ #define slic3r_SupportLayer_hpp_ +#include +#include #include #include +#include +#include // for Slic3r::deque #include "../libslic3r.h" #include "../ClipperUtils.hpp" diff --git a/src/libslic3r/Support/SupportMaterial.cpp b/src/libslic3r/Support/SupportMaterial.cpp index a955eb5ca7..ab40c155af 100644 --- a/src/libslic3r/Support/SupportMaterial.cpp +++ b/src/libslic3r/Support/SupportMaterial.cpp @@ -1,22 +1,48 @@ #include "ClipperUtils.hpp" +#include "libslic3r/ExPolygon.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" +#include "libslic3r/Flow.hpp" #include "Layer.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Polyline.hpp" #include "Print.hpp" #include "SupportMaterial.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/Support/SupportLayer.hpp" +#include "libslic3r/PrintConfig.hpp" #include "SupportCommon.hpp" #include "Geometry.hpp" #include "Point.hpp" #include "MutablePolygon.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Surface.hpp" +#include "libslic3r/TriangleSelector.hpp" +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include #include #include #include +#include +#include +#include #define SUPPORT_USE_AGG_RASTERIZER @@ -63,9 +89,9 @@ namespace Slic3r { #define PILLAR_SIZE (2.5) #define PILLAR_SPACING 10 -//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. -//#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5 -#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +//#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtMiter, 3. +//#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtMiter, 1.5 +#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtSquare, 0. static constexpr bool support_with_sheath = false; @@ -1634,7 +1660,7 @@ static inline std::tuple detect_contacts( offset( diff_polygons, scaled(SUPPORT_MATERIAL_MARGIN / NUM_MARGIN_STEPS), - ClipperLib::jtRound, + jtRound, // round mitter limit scale_(0.05)), slices_margin.polygons); diff --git a/src/libslic3r/Support/SupportMaterial.hpp b/src/libslic3r/Support/SupportMaterial.hpp index 6d5355dab1..1d5bec31b5 100644 --- a/src/libslic3r/Support/SupportMaterial.hpp +++ b/src/libslic3r/Support/SupportMaterial.hpp @@ -2,11 +2,14 @@ #define slic3r_SupportMaterial_hpp_ #include "Flow.hpp" +#include "libslic3r/Polygon.hpp" #include "PrintConfig.hpp" #include "Slicing.hpp" #include "Fill/FillBase.hpp" #include "SupportLayer.hpp" #include "SupportParameters.hpp" +#include +#include "libslic3r/libslic3r.h" namespace Slic3r { class PrintObject; diff --git a/src/libslic3r/Support/SupportParameters.hpp b/src/libslic3r/Support/SupportParameters.hpp index e9151c0c95..ebf2cc2f4e 100644 --- a/src/libslic3r/Support/SupportParameters.hpp +++ b/src/libslic3r/Support/SupportParameters.hpp @@ -1,9 +1,20 @@ #ifndef slic3r_SupportParameters_hpp_ #define slic3r_SupportParameters_hpp_ +#include #include +#include +#include +#include +#include #include "../libslic3r.h" #include "../Flow.hpp" +#include "../Layer.hpp" +#include "../Print.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Geometry.hpp" namespace Slic3r { diff --git a/src/libslic3r/Support/SupportSpotsGenerator.cpp b/src/libslic3r/Support/SupportSpotsGenerator.cpp index 6fb4908e67..a3c312ee15 100644 --- a/src/libslic3r/Support/SupportSpotsGenerator.cpp +++ b/src/libslic3r/Support/SupportSpotsGenerator.cpp @@ -4,6 +4,7 @@ #include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" +#include "libslic3r/Flow.hpp" #include "GCode/ExtrusionProcessor.hpp" #include "Line.hpp" #include "Point.hpp" @@ -20,6 +21,7 @@ #include "tbb/parallel_reduce.h" #include #include +#include #include #include #include diff --git a/src/libslic3r/Support/SupportSpotsGenerator.hpp b/src/libslic3r/Support/SupportSpotsGenerator.hpp index 615158dabb..e3c3245d47 100644 --- a/src/libslic3r/Support/SupportSpotsGenerator.hpp +++ b/src/libslic3r/Support/SupportSpotsGenerator.hpp @@ -8,6 +8,8 @@ #include "MaterialType.hpp" #include #include +#include +#include #include diff --git a/src/libslic3r/Support/TreeModelVolumes.cpp b/src/libslic3r/Support/TreeModelVolumes.cpp index 70c33aab0d..5d1a3bdb20 100644 --- a/src/libslic3r/Support/TreeModelVolumes.cpp +++ b/src/libslic3r/Support/TreeModelVolumes.cpp @@ -7,6 +7,8 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "TreeModelVolumes.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ExPolygon.hpp" #include "TreeSupportCommon.hpp" #include "../BuildVolume.hpp" @@ -18,13 +20,26 @@ #include "../PrintConfig.hpp" #include "../Utils.hpp" #include "../format.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include namespace Slic3r::TreeSupport3D { @@ -112,7 +127,7 @@ TreeModelVolumes::TreeModelVolumes( tbb::parallel_for(tbb::blocked_range(num_raft_layers, num_layers, std::min(1, std::max(16, num_layers / (8 * tbb::this_task_arena::max_concurrency())))), [&](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) - outlines[layer_idx] = polygons_simplify(to_polygons(print_object.get_layer(layer_idx - num_raft_layers)->lslices), mesh_settings.resolution, polygons_strictly_simple); + outlines[layer_idx] = polygons_simplify(to_polygons(print_object.get_layer(layer_idx - num_raft_layers)->lslices), mesh_settings.resolution); }); } #endif @@ -462,7 +477,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex // if a key does not exist when it is accessed it is added! collision_areas_offsetted[layer_idx] = offset_value == 0 ? union_(collision_areas) : - offset(union_ex(collision_areas), offset_value, ClipperLib::jtMiter, 1.2); + offset(union_ex(collision_areas), offset_value, jtMiter, 1.2); if(throw_on_cancel) throw_on_cancel(); } @@ -515,16 +530,16 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex // the conditional -0.5 ensures that plastic can never touch on the diagonal // downward when the z_distance_top_layers = 1. It is assumed to be better to // not support an overhang<90 degree than to risk fusing to it. - append(collisions, offset(union_ex(collision_areas_original), radius + required_range_x, ClipperLib::jtMiter, 1.2)); + append(collisions, offset(union_ex(collision_areas_original), radius + required_range_x, jtMiter, 1.2)); } collisions = processing_last_mesh && layer_idx < int(anti_overhang.size()) ? - union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, ClipperLib::jtMiter, 1.2)) : + union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, jtMiter, 1.2)) : union_(collisions); auto &dst = data[layer_idx]; if (processing_last_mesh) { if (! dst.empty()) collisions = union_(collisions, dst); - dst = polygons_simplify(collisions, min_resolution, polygons_strictly_simple); + dst = polygons_simplify(collisions, min_resolution); } else append(dst, std::move(collisions)); if (throw_on_cancel) @@ -552,7 +567,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex if (processing_last_mesh) { if (! dst.empty()) placable = union_(placable, dst); - dst = polygons_simplify(placable, min_resolution, polygons_strictly_simple); + dst = polygons_simplify(placable, min_resolution); } else append(dst, placable); if (throw_on_cancel) @@ -601,8 +616,8 @@ void TreeModelVolumes::calculateCollisionHolefree(const std::vectorgetCollision(m_increase_until_radius, layer_idx, false)), - 5 - increase_radius_ceil, ClipperLib::jtRound, m_min_resolution), - m_min_resolution, polygons_strictly_simple)); + 5 - increase_radius_ceil, jtRound, m_min_resolution), + m_min_resolution)); if (throw_on_cancel) throw_on_cancel(); } @@ -689,10 +704,10 @@ void TreeModelVolumes::calculateAvoidance(const std::vector &ke latest_avoidance = union_(current_layer_collisions, offset(latest_avoidance, istep + 1 == move_steps ? - last_move_step : - move_step, - ClipperLib::jtRound, m_min_resolution)); + jtRound, m_min_resolution)); if (task.to_model) latest_avoidance = diff(latest_avoidance, getPlaceableAreas(task.radius, layer_idx, throw_on_cancel)); - latest_avoidance = polygons_simplify(latest_avoidance, m_min_resolution, polygons_strictly_simple); + latest_avoidance = polygons_simplify(latest_avoidance, m_min_resolution); data.emplace_back(RadiusLayerPair{task.radius, layer_idx}, latest_avoidance); if (throw_on_cancel) throw_on_cancel(); @@ -815,12 +830,12 @@ void TreeModelVolumes::calculateWallRestrictions(const std::vector +#include +#include +#include +#include #include +#include #include #include +#include +#include #include "TreeSupportCommon.hpp" #include "../Point.hpp" #include "../Polygon.hpp" #include "../PrintConfig.hpp" +#include "libslic3r/libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 519b6e826e..10467012ff 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -1,6 +1,31 @@ +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/TriangleSelector.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Support/SupportParameters.hpp" +#include "libslic3r/Utils.hpp" #include "format.hpp" #include "ClipperUtils.hpp" #include "Fill/FillBase.hpp" @@ -14,10 +39,17 @@ #include "TreeSupportCommon.hpp" #include "TreeSupport.hpp" #include "TreeSupport3D.hpp" +#include "libslic3r/libslic3r.h" #include #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -26,6 +58,11 @@ #include #include +#include +#include +#include +#include +#include #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 @@ -664,7 +701,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p } -#define SUPPORT_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. +#define SUPPORT_SURFACES_OFFSET_PARAMETERS jtSquare, 0. void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) { bool tree_support_enable = m_object_config->enable_support.value && is_tree(m_object_config->support_type.value); @@ -2571,7 +2608,7 @@ void TreeSupport::draw_circles() Point direction = normal(pt_on_expoly - pt_on_poly, line_width_scaled / 2); hole_lower.translate(direction); // note to expand a hole, we need to do negative offset - auto hole_expanded = offset(hole_lower, -line_width_scaled / 4, ClipperLib::JoinType::jtSquare); + auto hole_expanded = offset(hole_lower, -line_width_scaled / 4, jtSquare); if (!hole_expanded.empty()) { base_area_lower.holes.push_back(std::move(hole_expanded[0])); holePropagationInfos.insert({ &base_area_lower.holes.back(), {25, direction, pt_far_on_poly} }); @@ -2584,7 +2621,7 @@ void TreeSupport::draw_circles() auto&& direction = std::get<1>(holePropagationInfos[&hole]); hole_lower.translate(direction); // note to shrink a hole, we need to do positive offset - auto hole_expanded = offset(hole_lower, line_width_scaled / 2, ClipperLib::JoinType::jtSquare); + auto hole_expanded = offset(hole_lower, line_width_scaled / 2, jtSquare); Point farPoint = std::get<2>(holePropagationInfos[&hole]) + direction * 2; if (!hole_expanded.empty()) { base_area_lower.holes.push_back(std::move(hole_expanded[0])); diff --git a/src/libslic3r/Support/TreeSupport.hpp b/src/libslic3r/Support/TreeSupport.hpp index bd5a154e26..e0da1f40c7 100644 --- a/src/libslic3r/Support/TreeSupport.hpp +++ b/src/libslic3r/Support/TreeSupport.hpp @@ -1,12 +1,26 @@ #ifndef TREESUPPORT_H #define TREESUPPORT_H +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include #include "ExPolygon.hpp" #include "Point.hpp" +#include "libslic3r/Polygon.hpp" #include "Slicing.hpp" #include "MinimumSpanningTree.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Support/TreeSupportCommon.hpp" +#include "libslic3r/Support/SupportParameters.hpp" #include "tbb/concurrent_unordered_map.h" #include "Flow.hpp" #include "PrintConfig.hpp" diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp index 3cd3f4110d..09f741ec25 100644 --- a/src/libslic3r/Support/TreeSupport3D.cpp +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -12,20 +12,47 @@ #include "BuildVolume.hpp" #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" +#include "libslic3r/Exception.hpp" +#include "libslic3r/ExPolygon.hpp" #include "Fill/Fill.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Fill/FillBase.hpp" #include "Layer.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" #include "Print.hpp" #include "MultiPoint.hpp" #include "Polygon.hpp" #include "Polyline.hpp" #include "MutablePolygon.hpp" +#include "libslic3r/Support/TreeSupportCommon.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Support/TreeModelVolumes.hpp" +#include "libslic3r/Support/SupportParameters.hpp" +#include "libslic3r/Support/SupportLayer.hpp" #include "SupportCommon.hpp" +#include "libslic3r/Surface.hpp" #include "TriangleMeshSlicer.hpp" #include "TreeSupport.hpp" #include "I18N.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Utils.hpp" +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -36,6 +63,10 @@ #include #include #include +#include +#include +#include +#include #if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32) #define TREE_SUPPORT_SHOW_ERRORS_WIN32 @@ -68,7 +99,7 @@ static inline void validate_range(const Point &pt) { static constexpr const int32_t hi = 65536 * 16384; if (pt.x() > hi || pt.y() > hi || -pt.x() > hi || -pt.y() > hi) - throw ClipperLib::clipperException("Coordinate outside allowed range"); + throw RuntimeError("Coordinate outside allowed range"); } static inline void validate_range(const Points &points) @@ -832,16 +863,16 @@ static std::optional> polyline_sample_next_point_at_dis } // offset in steps for (int i = 0; i < steps; ++ i) { - ret = diff(offset(ret, step_size, ClipperLib::jtRound, scaled(0.01)), collision_trimmed()); + ret = diff(offset(ret, step_size, jtRound, scaled(0.01)), collision_trimmed()); // ensure that if many offsets are done the performance does not suffer extremely by the new vertices of jtRound. if (i % 10 == 7) - ret = polygons_simplify(ret, scaled(0.015), polygons_strictly_simple); + ret = polygons_simplify(ret, scaled(0.015)); } // offset the remainder float last_offset = distance - steps * step_size; if (last_offset > SCALED_EPSILON) - ret = offset(ret, distance - steps * step_size, ClipperLib::jtRound, scaled(0.01)); - ret = polygons_simplify(ret, scaled(0.015), polygons_strictly_simple); + ret = offset(ret, distance - steps * step_size, jtRound, scaled(0.01)); + ret = polygons_simplify(ret, scaled(0.015)); if (do_final_difference) ret = diff(ret, collision_trimmed()); @@ -1622,8 +1653,8 @@ static Point move_inside_if_outside(const Polygons &polygons, Point from, int di safe_movement_distance, safe_movement_distance + radius, 1); } if (settings.no_error && settings.move) - // as ClipperLib::jtRound has to be used for offsets this simplify is VERY important for performance. - polygons_simplify(increased, scaled(0.025), polygons_strictly_simple); + // as jtRound has to be used for offsets this simplify is VERY important for performance. + polygons_simplify(increased, scaled(0.025)); } else // if no movement is done the areas keep parent area as no move == offset(0) increased = parent.influence_area; @@ -4145,7 +4176,7 @@ void organic_draw_branches( base_layer_polygons = smooth_outward(union_(base_layer_polygons), config.support_line_width); //FIXME was .smooth(50); //smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) : // simplify a bit, to ensure the output does not contain outrageous amounts of vertices. Should not be necessary, just a precaution. - base_layer_polygons = polygons_simplify(base_layer_polygons, std::min(scaled(0.03), double(config.resolution)), polygons_strictly_simple); + base_layer_polygons = polygons_simplify(base_layer_polygons, std::min(scaled(0.03), double(config.resolution))); } // Subtract top contact layer polygons from support base. diff --git a/src/libslic3r/Support/TreeSupport3D.hpp b/src/libslic3r/Support/TreeSupport3D.hpp index a333edb962..65a5e22975 100644 --- a/src/libslic3r/Support/TreeSupport3D.hpp +++ b/src/libslic3r/Support/TreeSupport3D.hpp @@ -9,6 +9,8 @@ #ifndef slic3r_TreeSupport_hpp #define slic3r_TreeSupport_hpp +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Layer.hpp" #include "SupportLayer.hpp" #include "TreeModelVolumes.hpp" #include "TreeSupportCommon.hpp" @@ -16,8 +18,16 @@ #include "../BoundingBox.hpp" #include "../Point.hpp" #include "../Utils.hpp" +#include "libslic3r/libslic3r.h" #include +#include +#include +#include +#include +#include +#include +#include // #define TREE_SUPPORT_SHOW_ERRORS diff --git a/src/libslic3r/Support/TreeSupportCommon.hpp b/src/libslic3r/Support/TreeSupportCommon.hpp index 07dcb324b8..97a0e31eb3 100644 --- a/src/libslic3r/Support/TreeSupportCommon.hpp +++ b/src/libslic3r/Support/TreeSupportCommon.hpp @@ -11,10 +11,28 @@ #include "../libslic3r.h" #include "../Polygon.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Slicing.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/Flow.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Support/SupportParameters.hpp" +#include "libslic3r/Support/SupportLayer.hpp" #include "SupportCommon.hpp" +#include "libslic3r/Utils.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include namespace Slic3r { @@ -588,8 +606,6 @@ private: // std::vector known_z; }; -static constexpr const bool polygons_strictly_simple = false; - inline double tiny_area_threshold() { return sqr(scaled(0.001)); } inline void tree_supports_show_error(std::string_view message, bool critical) diff --git a/src/libslic3r/Surface.cpp b/src/libslic3r/Surface.cpp index 58ac7294cc..cb7d0d4674 100644 --- a/src/libslic3r/Surface.cpp +++ b/src/libslic3r/Surface.cpp @@ -1,6 +1,11 @@ #include "BoundingBox.hpp" #include "Surface.hpp" +#include "Polygon.hpp" +#include "Point.hpp" +#include "ExPolygon.hpp" #include "SVG.hpp" +#include +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index b63c283251..1849e3462a 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -1,8 +1,16 @@ #ifndef slic3r_Surface_hpp_ #define slic3r_Surface_hpp_ +#include "Polygon.hpp" +#include "Line.hpp" +#include "Point.hpp" #include "libslic3r.h" #include "ExPolygon.hpp" +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/SurfaceCollection.cpp b/src/libslic3r/SurfaceCollection.cpp index 83015c3e6a..47109b9965 100644 --- a/src/libslic3r/SurfaceCollection.cpp +++ b/src/libslic3r/SurfaceCollection.cpp @@ -1,8 +1,18 @@ #include "SurfaceCollection.hpp" #include "BoundingBox.hpp" +#include "ExPolygon.hpp" +#include "Polygon.hpp" +#include "Point.hpp" #include "SVG.hpp" +#include "Surface.hpp" +#include +#include +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 1895516aa2..3b6316e0a4 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -1,9 +1,13 @@ #ifndef slic3r_SurfaceCollection_hpp_ #define slic3r_SurfaceCollection_hpp_ +#include "Polygon.hpp" +#include "ExPolygon.hpp" #include "libslic3r.h" #include "Surface.hpp" +#include #include +#include #include namespace Slic3r { diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 82dff2e22d..221c584697 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -2,8 +2,13 @@ #define slic3r_SurfaceMesh_hpp_ #include +#include +#include +#include #include +#include +#include "Point.hpp" #include "boost/container/small_vector.hpp" namespace Slic3r { diff --git a/src/libslic3r/Tesselate.cpp b/src/libslic3r/Tesselate.cpp index febb3d0e74..be7087a311 100644 --- a/src/libslic3r/Tesselate.cpp +++ b/src/libslic3r/Tesselate.cpp @@ -1,8 +1,17 @@ #include "Tesselate.hpp" #include "ExPolygon.hpp" +#include "Point.hpp" +#include "libslic3r.h" +#include +#include +#include +#include +#include #include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Tesselate.hpp b/src/libslic3r/Tesselate.hpp index 2dbe6caa10..f9effa242d 100644 --- a/src/libslic3r/Tesselate.hpp +++ b/src/libslic3r/Tesselate.hpp @@ -4,6 +4,7 @@ #include #include "Point.hpp" +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/TextConfiguration.hpp b/src/libslic3r/TextConfiguration.hpp index 40c8c836ac..753cec71ba 100644 --- a/src/libslic3r/TextConfiguration.hpp +++ b/src/libslic3r/TextConfiguration.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_TextConfiguration_hpp_ #define slic3r_TextConfiguration_hpp_ +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include "Point.hpp" // Transform3d +#include "libslic3r.h" namespace Slic3r { diff --git a/src/libslic3r/TextureBake/TextureBakeDebug.cpp b/src/libslic3r/TextureBake/TextureBakeDebug.cpp index 9465080e21..7b3538da72 100644 --- a/src/libslic3r/TextureBake/TextureBakeDebug.cpp +++ b/src/libslic3r/TextureBake/TextureBakeDebug.cpp @@ -1,11 +1,19 @@ #include "TextureBakeDebug.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" #include +#include +#include #include +#include #include #include #include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/TextureBake/TextureBakeDebug.hpp b/src/libslic3r/TextureBake/TextureBakeDebug.hpp index 5c6d987e44..b0cf0c1952 100644 --- a/src/libslic3r/TextureBake/TextureBakeDebug.hpp +++ b/src/libslic3r/TextureBake/TextureBakeDebug.hpp @@ -18,8 +18,10 @@ #include #include #include +#include #include +#include "libslic3r/Point.hpp" #include "TextureBakeIndex.hpp" namespace Slic3r { diff --git a/src/libslic3r/TextureBake/TextureBakeDecimate.cpp b/src/libslic3r/TextureBake/TextureBakeDecimate.cpp index ee335cff3c..c03607e99c 100644 --- a/src/libslic3r/TextureBake/TextureBakeDecimate.cpp +++ b/src/libslic3r/TextureBake/TextureBakeDecimate.cpp @@ -1,8 +1,13 @@ #include "TextureBakeDecimate.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" #include #include #include +#include +#include +#include #include #include @@ -10,6 +15,7 @@ #include #include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeDecimate.hpp b/src/libslic3r/TextureBake/TextureBakeDecimate.hpp index 5579778050..8b31dbb642 100644 --- a/src/libslic3r/TextureBake/TextureBakeDecimate.hpp +++ b/src/libslic3r/TextureBake/TextureBakeDecimate.hpp @@ -10,6 +10,7 @@ // Flat-face harvesting: the loop keeps going past the triangle target while each collapse's error // stays under an absolute bound, so flat faces that cost nothing to remove are not left behind. +#include #include #include #include diff --git a/src/libslic3r/TextureBake/TextureBakeDisplace.cpp b/src/libslic3r/TextureBake/TextureBakeDisplace.cpp index 6e306b1c43..7dee94de99 100644 --- a/src/libslic3r/TextureBake/TextureBakeDisplace.cpp +++ b/src/libslic3r/TextureBake/TextureBakeDisplace.cpp @@ -1,11 +1,18 @@ #include "TextureBakeDisplace.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" #include #include +#include +#include #include +#include #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeDisplace.hpp b/src/libslic3r/TextureBake/TextureBakeDisplace.hpp index eee6ca0626..76e70d3bc5 100644 --- a/src/libslic3r/TextureBake/TextureBakeDisplace.hpp +++ b/src/libslic3r/TextureBake/TextureBakeDisplace.hpp @@ -13,6 +13,7 @@ #include #include +#include "libslic3r/Point.hpp" #include "TextureBakeIndex.hpp" namespace Slic3r { diff --git a/src/libslic3r/TextureBake/TextureBakeFlip.cpp b/src/libslic3r/TextureBake/TextureBakeFlip.cpp index f4d9997f71..8f7000a878 100644 --- a/src/libslic3r/TextureBake/TextureBakeFlip.cpp +++ b/src/libslic3r/TextureBake/TextureBakeFlip.cpp @@ -1,13 +1,20 @@ #include "TextureBakeFlip.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/TextureBake/TextureBakeDisplace.hpp" +#include "libslic3r/Point.hpp" #include #include #include +#include +#include #include #include #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeFlip.hpp b/src/libslic3r/TextureBake/TextureBakeFlip.hpp index 02701bbced..a1057a344a 100644 --- a/src/libslic3r/TextureBake/TextureBakeFlip.hpp +++ b/src/libslic3r/TextureBake/TextureBakeFlip.hpp @@ -16,6 +16,7 @@ // flat regions cost nothing; a non-planar quad (a model crease) is never touched, nor is one whose // triangles belong to different source faces or straddle the painted boundary. +#include #include #include diff --git a/src/libslic3r/TextureBake/TextureBakeIndex.cpp b/src/libslic3r/TextureBake/TextureBakeIndex.cpp index ac7234774b..75839c746b 100644 --- a/src/libslic3r/TextureBake/TextureBakeIndex.cpp +++ b/src/libslic3r/TextureBake/TextureBakeIndex.cpp @@ -1,6 +1,9 @@ #include "TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeIndex.hpp b/src/libslic3r/TextureBake/TextureBakeIndex.hpp index 2b1dd72395..6fbfa4f831 100644 --- a/src/libslic3r/TextureBake/TextureBakeIndex.hpp +++ b/src/libslic3r/TextureBake/TextureBakeIndex.hpp @@ -11,7 +11,9 @@ #include #include +#include #include +#include #include #include "../Point.hpp" diff --git a/src/libslic3r/TextureBake/TextureBakeMesh.cpp b/src/libslic3r/TextureBake/TextureBakeMesh.cpp index 6f6d72218d..caf6e22d36 100644 --- a/src/libslic3r/TextureBake/TextureBakeMesh.cpp +++ b/src/libslic3r/TextureBake/TextureBakeMesh.cpp @@ -1,6 +1,11 @@ #include "TextureBakeMesh.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" #include +#include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeMesh.hpp b/src/libslic3r/TextureBake/TextureBakeMesh.hpp index b4e3ced5fe..860aa1445d 100644 --- a/src/libslic3r/TextureBake/TextureBakeMesh.hpp +++ b/src/libslic3r/TextureBake/TextureBakeMesh.hpp @@ -5,6 +5,8 @@ #include "TextureBakeIndex.hpp" #include "../TriangleMesh.hpp" +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakePipeline.cpp b/src/libslic3r/TextureBake/TextureBakePipeline.cpp index 2b678905b1..b44ae837bc 100644 --- a/src/libslic3r/TextureBake/TextureBakePipeline.cpp +++ b/src/libslic3r/TextureBake/TextureBakePipeline.cpp @@ -1,8 +1,21 @@ #include "TextureBakePipeline.hpp" +#include +#include +#include +#include #include #include +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TextureBake/TextureBakeDisplace.hpp" +#include "libslic3r/TextureBake/TextureBakeSubdivide.hpp" +#include "libslic3r/TextureBake/TextureBakeRegularize.hpp" +#include "libslic3r/TextureBake/TextureBakeRelocate.hpp" +#include "libslic3r/TextureBake/TextureBakeFlip.hpp" +#include "libslic3r/TextureBake/TextureBakeDecimate.hpp" +#include "libslic3r/TextureBake/TextureBakeRepair.hpp" #include "TextureBakeDebug.hpp" #include @@ -11,6 +24,8 @@ #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakePipeline.hpp b/src/libslic3r/TextureBake/TextureBakePipeline.hpp index e230cf0d49..43429ce22f 100644 --- a/src/libslic3r/TextureBake/TextureBakePipeline.hpp +++ b/src/libslic3r/TextureBake/TextureBakePipeline.hpp @@ -13,10 +13,12 @@ // Decimation and repair are export-only - decimation drops the output-to-input face mapping a bake // needs to carry per-face data forward. +#include #include #include #include +#include "libslic3r/Point.hpp" #include "TextureBakeDecimate.hpp" #include "TextureBakeDisplace.hpp" #include "TextureBakeIndex.hpp" diff --git a/src/libslic3r/TextureBake/TextureBakeRegularize.cpp b/src/libslic3r/TextureBake/TextureBakeRegularize.cpp index 3028d8bee9..fb32eb7712 100644 --- a/src/libslic3r/TextureBake/TextureBakeRegularize.cpp +++ b/src/libslic3r/TextureBake/TextureBakeRegularize.cpp @@ -1,11 +1,18 @@ #include "TextureBakeRegularize.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" #include #include +#include +#include +#include #include #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeRegularize.hpp b/src/libslic3r/TextureBake/TextureBakeRegularize.hpp index 350666783a..b6cd5eedc3 100644 --- a/src/libslic3r/TextureBake/TextureBakeRegularize.hpp +++ b/src/libslic3r/TextureBake/TextureBakeRegularize.hpp @@ -12,6 +12,7 @@ // flattened); and the link condition must hold, or the result would be non-manifold. Boundary and // non-manifold edges are skipped outright. Rounds repeat until one achieves nothing. +#include #include #include diff --git a/src/libslic3r/TextureBake/TextureBakeRelocate.cpp b/src/libslic3r/TextureBake/TextureBakeRelocate.cpp index 5ea33b353b..405ea8e286 100644 --- a/src/libslic3r/TextureBake/TextureBakeRelocate.cpp +++ b/src/libslic3r/TextureBake/TextureBakeRelocate.cpp @@ -1,11 +1,17 @@ #include "TextureBakeRelocate.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/TextureBake/TextureBakeDisplace.hpp" #include #include +#include +#include #include #include #include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeRelocate.hpp b/src/libslic3r/TextureBake/TextureBakeRelocate.hpp index cd674d03ae..36ca059dde 100644 --- a/src/libslic3r/TextureBake/TextureBakeRelocate.hpp +++ b/src/libslic3r/TextureBake/TextureBakeRelocate.hpp @@ -21,6 +21,7 @@ // Vertices in flat regions have no gradient to speak of and are left alone, so the pass costs nothing // where there is nothing to align. +#include #include #include #include diff --git a/src/libslic3r/TextureBake/TextureBakeRepair.cpp b/src/libslic3r/TextureBake/TextureBakeRepair.cpp index 438e0ea25d..49f427d461 100644 --- a/src/libslic3r/TextureBake/TextureBakeRepair.cpp +++ b/src/libslic3r/TextureBake/TextureBakeRepair.cpp @@ -1,10 +1,16 @@ #include "TextureBakeRepair.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include "libslic3r/Point.hpp" #include #include #include +#include +#include #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeRepair.hpp b/src/libslic3r/TextureBake/TextureBakeRepair.hpp index 35e9f50b06..07d5323059 100644 --- a/src/libslic3r/TextureBake/TextureBakeRepair.hpp +++ b/src/libslic3r/TextureBake/TextureBakeRepair.hpp @@ -7,6 +7,7 @@ // one incident face on one side, which a slicer reads as an open boundary. This splits the offending // face into a fan so every on-edge vertex becomes a real corner. +#include #include #include diff --git a/src/libslic3r/TextureBake/TextureBakeSubdivide.cpp b/src/libslic3r/TextureBake/TextureBakeSubdivide.cpp index 6b882b1fc8..967f88381a 100644 --- a/src/libslic3r/TextureBake/TextureBakeSubdivide.cpp +++ b/src/libslic3r/TextureBake/TextureBakeSubdivide.cpp @@ -1,12 +1,20 @@ #include "TextureBakeSubdivide.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" #include #include +#include +#include +#include +#include #include #include #include #include +#include +#include namespace Slic3r { namespace TextureBake { diff --git a/src/libslic3r/TextureBake/TextureBakeSubdivide.hpp b/src/libslic3r/TextureBake/TextureBakeSubdivide.hpp index 743c74eb49..0120160345 100644 --- a/src/libslic3r/TextureBake/TextureBakeSubdivide.hpp +++ b/src/libslic3r/TextureBake/TextureBakeSubdivide.hpp @@ -8,9 +8,12 @@ // The 1->4 case is what keeps the tessellation regular - its children are similar to the parent. An // irregular one shows up after displacement as adjacent triangles tilting alternately, i.e. noise. +#include +#include #include #include +#include "libslic3r/Point.hpp" #include "TextureBakeIndex.hpp" namespace Slic3r { diff --git a/src/libslic3r/TextureDisplacement.cpp b/src/libslic3r/TextureDisplacement.cpp index 862c6c9044..46a7cb18b4 100644 --- a/src/libslic3r/TextureDisplacement.cpp +++ b/src/libslic3r/TextureDisplacement.cpp @@ -1,7 +1,10 @@ #include "TextureDisplacement.hpp" +#include +#include #include #include +#include #include #include #include @@ -11,10 +14,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -27,11 +33,16 @@ #include #include +#include +#include #include "AABBTreeIndirect.hpp" #include "MeshBoolean.hpp" #include "Model.hpp" #include "PNGReadWrite.hpp" +#include "Point.hpp" +#include "TriangleMesh.hpp" +#include "TextureBake/TextureBakeDisplace.hpp" #include "TriangleSelector.hpp" #include "TextureBake/TextureBakeDebug.hpp" #include "TextureBake/TextureBakeMesh.hpp" diff --git a/src/libslic3r/TextureDisplacement.hpp b/src/libslic3r/TextureDisplacement.hpp index e97178abca..afe6a42911 100644 --- a/src/libslic3r/TextureDisplacement.hpp +++ b/src/libslic3r/TextureDisplacement.hpp @@ -1,10 +1,13 @@ #ifndef slic3r_TextureDisplacement_hpp_ #define slic3r_TextureDisplacement_hpp_ +#include +#include #include #include #include #include +#include #include #include diff --git a/src/libslic3r/TexturePainting.cpp b/src/libslic3r/TexturePainting.cpp index 9f83f282cd..e44f870b5d 100644 --- a/src/libslic3r/TexturePainting.cpp +++ b/src/libslic3r/TexturePainting.cpp @@ -1,9 +1,15 @@ #include "TexturePainting.hpp" #include +#include #include +#include +#include #include +#include +#include #include +#include #include #include @@ -11,11 +17,15 @@ #include #include +#include +#include "Point.hpp" +#include "TextureToColor/Callbacks.hpp" #include "TextureToColor/TextureToColor.hpp" #include "TextureToColor/ColorUtils.hpp" #include "Model.hpp" +#include "TextureToColor/TriMesh.hpp" #include "TriangleMesh.hpp" #include "TriangleSelector.hpp" diff --git a/src/libslic3r/TextureToColor/CgalUtils.hpp b/src/libslic3r/TextureToColor/CgalUtils.hpp index 109d454827..1782530bcb 100644 --- a/src/libslic3r/TextureToColor/CgalUtils.hpp +++ b/src/libslic3r/TextureToColor/CgalUtils.hpp @@ -1,8 +1,10 @@ #pragma once +#include "libslic3r/Point.hpp" #include "TriMesh.hpp" #include #include #include +#include #include #include #include diff --git a/src/libslic3r/TextureToColor/ColorUtils.cpp b/src/libslic3r/TextureToColor/ColorUtils.cpp index 7127a5d364..a32b4848b2 100644 --- a/src/libslic3r/TextureToColor/ColorUtils.cpp +++ b/src/libslic3r/TextureToColor/ColorUtils.cpp @@ -1,12 +1,26 @@ #include "ColorUtils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include +#include +#include #include +#include +#include #include #include @@ -23,11 +37,19 @@ #include #include #include +#include #include #include "CgalUtils.hpp" +#include "TriMesh.hpp" +#include "libslic3r/Point.hpp" #include "libslic3r/AABBTreeIndirect.hpp" #include +#include +#include +#include +#include +#include namespace Slic3r { namespace tex2color { namespace color_utils { diff --git a/src/libslic3r/TextureToColor/ColorUtils.hpp b/src/libslic3r/TextureToColor/ColorUtils.hpp index 05849109f4..89e6095923 100644 --- a/src/libslic3r/TextureToColor/ColorUtils.hpp +++ b/src/libslic3r/TextureToColor/ColorUtils.hpp @@ -1,7 +1,12 @@ #pragma once #include "Callbacks.hpp" +#include "libslic3r/Point.hpp" #include "TriMesh.hpp" +#include +#include +#include +#include namespace Slic3r { namespace tex2color { diff --git a/src/libslic3r/TextureToColor/Repair.hpp b/src/libslic3r/TextureToColor/Repair.hpp index 44dc30c144..092c0623fb 100644 --- a/src/libslic3r/TextureToColor/Repair.hpp +++ b/src/libslic3r/TextureToColor/Repair.hpp @@ -4,18 +4,22 @@ #include "Callbacks.hpp" #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include +#include #include #include +#include namespace Slic3r { namespace tex2color { diff --git a/src/libslic3r/TextureToColor/TextureToColor.cpp b/src/libslic3r/TextureToColor/TextureToColor.cpp index e5dde36714..15a2a641af 100644 --- a/src/libslic3r/TextureToColor/TextureToColor.cpp +++ b/src/libslic3r/TextureToColor/TextureToColor.cpp @@ -1,5 +1,12 @@ #include "TextureToColor.hpp" +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -9,14 +16,20 @@ #include #include +#include "Callbacks.hpp" #include "CgalUtils.hpp" #include "ColorUtils.hpp" +#include "TriMesh.hpp" +#include "libslic3r/Point.hpp" #include "libslic3r/TriangleMesh.hpp" #include #include #include "Repair.hpp" #include "libslic3r/AABBTreeIndirect.hpp" #include +#include +#include +#include namespace Slic3r { namespace tex2color { diff --git a/src/libslic3r/TextureToColor/TextureToColor.hpp b/src/libslic3r/TextureToColor/TextureToColor.hpp index 019a113fc4..a88fe2086e 100644 --- a/src/libslic3r/TextureToColor/TextureToColor.hpp +++ b/src/libslic3r/TextureToColor/TextureToColor.hpp @@ -1,10 +1,15 @@ #pragma once #include "Callbacks.hpp" +#include "libslic3r/Point.hpp" #include "TriMesh.hpp" #include "opencv2/core.hpp" +#include +#include #include +#include #include +#include namespace Slic3r { namespace tex2color { diff --git a/src/libslic3r/TextureToColor/TriMesh.hpp b/src/libslic3r/TextureToColor/TriMesh.hpp index d557ae1d2e..63d5286ab7 100644 --- a/src/libslic3r/TextureToColor/TriMesh.hpp +++ b/src/libslic3r/TextureToColor/TriMesh.hpp @@ -1,5 +1,8 @@ #pragma once #include +#include +#include +#include #include "Point.hpp" namespace Slic3r { namespace tex2color { diff --git a/src/libslic3r/Thread.cpp b/src/libslic3r/Thread.cpp index edd7c2a3d0..066656c9ed 100644 --- a/src/libslic3r/Thread.cpp +++ b/src/libslic3r/Thread.cpp @@ -6,6 +6,14 @@ #include #endif +#include +#include +#include +#include +#include +#include +#include + #include #include #include diff --git a/src/libslic3r/Thread.hpp b/src/libslic3r/Thread.hpp index c407159072..e40cae5f26 100644 --- a/src/libslic3r/Thread.hpp +++ b/src/libslic3r/Thread.hpp @@ -1,6 +1,7 @@ #ifndef GUI_THREAD_HPP #define GUI_THREAD_HPP +#include #include #include #include diff --git a/src/libslic3r/Time.cpp b/src/libslic3r/Time.cpp index 81b9af49e2..a9f3f07352 100644 --- a/src/libslic3r/Time.cpp +++ b/src/libslic3r/Time.cpp @@ -1,6 +1,10 @@ #include "Time.hpp" #include +#include +#include +#include +#include #include #include #include @@ -8,6 +12,8 @@ #include #include #include +#include +#include #ifdef _MSC_VER #include diff --git a/src/libslic3r/Timer.cpp b/src/libslic3r/Timer.cpp index 91f3b0f09e..1a81210c58 100644 --- a/src/libslic3r/Timer.cpp +++ b/src/libslic3r/Timer.cpp @@ -1,5 +1,7 @@ #include "Timer.hpp" #include +#include +#include using namespace std::chrono; diff --git a/src/libslic3r/Timer.hpp b/src/libslic3r/Timer.hpp index 01f73a9b3e..e122c6cb1d 100644 --- a/src/libslic3r/Timer.hpp +++ b/src/libslic3r/Timer.hpp @@ -1,8 +1,10 @@ #ifndef libslic3r_Timer_hpp_ #define libslic3r_Timer_hpp_ +#include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 9e08e6f1e0..2f047e4e7f 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1,5 +1,7 @@ +#include "BoundingBox.hpp" #include "Exception.hpp" #include "TriangleMesh.hpp" +#include "Polygon.hpp" #include "TriangleMeshSlicer.hpp" #include "MeshSplitImpl.hpp" #include "ClipperUtils.hpp" @@ -11,13 +13,26 @@ #include "CutUtils.hpp" #include "Utils.hpp" #include "Format/STL.hpp" +#include "libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b963671ce9..8c82bac52f 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -3,6 +3,11 @@ #include "libslic3r.h" #include +#include +#include +#include +#include +#include #include #include #include "BoundingBox.hpp" diff --git a/src/libslic3r/TriangleMeshDeal.cpp b/src/libslic3r/TriangleMeshDeal.cpp index 4ea3030e51..7ecfc362d1 100644 --- a/src/libslic3r/TriangleMeshDeal.cpp +++ b/src/libslic3r/TriangleMeshDeal.cpp @@ -1,5 +1,7 @@ #include "TriangleMeshDeal.hpp" +#include "TriangleMesh.hpp" +#include #include #undef NDEBUG #include diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index a08ea6b55d..2bd5e94622 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1,16 +1,29 @@ #include "ClipperUtils.hpp" +#include "ExPolygon.hpp" #include "Geometry.hpp" +#include "Point.hpp" +#include "Line.hpp" +#include "MultiPoint.hpp" +#include "Polygon.hpp" #include "Tesselate.hpp" #include "TriangleMesh.hpp" #include "TriangleMeshSlicer.hpp" #include "Utils.hpp" // BBS #include "MeshBoolean.hpp" +#include "libslic3r.h" #include +#include #include +#include +#include #include #include +#include +#include +#include +#include #include #include #include @@ -18,6 +31,7 @@ #include #include +#include #ifndef NDEBUG // #define EXPENSIVE_DEBUG_CHECKS @@ -1856,7 +1870,7 @@ static ExPolygons make_expolygons_simple(std::vector &lines) return slices; } -static void make_expolygons(const Polygons &loops, const float closing_radius, const float extra_offset, ClipperLib::PolyFillType fill_type, ExPolygons* slices) +static void make_expolygons(const Polygons &loops, const float closing_radius, const float extra_offset, PolyFillType fill_type, ExPolygons* slices) { /* Input loops are not suitable for evenodd nor nonzero fill types, as we might get @@ -2156,8 +2170,8 @@ std::vector slice_mesh_ex( const auto this_mode = layer_id < params.slicing_mode_normal_below_layer ? params.mode_below : params.mode; Slic3r::make_expolygons( layers_p[layer_id], params.closing_radius, params.extra_offset, - this_mode == MeshSlicingParams::SlicingMode::EvenOdd ? ClipperLib::pftEvenOdd : - this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour ? ClipperLib::pftPositive : ClipperLib::pftNonZero, + this_mode == MeshSlicingParams::SlicingMode::EvenOdd ? pftEvenOdd : + this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour ? pftPositive : pftNonZero, &expolygons); //FIXME simplify if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour) diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 1f7bba9d27..aa1b020716 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -1,8 +1,14 @@ #ifndef slic3r_TriangleMeshSlicer_hpp_ #define slic3r_TriangleMeshSlicer_hpp_ +#include +#include #include +#include #include +#include + +#include "Point.hpp" #include "Polygon.hpp" #include "ExPolygon.hpp" @@ -12,13 +18,13 @@ struct MeshSlicingParams { enum class SlicingMode : uint32_t { // Regular slicing, maintain all contours and their orientation. - // slice_mesh_ex() applies ClipperLib::pftNonZero rule to the result of slice_mesh(). + // slice_mesh_ex() applies pftNonZero rule to the result of slice_mesh(). Regular, // For slicing 3DLabPrints plane models (aka to be compatible with S3D default strategy). - // slice_mesh_ex() applies ClipperLib::pftEvenOdd rule. slice_mesh() slices EvenOdd as Regular. + // slice_mesh_ex() applies pftEvenOdd rule. slice_mesh() slices EvenOdd as Regular. EvenOdd, // Maintain all contours, orient all contours CCW. - // slice_mesh_ex() applies ClipperLib::pftNonZero rule, thus holes will be closed. + // slice_mesh_ex() applies pftNonZero rule, thus holes will be closed. Positive, // Orient all contours CCW and keep only the contour with the largest area. // This mode is useful for slicing complex objects in vase mode. diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index 4d6007530f..7314b00082 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -1,12 +1,31 @@ #include "TriangleSelector.hpp" +#include "Geometry.hpp" #include "Model.hpp" #include "AABBTreeIndirect.hpp" +#include "Point.hpp" +#include "libslic3r.h" +#include "Utils.hpp" +#include "TriangleMesh.hpp" +#include +#include +#include +#include #include #include +#include +#include #include +#include +#include +#include #include +#include +#include #include +#include +#include +#include #ifndef NDEBUG // #define EXPENSIVE_DEBUG_CHECKS diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 344e88cb99..3dd2efdaf0 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -4,7 +4,18 @@ // #define PRUSASLICER_TRIANGLE_SELECTOR_DEBUG +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include "Point.hpp" #include "TriangleMesh.hpp" diff --git a/src/libslic3r/TriangleSetSampling.cpp b/src/libslic3r/TriangleSetSampling.cpp index bb03ff6d75..6ab4290ee6 100644 --- a/src/libslic3r/TriangleSetSampling.cpp +++ b/src/libslic3r/TriangleSetSampling.cpp @@ -1,8 +1,13 @@ #include "TriangleSetSampling.hpp" +#include +#include "Point.hpp" +#include +#include #include #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/TriangleSetSampling.hpp b/src/libslic3r/TriangleSetSampling.hpp index 28a661d76f..ba20a932eb 100644 --- a/src/libslic3r/TriangleSetSampling.hpp +++ b/src/libslic3r/TriangleSetSampling.hpp @@ -2,6 +2,8 @@ #define SRC_LIBSLIC3R_TRIANGLESETSAMPLING_HPP_ #include +#include +#include #include "libslic3r/Point.hpp" namespace Slic3r { diff --git a/src/libslic3r/TriangulateWall.hpp b/src/libslic3r/TriangulateWall.hpp index fcdb842f9b..fcc67e29b2 100644 --- a/src/libslic3r/TriangulateWall.hpp +++ b/src/libslic3r/TriangulateWall.hpp @@ -1,7 +1,11 @@ #ifndef TRIANGULATEWALL_HPP #define TRIANGULATEWALL_HPP +#include "Point.hpp" #include "libslic3r/Polygon.hpp" +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/Triangulation.cpp b/src/libslic3r/Triangulation.cpp index f290442bf1..63a5b30fe5 100644 --- a/src/libslic3r/Triangulation.cpp +++ b/src/libslic3r/Triangulation.cpp @@ -1,10 +1,27 @@ #include "Triangulation.hpp" #include "IntersectionPoints.hpp" +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Line.hpp" +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/ExPolygon.hpp" +#include using namespace Slic3r; namespace priv{ diff --git a/src/libslic3r/Triangulation.hpp b/src/libslic3r/Triangulation.hpp index 6a168d1d20..261f76bba5 100644 --- a/src/libslic3r/Triangulation.hpp +++ b/src/libslic3r/Triangulation.hpp @@ -1,6 +1,8 @@ #ifndef libslic3r_Triangulation_hpp_ #define libslic3r_Triangulation_hpp_ +#include +#include #include #include #include diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index d142afae92..cc84b93939 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -1,9 +1,23 @@ #ifndef slic3r_Utils_hpp_ #define slic3r_Utils_hpp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include +#include +#include +#include #include #include #include @@ -19,6 +33,7 @@ #include "boost/date_time/posix_time/ptime.hpp" #include +#include #include "libslic3r.h" #include "Semver.hpp" diff --git a/src/libslic3r/VariableWidth.cpp b/src/libslic3r/VariableWidth.cpp index c00fc13bdf..db8f0bc373 100644 --- a/src/libslic3r/VariableWidth.cpp +++ b/src/libslic3r/VariableWidth.cpp @@ -1,4 +1,16 @@ #include "VariableWidth.hpp" +#include "ExtrusionEntity.hpp" +#include "Polyline.hpp" +#include "Flow.hpp" +#include "Line.hpp" +#include +#include "libslic3r.h" +#include "Point.hpp" +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/VariableWidth.hpp b/src/libslic3r/VariableWidth.hpp index f6eca97089..7b8f1f4b0a 100644 --- a/src/libslic3r/VariableWidth.hpp +++ b/src/libslic3r/VariableWidth.hpp @@ -4,6 +4,8 @@ #include "Polygon.hpp" #include "ExtrusionEntity.hpp" #include "Flow.hpp" +#include "Polyline.hpp" +#include namespace Slic3r { ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance, const float merge_tolerance); diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index aa0c6409e7..4e7e53a1b5 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -1,9 +1,14 @@ +#include +#include #include #include "Exception.hpp" #include "Zipper.hpp" #include "miniz_extension.hpp" #include +#include +#include +#include #include "I18N.hpp" //! macro used to mark string used at localization, diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp index bbaf2f05e7..dbd1fb9cc0 100644 --- a/src/libslic3r/Zipper.hpp +++ b/src/libslic3r/Zipper.hpp @@ -1,9 +1,11 @@ #ifndef ZIPPER_HPP #define ZIPPER_HPP +#include #include #include #include +#include namespace Slic3r { diff --git a/src/libslic3r/calib.cpp b/src/libslic3r/calib.cpp index 99625ca196..dd6d8592b7 100644 --- a/src/libslic3r/calib.cpp +++ b/src/libslic3r/calib.cpp @@ -1,9 +1,23 @@ #include "calib.hpp" #include "BoundingBox.hpp" #include "Config.hpp" +#include "Flow.hpp" +#include "GCodeWriter.hpp" +#include "GCode/GCodeProcessor.hpp" +#include "CustomGCode.hpp" #include "Model.hpp" #include "GCode.hpp" +#include "PrintConfig.hpp" +#include +#include "Point.hpp" +#include "libslic3r.h" #include +#include +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index abca5e79dc..fd22d4a08f 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -1,5 +1,11 @@ #pragma once +#include "Point.hpp" +#include +#include +#include #include +#include +#include #define calib_pressure_advance_dd #include "GCodeWriter.hpp" diff --git a/src/libslic3r/clipper.cpp b/src/libslic3r/clipper.cpp deleted file mode 100644 index 8f38ba6215..0000000000 --- a/src/libslic3r/clipper.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Hackish wrapper around the ClipperLib library to compile the Clipper library using Slic3r::Point. - -#include "clipper.hpp" - -// Don't include for the second time. -#define clipper_hpp - -// Override ClipperLib namespace to Slic3r::ClipperLib -#define CLIPPERLIB_NAMESPACE_PREFIX Slic3r -// Override Slic3r::ClipperLib::IntPoint to Slic3r::Point -#define CLIPPERLIB_INTPOINT_TYPE Slic3r::Point - -#include diff --git a/src/libslic3r/clipper.hpp b/src/libslic3r/clipper.hpp deleted file mode 100644 index b0dd51a4f7..0000000000 --- a/src/libslic3r/clipper.hpp +++ /dev/null @@ -1,26 +0,0 @@ -// Hackish wrapper around the ClipperLib library to compile the Clipper library using Slic3r's own Point type. - -#ifndef slic3r_clipper_hpp - -#ifdef clipper_hpp -#error "You should include the libslic3r/clipper.hpp before clipper/clipper.hpp" -#endif - -#ifdef CLIPPERLIB_USE_XYZ -#error "Something went wrong. Using clipper.hpp with Slic3r Point type, but CLIPPERLIB_USE_XYZ is defined." -#endif - -#define slic3r_clipper_hpp - -#include "Point.hpp" - -#define CLIPPERLIB_NAMESPACE_PREFIX Slic3r -#define CLIPPERLIB_INTPOINT_TYPE Slic3r::Point - -#include - -#undef clipper_hpp -#undef CLIPPERLIB_NAMESPACE_PREFIX -#undef CLIPPERLIB_INTPOINT_TYPE - -#endif // slic3r_clipper_hpp diff --git a/src/libslic3r/format.hpp b/src/libslic3r/format.hpp index c3747677b0..7f3385c3d7 100644 --- a/src/libslic3r/format.hpp +++ b/src/libslic3r/format.hpp @@ -14,6 +14,7 @@ // boost::format may convert to string, see slic3r/GUI/I18N.hpp for a "cook" function to convert wxString to UTF8. #include +#include namespace Slic3r { diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index c339da566a..bc32a8c60f 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -2,6 +2,12 @@ #define _libslic3r_h_ #include "libslic3r_version.h" +#include +#include +#include +#include +#include +#include #define SLIC3R_APP_FULL_NAME "Orca Slicer" #define GCODEVIEWER_APP_NAME "OrcaSlicer G-code Viewer" #define GCODEVIEWER_APP_KEY "OrcaSlicerGcodeViewer" diff --git a/src/libslic3r/miniz_extension.cpp b/src/libslic3r/miniz_extension.cpp index 4d9b528267..33f24a9a55 100644 --- a/src/libslic3r/miniz_extension.cpp +++ b/src/libslic3r/miniz_extension.cpp @@ -1,3 +1,8 @@ +#include +#include +#include +#include +#include #include #include @@ -6,6 +11,9 @@ #include #include +#include +#include +#include #if defined(_MSC_VER) || defined(__MINGW64__) #include "boost/nowide/cstdio.hpp" diff --git a/src/libslic3r/pchheader.hpp b/src/libslic3r/pchheader.hpp index 1bedfb482a..401e9b1145 100644 --- a/src/libslic3r/pchheader.hpp +++ b/src/libslic3r/pchheader.hpp @@ -110,8 +110,6 @@ #include #include -#include -#include "clipper.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" #include "Config.hpp" diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 849d309563..6205f11219 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -1,11 +1,43 @@ #include "Utils.hpp" +#include "Exception.hpp" #include "I18N.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include #include #include #include @@ -14,7 +46,12 @@ #include #include #include +#include +#include +#include +#include +#include "Semver.hpp" #include "format.hpp" #include "Platform.hpp" #include "Time.hpp" @@ -23,6 +60,7 @@ // (get_version_from_json) and the preset cache stamp (VendorCacheFile). #include "Preset.hpp" #include "PresetCacheFormat.hpp" +#include "libslic3r_version.h" #ifdef __APPLE__ #include "MacUtils.hpp" diff --git a/src/libvgcode/include/ColorPrint.hpp b/src/libvgcode/include/ColorPrint.hpp index 071b93a708..bbae9284a5 100644 --- a/src/libvgcode/include/ColorPrint.hpp +++ b/src/libvgcode/include/ColorPrint.hpp @@ -6,6 +6,8 @@ #define VGCODE_COLORPRINT_HPP #include "../include/Types.hpp" +#include +#include namespace libvgcode { diff --git a/src/libvgcode/include/ColorRange.hpp b/src/libvgcode/include/ColorRange.hpp index e6c83cb21d..ce34c3de7b 100644 --- a/src/libvgcode/include/ColorRange.hpp +++ b/src/libvgcode/include/ColorRange.hpp @@ -7,7 +7,10 @@ #include "../include/Types.hpp" +#include #include +#include +#include namespace libvgcode { diff --git a/src/libvgcode/include/GCodeInputData.hpp b/src/libvgcode/include/GCodeInputData.hpp index 5085322e37..a0057230e7 100644 --- a/src/libvgcode/include/GCodeInputData.hpp +++ b/src/libvgcode/include/GCodeInputData.hpp @@ -6,6 +6,8 @@ #define VGCODE_GCODEINPUTDATA_HPP #include "PathVertex.hpp" +#include +#include "Types.hpp" namespace libvgcode { diff --git a/src/libvgcode/include/PathVertex.hpp b/src/libvgcode/include/PathVertex.hpp index f5704d5376..8f24d6a440 100644 --- a/src/libvgcode/include/PathVertex.hpp +++ b/src/libvgcode/include/PathVertex.hpp @@ -7,7 +7,9 @@ #include "Types.hpp" +#include #include +#include namespace libvgcode { diff --git a/src/libvgcode/include/Types.hpp b/src/libvgcode/include/Types.hpp index 2187238ef0..1c3b50208a 100644 --- a/src/libvgcode/include/Types.hpp +++ b/src/libvgcode/include/Types.hpp @@ -5,6 +5,7 @@ #ifndef VGCODE_TYPES_HPP #define VGCODE_TYPES_HPP +#include #define VGCODE_ENABLE_COG_AND_TOOL_MARKERS 0 #include @@ -37,6 +38,8 @@ static constexpr float MAX_WIPES_RADIUS_MM = 1.0f; // Used for positions, displacements and so on. // using Vec3 = std::array; +// ORCA: the per vertex data uploaded as GL_RGBA32F, see extract_pos_and_or_hwa(). +using Vec4 = std::array; // // 4x4 square matrix with elements in column-major order: diff --git a/src/libvgcode/include/Viewer.hpp b/src/libvgcode/include/Viewer.hpp index 179105032d..a714bf1756 100644 --- a/src/libvgcode/include/Viewer.hpp +++ b/src/libvgcode/include/Viewer.hpp @@ -7,7 +7,10 @@ #include "Types.hpp" +#include +#include #include +#include namespace libvgcode { @@ -76,6 +79,14 @@ public: // caller decides which of the two it varies with the realistic view setting. // void set_tone(float exposure, float saturation); + // + // ORCA: section view. Cuts away where dot(plane, (x, y, z, 1)) < 0; { 0, 0, 0, 1 } keeps all. + // + void set_clipping_plane(const std::array& plane); + // + // ORCA: direction to the top light in eye space, shading the toolpaths and biasing their shadow lookup. + // + void set_light_top_dir(const Vec3& direction); // // ************************************************************************ diff --git a/src/libvgcode/src/Bitset.hpp b/src/libvgcode/src/Bitset.hpp index eebe297262..75dbe5580b 100644 --- a/src/libvgcode/src/Bitset.hpp +++ b/src/libvgcode/src/Bitset.hpp @@ -6,6 +6,9 @@ #define VGCODE_BITSET_HPP #include +#include +#include +#include #include namespace libvgcode { diff --git a/src/libvgcode/src/ColorRange.cpp b/src/libvgcode/src/ColorRange.cpp index 1ba0dfc526..86a034fffe 100644 --- a/src/libvgcode/src/ColorRange.cpp +++ b/src/libvgcode/src/ColorRange.cpp @@ -7,8 +7,13 @@ #include "Utils.hpp" #include +#include #include +#include #include +#include "../include/Types.hpp" +#include +#include namespace libvgcode { diff --git a/src/libvgcode/src/ExtrusionRoles.cpp b/src/libvgcode/src/ExtrusionRoles.cpp index e38886c57b..bac4eac60e 100644 --- a/src/libvgcode/src/ExtrusionRoles.cpp +++ b/src/libvgcode/src/ExtrusionRoles.cpp @@ -3,6 +3,11 @@ ///|/ libvgcode is released under the terms of the AGPLv3 or higher ///|/ #include "ExtrusionRoles.hpp" +#include "../include/Types.hpp" +#include +#include +#include +#include namespace libvgcode { diff --git a/src/libvgcode/src/ExtrusionRoles.hpp b/src/libvgcode/src/ExtrusionRoles.hpp index ee949fbf0d..5ab06cef94 100644 --- a/src/libvgcode/src/ExtrusionRoles.hpp +++ b/src/libvgcode/src/ExtrusionRoles.hpp @@ -7,7 +7,10 @@ #include "../include/Types.hpp" +#include +#include #include +#include namespace libvgcode { diff --git a/src/libvgcode/src/Layers.cpp b/src/libvgcode/src/Layers.cpp index 16a2e38fcd..5e52bc7aa9 100644 --- a/src/libvgcode/src/Layers.cpp +++ b/src/libvgcode/src/Layers.cpp @@ -9,6 +9,11 @@ #include #include +#include "../include/Types.hpp" +#include +#include +#include +#include namespace libvgcode { diff --git a/src/libvgcode/src/Layers.hpp b/src/libvgcode/src/Layers.hpp index bf3386016c..e55d1f04af 100644 --- a/src/libvgcode/src/Layers.hpp +++ b/src/libvgcode/src/Layers.hpp @@ -6,6 +6,11 @@ #define VGCODE_LAYERS_HPP #include "Range.hpp" +#include +#include +#include "../include/Types.hpp" +#include +#include namespace libvgcode { diff --git a/src/libvgcode/src/OpenGLUtils.cpp b/src/libvgcode/src/OpenGLUtils.cpp index bc39b29a4d..c6617af506 100644 --- a/src/libvgcode/src/OpenGLUtils.cpp +++ b/src/libvgcode/src/OpenGLUtils.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace libvgcode { diff --git a/src/libvgcode/src/OptionTemplate.cpp b/src/libvgcode/src/OptionTemplate.cpp index 316897ad3b..cc2b39a5ec 100644 --- a/src/libvgcode/src/OptionTemplate.cpp +++ b/src/libvgcode/src/OptionTemplate.cpp @@ -6,6 +6,9 @@ #include "OpenGLUtils.hpp" #include "Utils.hpp" +#include +#include "../include/Types.hpp" +#include #include #include #include diff --git a/src/libvgcode/src/PathVertex.cpp b/src/libvgcode/src/PathVertex.cpp index ed1569bc36..e157f20ff7 100644 --- a/src/libvgcode/src/PathVertex.cpp +++ b/src/libvgcode/src/PathVertex.cpp @@ -3,6 +3,7 @@ ///|/ libvgcode is released under the terms of the AGPLv3 or higher ///|/ #include "../include/PathVertex.hpp" +#include "../include/Types.hpp" namespace libvgcode { diff --git a/src/libvgcode/src/Range.cpp b/src/libvgcode/src/Range.cpp index 4d8df12f3d..5ef4570d1f 100644 --- a/src/libvgcode/src/Range.cpp +++ b/src/libvgcode/src/Range.cpp @@ -5,6 +5,7 @@ #include "Range.hpp" #include +#include "../include/Types.hpp" namespace libvgcode { diff --git a/src/libvgcode/src/SegmentTemplate.cpp b/src/libvgcode/src/SegmentTemplate.cpp index 9d9872aa3b..f925e0a860 100644 --- a/src/libvgcode/src/SegmentTemplate.cpp +++ b/src/libvgcode/src/SegmentTemplate.cpp @@ -5,6 +5,7 @@ #include "SegmentTemplate.hpp" #include "OpenGLUtils.hpp" +#include #include #include diff --git a/src/libvgcode/src/Settings.hpp b/src/libvgcode/src/Settings.hpp index b3aa371c4a..fe205531f2 100644 --- a/src/libvgcode/src/Settings.hpp +++ b/src/libvgcode/src/Settings.hpp @@ -7,6 +7,8 @@ #include "../include/Types.hpp" +#include +#include #include namespace libvgcode { diff --git a/src/libvgcode/src/Shaders.hpp b/src/libvgcode/src/Shaders.hpp index 9f546d6dc8..eaf143f583 100644 --- a/src/libvgcode/src/Shaders.hpp +++ b/src/libvgcode/src/Shaders.hpp @@ -14,7 +14,7 @@ static const char* Segments_Vertex_Shader = "#version 150\n" "#define POINTY_CAPS\n" "#define FIX_TWISTING\n" -"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n" +"uniform vec3 light_top_dir;\n" "const float light_top_diffuse = 0.6 * 0.8;\n" // ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen. "const float light_top_specular = 0.6 * 0.25;\n" @@ -31,13 +31,11 @@ static const char* Segments_Vertex_Shader = "uniform samplerBuffer height_width_angle_tex;\n" "uniform samplerBuffer color_tex;\n" "uniform usamplerBuffer segment_index_tex;\n" -// ORCA: 0 during the shadow caster pass - the bias below shifts eye_position but not -// world_position, so the caster would write a depth the receiver never looks up. -"uniform float bias_scale;\n" -// draw the instances last to first, top layers before the ones they hide, so that early depth -// rejection discards most of the hidden fragments; set when the camera looks down on the print -"uniform int reverse_order;\n" -"uniform int instance_count;\n" +// ORCA: draw last segment first, so looking down the top layers hide the rest from the fragment shader. +"uniform bool reverse_order;\n" +"uniform int instances_count;\n" +// ORCA: section view +"uniform vec4 clipping_plane;\n" "in int vertex_id;\n" "out vec3 color;\n" "// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n" @@ -48,13 +46,25 @@ static const char* Segments_Vertex_Shader = "// needs its world position and, for the depth bias, its eye space normal.\n" "out vec3 world_position;\n" "out vec3 shadow_normal;\n" -"vec3 decode_color(float color) {\n" +// ORCA: section view - the segment and the light on its cut face +"flat out int segment_id;\n" +"out vec3 cut_color_direct;\n" +// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors(). +"uniform ivec2 lit_layers;\n" +"uniform int grey_below_layer;\n" +"uniform float dim_brightness;\n" +"uniform int kept_vertex;\n" +"vec3 decode_color(float color, int id, int layer) {\n" " int c = int(round(color));\n" -" int r = (c >> 16) & 0xFF;\n" -" int g = (c >> 8) & 0xFF;\n" -" int b = (c >> 0) & 0xFF;\n" +" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n" +" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n" +" if (dim_brightness >= 0.0)\n" +" rgb = floor(rgb * dim_brightness);\n" +" else if (layer < grey_below_layer)\n" +" rgb = vec3(64.0);\n" +" }\n" " float f = 1.0 / 255.0f;\n" -" return f * vec3(r, g, b);\n" +" return f * rgb;\n" "}\n" "float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n" " float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n" @@ -63,7 +73,7 @@ static const char* Segments_Vertex_Shader = " return top_diffuse + front_diffuse + top_specular;\n" "}\n" "void main() {\n" -" int instance = (reverse_order != 0) ? instance_count - 1 - gl_InstanceID : gl_InstanceID;\n" +" int instance = reverse_order ? instances_count - 1 - gl_InstanceID : gl_InstanceID;\n" " int id_a = int(texelFetch(segment_index_tex, instance).r);\n" " int id_b = id_a + 1;\n" " vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n" @@ -152,22 +162,73 @@ static const char* Segments_Vertex_Shader = " }\n" " vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n" " // ORCA: Apply bias to z-position to avoid z-fighting\n" -" eye_position.z += bias * bias_scale;\n" +" eye_position.z += bias;\n" " vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n" -" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n" +" vec3 color_base = decode_color(texelFetch(color_tex, id).r, id, int(texelFetch(position_tex, id).w));\n" " color = color_base * (ambient + emission);\n" " color_direct = color_base * direct_lighting(eye_position, eye_normal);\n" " world_position = pos;\n" " shadow_normal = eye_normal;\n" +" segment_id = id_a;\n" +" cut_color_direct = clipping_plane.xyz == vec3(0.0) ? vec3(0.0) :\n" +" color_base * direct_lighting(eye_position, mat3(view_matrix) * -clipping_plane.xyz);\n" " gl_Position = projection_matrix * vec4(eye_position, 1.0);\n" "}\n"; +// ORCA: realistic view - shadow caster, one light facing ribbon per segment, not instanced as tiny instances are slow. +static const char* Segments_Shadow_Caster_Vertex_Shader = +"#version 150\n" +"const vec3 UP = vec3(0, 0, 1);\n" +"const int CORNERS[6] = int[](0, 1, 2, 0, 2, 3);\n" +"uniform mat4 view_matrix;\n" +"uniform mat4 projection_matrix;\n" +"uniform samplerBuffer position_tex;\n" +"uniform samplerBuffer height_width_angle_tex;\n" +"uniform usamplerBuffer segment_index_tex;\n" +"uniform bool reverse_order;\n" +"uniform int instances_count;\n" +"out vec3 world_position;\n" +"void main() {\n" +" int segment = gl_VertexID / 6;\n" +" int corner = CORNERS[gl_VertexID - 6 * segment];\n" +" int instance = reverse_order ? instances_count - 1 - segment : segment;\n" +" int id_a = int(texelFetch(segment_index_tex, instance).r);\n" +" int id = corner < 2 ? id_a : id_a + 1;\n" +" vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n" +" vec3 pos_b = texelFetch(position_tex, id_a + 1).xyz;\n" +" vec3 line = pos_b - pos_a;\n" +" float line_len = length(line);\n" +" vec3 line_dir = line_len < 1e-4 ? vec3(1.0, 0.0, 0.0) : line / line_len;\n" +" vec3 line_right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n" +" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n" +" vec3 to_light = vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]);\n" +" vec3 side_dir = cross(to_light, line_dir);\n" +" side_dir = dot(side_dir, side_dir) < 1e-8 ? line_right_dir : normalize(side_dir);\n" +" vec2 height_width = texelFetch(height_width_angle_tex, id).xy;\n" +" float half_extent = 0.5 * (height_width.y * abs(dot(line_right_dir, side_dir)) + height_width.x * abs(dot(line_up_dir, side_dir)));\n" +" float along = (corner < 2 ? -0.5 : 0.5) * height_width.y;\n" +" float side = (corner == 0 || corner == 3) ? -1.0 : 1.0;\n" +" vec3 pos = (corner < 2 ? pos_a : pos_b) + along * line_dir + side * half_extent * side_dir;\n" +" world_position = pos;\n" +" gl_Position = projection_matrix * (view_matrix * vec4(pos, 1.0));\n" +"}\n"; + +// ORCA: realistic view - the shadow caster writes depth only. What a section cuts away casts no shadow. +static const char* Segments_Shadow_Caster_Fragment_Shader = +"#version 150\n" +"uniform vec4 clipping_plane;\n" +"in vec3 world_position;\n" +"void main() {\n" +" if (dot(vec4(world_position, 1.0), clipping_plane) < 0.0)\n" +" discard;\n" +"}\n"; + static const char* Segments_Fragment_Shader = "#version 150\n" "// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n" "// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n" "// so the toolpaths shade exactly as before whenever realistic view is off.\n" -"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n" +"uniform vec3 light_top_dir;\n" "uniform sampler2D shadow_map;\n" "uniform mat4 shadow_light_vp;\n" "uniform float shadow_intensity;\n" @@ -178,23 +239,33 @@ static const char* Segments_Fragment_Shader = // passes in each mode is decided in GLCanvas3D::_render_gcode, not here. "uniform float exposure;\n" "uniform float saturation;\n" +// ORCA: section view - only camera-facing faces are drawn, so cut faces are ray cast +"uniform vec4 clipping_plane;\n" +"uniform mat4 view_matrix;\n" +"uniform mat4 projection_matrix;\n" +"uniform vec3 camera_position;\n" +"uniform samplerBuffer position_tex;\n" +"uniform samplerBuffer height_width_angle_tex;\n" +"const vec3 UP = vec3(0, 0, 1);\n" "const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n" "in vec3 color;\n" "in vec3 color_direct;\n" "in vec3 world_position;\n" "in vec3 shadow_normal;\n" +"flat in int segment_id;\n" +"in vec3 cut_color_direct;\n" "out vec4 fragment_color;\n" -"float shadow_shade() {\n" +"float shadow_shade(vec3 position, vec3 normal) {\n" " if (shadow_intensity <= 0.0)\n" " return 1.0;\n" -" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n" +" vec4 lp = shadow_light_vp * vec4(position, 1.0);\n" " vec3 proj = lp.xyz / lp.w;\n" " proj = proj * 0.5 + 0.5;\n" " if (proj.z > 1.0)\n" " return 1.0;\n" " // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n" " // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n" -" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n" +" float NdotL = dot(normalize(normal), light_top_dir);\n" " float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n" " float sum = 0.0;\n" " for (int x = -2; x <= 2; ++x) {\n" @@ -205,8 +276,39 @@ static const char* Segments_Fragment_Shader = " }\n" " return 1.0 - shadow_intensity * (sum / 25.0);\n" "}\n" +// ORCA: section view - where the view ray meets the plane, if inside the extrusion's diamond section +"bool find_cut(out vec3 cut) {\n" +// parallel rays for an orthographic projection +" vec3 ray = projection_matrix[3][3] == 1.0 ? -vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]) :\n" +" normalize(world_position - camera_position);\n" +" float approach = dot(clipping_plane.xyz, ray);\n" +" if (approach <= 0.0)\n" +" return false;\n" +" cut = world_position - dot(vec4(world_position, 1.0), clipping_plane) / approach * ray;\n" +" vec3 pos_a = texelFetch(position_tex, segment_id).xyz;\n" +" vec3 line = texelFetch(position_tex, segment_id + 1).xyz - pos_a;\n" +" float length_sq = dot(line, line);\n" +" float along = length_sq < 1e-8 ? -1.0 : dot(cut - pos_a, line) / length_sq;\n" +" if (along < 0.0 || along > 1.0)\n" +" return false;\n" +" vec3 line_dir = line * inversesqrt(length_sq);\n" +" vec3 right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n" +" vec3 offset = cut - pos_a - along * line;\n" +" vec2 half_height_width = 0.5 * mix(texelFetch(height_width_angle_tex, segment_id).xy,\n" +" texelFetch(height_width_angle_tex, segment_id + 1).xy, along);\n" +" return abs(dot(offset, right_dir)) / half_height_width.y + abs(dot(offset, cross(right_dir, line_dir))) / half_height_width.x <= 1.0;\n" +"}\n" "void main() {\n" -" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n" +" vec3 c;\n" +" if (dot(vec4(world_position, 1.0), clipping_plane) >= 0.0)\n" +" c = color + color_direct * shadow_shade(world_position, shadow_normal);\n" +" else {\n" +" vec3 cut;\n" +" if (!find_cut(cut))\n" +" discard;\n" +" c = color + cut_color_direct * shadow_shade(cut, mat3(view_matrix) * -clipping_plane.xyz);\n" +" }\n" +" c *= exposure;\n" " c = mix(vec3(dot(c, LUMA)), c, saturation);\n" " fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n" "}\n"; @@ -234,16 +336,28 @@ static const char* Options_Vertex_Shader = "uniform samplerBuffer height_width_angle_tex;\n" "uniform samplerBuffer color_tex;\n" "uniform usamplerBuffer segment_index_tex;\n" +// ORCA: section view +"uniform vec4 clipping_plane;\n" "in vec3 in_position;\n" "in vec3 in_normal;\n" "out vec3 color;\n" -"vec3 decode_color(float color) {\n" +"out float clipping_plane_dot;\n" +// ORCA: as in Segments_Vertex_Shader. +"uniform ivec2 lit_layers;\n" +"uniform int grey_below_layer;\n" +"uniform float dim_brightness;\n" +"uniform int kept_vertex;\n" +"vec3 decode_color(float color, int id, int layer) {\n" " int c = int(round(color));\n" -" int r = (c >> 16) & 0xFF;\n" -" int g = (c >> 8) & 0xFF;\n" -" int b = (c >> 0) & 0xFF;\n" +" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n" +" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n" +" if (dim_brightness >= 0.0)\n" +" rgb = floor(rgb * dim_brightness);\n" +" else if (layer < grey_below_layer)\n" +" rgb = vec3(64.0);\n" +" }\n" " float f = 1.0 / 255.0f;\n" -" return f * vec3(r, g, b);\n" +" return f * rgb;\n" "}\n" "float lighting(vec3 eye_position, vec3 eye_normal) {\n" " float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n" @@ -263,11 +377,13 @@ static const char* Options_Vertex_Shader = " height_width.y, 0.0, 0.0,\n" " 0.0, height_width.y, 0.0,\n" " 0.0, 0.0, height_width.x);\n" +// ORCA: section view - markers are cut away whole, by their centre +" clipping_plane_dot = dot(vec4(offset, 1.0), clipping_plane);\n" " vec3 eye_position = (view_matrix * vec4(scale_matrix * in_position + offset, 1.0)).xyz;\n" " // ORCA: Apply bias to z-position to avoid z-fighting\n" " eye_position.z += bias;\n" " vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n" -" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n" +" vec3 color_base = decode_color(texelFetch(color_tex, id).r, id, int(texelFetch(position_tex, id).w));\n" " color = color_base * lighting(eye_position, eye_normal);\n" " gl_Position = projection_matrix * vec4(eye_position, 1.0);\n" "}\n"; @@ -275,8 +391,11 @@ static const char* Options_Vertex_Shader = static const char* Options_Fragment_Shader = "#version 150\n" "in vec3 color;\n" +"in float clipping_plane_dot;\n" "out vec4 fragment_color;\n" "void main() {\n" +" if (clipping_plane_dot < 0.0)\n" +" discard;\n" " fragment_color = vec4(color, 1.0);\n" "}\n"; diff --git a/src/libvgcode/src/ShadersES.hpp b/src/libvgcode/src/ShadersES.hpp index 4194b836e3..12871f6249 100644 --- a/src/libvgcode/src/ShadersES.hpp +++ b/src/libvgcode/src/ShadersES.hpp @@ -15,7 +15,7 @@ static const char* Segments_Vertex_Shader_ES = "precision lowp usampler2D;\n" "#define POINTY_CAPS\n" "#define FIX_TWISTING\n" -"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n" +"uniform vec3 light_top_dir;\n" "const float light_top_diffuse = 0.6 * 0.8;\n" // ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen. "const float light_top_specular = 0.6 * 0.25;\n" @@ -32,6 +32,11 @@ static const char* Segments_Vertex_Shader_ES = "uniform sampler2D height_width_angle_tex;\n" "uniform sampler2D color_tex;\n" "uniform usampler2D segment_index_tex;\n" +// ORCA: draw last segment first, so looking down the top layers hide the rest from the fragment shader. +"uniform bool reverse_order;\n" +"uniform int instances_count;\n" +// ORCA: section view +"uniform vec4 clipping_plane;\n" "in float vertex_id_float;\n" "out vec3 color;\n" "// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n" @@ -42,13 +47,25 @@ static const char* Segments_Vertex_Shader_ES = "// needs its world position and, for the depth bias, its eye space normal.\n" "out vec3 world_position;\n" "out vec3 shadow_normal;\n" -"vec3 decode_color(float color) {\n" +// ORCA: section view - the segment and the light on its cut face +"flat out int segment_id;\n" +"out vec3 cut_color_direct;\n" +// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors(). +"uniform ivec2 lit_layers;\n" +"uniform int grey_below_layer;\n" +"uniform float dim_brightness;\n" +"uniform int kept_vertex;\n" +"vec3 decode_color(float color, int id, int layer) {\n" " int c = int(round(color));\n" -" int r = (c >> 16) & 0xFF;\n" -" int g = (c >> 8) & 0xFF;\n" -" int b = (c >> 0) & 0xFF;\n" +" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n" +" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n" +" if (dim_brightness >= 0.0)\n" +" rgb = floor(rgb * dim_brightness);\n" +" else if (layer < grey_below_layer)\n" +" rgb = vec3(64.0);\n" +" }\n" " float f = 1.0 / 255.0f;\n" -" return f * vec3(r, g, b);\n" +" return f * rgb;\n" "}\n" "float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n" " float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n" @@ -66,7 +83,8 @@ static const char* Segments_Vertex_Shader_ES = "}\n" "void main() {\n" " int vertex_id = int(vertex_id_float);\n" -" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, gl_InstanceID), 0).r);\n" +" int instance = reverse_order ? instances_count - 1 - gl_InstanceID : gl_InstanceID;\n" +" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, instance), 0).r);\n" " int id_b = id_a + 1;\n" " vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;\n" " vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_b), 0).xyz;\n" @@ -151,24 +169,87 @@ static const char* Segments_Vertex_Shader_ES = " }\n" " vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n" " vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n" -" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n" +" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r, id, int(texelFetch(position_tex, tex_coord(position_tex, id), 0).w));\n" " color = color_base * (ambient + emission);\n" " color_direct = color_base * direct_lighting(eye_position, eye_normal);\n" " world_position = pos;\n" " shadow_normal = eye_normal;\n" +" segment_id = id_a;\n" +" cut_color_direct = clipping_plane.xyz == vec3(0.0) ? vec3(0.0) :\n" +" color_base * direct_lighting(eye_position, mat3(view_matrix) * -clipping_plane.xyz);\n" " gl_Position = projection_matrix * vec4(eye_position, 1.0);\n" "}\n"; +// ORCA: realistic view - shadow caster, one light facing ribbon per segment, not instanced as tiny instances are slow. +static const char* Segments_Shadow_Caster_Vertex_Shader_ES = +"#version 300 es\n" +"precision lowp usampler2D;\n" +"const vec3 UP = vec3(0, 0, 1);\n" +"const int CORNERS[6] = int[](0, 1, 2, 0, 2, 3);\n" +"uniform mat4 view_matrix;\n" +"uniform mat4 projection_matrix;\n" +"uniform sampler2D position_tex;\n" +"uniform sampler2D height_width_angle_tex;\n" +"uniform usampler2D segment_index_tex;\n" +"uniform bool reverse_order;\n" +"uniform int instances_count;\n" +"out vec3 world_position;\n" +"ivec2 tex_coord(sampler2D sampler, int id) {\n" +" ivec2 tex_size = textureSize(sampler, 0);\n" +" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n" +"}\n" +"ivec2 tex_coord_u(usampler2D sampler, int id) {\n" +" ivec2 tex_size = textureSize(sampler, 0);\n" +" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n" +"}\n" +"void main() {\n" +" int segment = gl_VertexID / 6;\n" +" int corner = CORNERS[gl_VertexID - 6 * segment];\n" +" int instance = reverse_order ? instances_count - 1 - segment : segment;\n" +" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, instance), 0).r);\n" +" int id = corner < 2 ? id_a : id_a + 1;\n" +" vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;\n" +" vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_a + 1), 0).xyz;\n" +" vec3 line = pos_b - pos_a;\n" +" float line_len = length(line);\n" +" vec3 line_dir = line_len < 1e-4 ? vec3(1.0, 0.0, 0.0) : line / line_len;\n" +" vec3 line_right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n" +" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n" +" vec3 to_light = vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]);\n" +" vec3 side_dir = cross(to_light, line_dir);\n" +" side_dir = dot(side_dir, side_dir) < 1e-8 ? line_right_dir : normalize(side_dir);\n" +" vec2 height_width = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0).xy;\n" +" float half_extent = 0.5 * (height_width.y * abs(dot(line_right_dir, side_dir)) + height_width.x * abs(dot(line_up_dir, side_dir)));\n" +" float along = (corner < 2 ? -0.5 : 0.5) * height_width.y;\n" +" float side = (corner == 0 || corner == 3) ? -1.0 : 1.0;\n" +" vec3 pos = (corner < 2 ? pos_a : pos_b) + along * line_dir + side * half_extent * side_dir;\n" +" world_position = pos;\n" +" gl_Position = projection_matrix * (view_matrix * vec4(pos, 1.0));\n" +"}\n"; + +// ORCA: realistic view - the shadow caster writes depth only. What a section cuts away casts no shadow. +static const char* Segments_Shadow_Caster_Fragment_Shader_ES = +"#version 300 es\n" +"precision highp float;\n" +"uniform vec4 clipping_plane;\n" +"in vec3 world_position;\n" +"void main() {\n" +" if (dot(vec4(world_position, 1.0), clipping_plane) < 0.0)\n" +" discard;\n" +"}\n"; + static const char* Segments_Fragment_Shader_ES = "#version 300 es\n" "precision highp float;\n" +// ORCA: section view - segment ids exceed mediump +"precision highp int;\n" "// ORCA: sampler2D defaults to lowp in an ES fragment shader, far too coarse to compare\n" "// shadow map depths against.\n" "precision highp sampler2D;\n" "// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n" "// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n" "// so the toolpaths shade exactly as before whenever realistic view is off.\n" -"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n" +"uniform vec3 light_top_dir;\n" "uniform sampler2D shadow_map;\n" "uniform mat4 shadow_light_vp;\n" "uniform float shadow_intensity;\n" @@ -179,23 +260,33 @@ static const char* Segments_Fragment_Shader_ES = // passes in each mode is decided in GLCanvas3D::_render_gcode, not here. "uniform float exposure;\n" "uniform float saturation;\n" +// ORCA: section view - cut faces are ray cast; data samplers stay lowp as in the vertex shader +"uniform vec4 clipping_plane;\n" +"uniform mat4 view_matrix;\n" +"uniform mat4 projection_matrix;\n" +"uniform vec3 camera_position;\n" +"uniform lowp sampler2D position_tex;\n" +"uniform lowp sampler2D height_width_angle_tex;\n" +"const vec3 UP = vec3(0, 0, 1);\n" "const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n" "in vec3 color;\n" "in vec3 color_direct;\n" "in vec3 world_position;\n" "in vec3 shadow_normal;\n" +"flat in int segment_id;\n" +"in vec3 cut_color_direct;\n" "out vec4 fragment_color;\n" -"float shadow_shade() {\n" +"float shadow_shade(vec3 position, vec3 normal) {\n" " if (shadow_intensity <= 0.0)\n" " return 1.0;\n" -" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n" +" vec4 lp = shadow_light_vp * vec4(position, 1.0);\n" " vec3 proj = lp.xyz / lp.w;\n" " proj = proj * 0.5 + 0.5;\n" " if (proj.z > 1.0)\n" " return 1.0;\n" " // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n" " // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n" -" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n" +" float NdotL = dot(normalize(normal), light_top_dir);\n" " float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n" " float sum = 0.0;\n" " for (int x = -2; x <= 2; ++x) {\n" @@ -206,8 +297,43 @@ static const char* Segments_Fragment_Shader_ES = " }\n" " return 1.0 - shadow_intensity * (sum / 25.0);\n" "}\n" +"vec4 fetch(lowp sampler2D sampler, int id) {\n" +" ivec2 tex_size = textureSize(sampler, 0);\n" +" return texelFetch(sampler, (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x), 0);\n" +"}\n" +// ORCA: section view - where the view ray meets the plane, if inside the extrusion's diamond section +"bool find_cut(out vec3 cut) {\n" +// parallel rays for an orthographic projection +" vec3 ray = projection_matrix[3][3] == 1.0 ? -vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]) :\n" +" normalize(world_position - camera_position);\n" +" float approach = dot(clipping_plane.xyz, ray);\n" +" if (approach <= 0.0)\n" +" return false;\n" +" cut = world_position - dot(vec4(world_position, 1.0), clipping_plane) / approach * ray;\n" +" vec3 pos_a = fetch(position_tex, segment_id).xyz;\n" +" vec3 line = fetch(position_tex, segment_id + 1).xyz - pos_a;\n" +" float length_sq = dot(line, line);\n" +" float along = length_sq < 1e-8 ? -1.0 : dot(cut - pos_a, line) / length_sq;\n" +" if (along < 0.0 || along > 1.0)\n" +" return false;\n" +" vec3 line_dir = line * inversesqrt(length_sq);\n" +" vec3 right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n" +" vec3 offset = cut - pos_a - along * line;\n" +" vec2 half_height_width = 0.5 * mix(fetch(height_width_angle_tex, segment_id).xy,\n" +" fetch(height_width_angle_tex, segment_id + 1).xy, along);\n" +" return abs(dot(offset, right_dir)) / half_height_width.y + abs(dot(offset, cross(right_dir, line_dir))) / half_height_width.x <= 1.0;\n" +"}\n" "void main() {\n" -" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n" +" vec3 c;\n" +" if (dot(vec4(world_position, 1.0), clipping_plane) >= 0.0)\n" +" c = color + color_direct * shadow_shade(world_position, shadow_normal);\n" +" else {\n" +" vec3 cut;\n" +" if (!find_cut(cut))\n" +" discard;\n" +" c = color + cut_color_direct * shadow_shade(cut, mat3(view_matrix) * -clipping_plane.xyz);\n" +" }\n" +" c *= exposure;\n" " c = mix(vec3(dot(c, LUMA)), c, saturation);\n" " fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n" "}\n"; @@ -230,16 +356,28 @@ static const char* Options_Vertex_Shader_ES = "uniform sampler2D height_width_angle_tex;\n" "uniform sampler2D color_tex;\n" "uniform usampler2D segment_index_tex;\n" +// ORCA: section view +"uniform vec4 clipping_plane;\n" "in vec3 in_position;\n" "in vec3 in_normal;\n" "out vec3 color;\n" -"vec3 decode_color(float color) {\n" +"out float clipping_plane_dot;\n" +// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors(). +"uniform ivec2 lit_layers;\n" +"uniform int grey_below_layer;\n" +"uniform float dim_brightness;\n" +"uniform int kept_vertex;\n" +"vec3 decode_color(float color, int id, int layer) {\n" " int c = int(round(color));\n" -" int r = (c >> 16) & 0xFF;\n" -" int g = (c >> 8) & 0xFF;\n" -" int b = (c >> 0) & 0xFF;\n" +" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n" +" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n" +" if (dim_brightness >= 0.0)\n" +" rgb = floor(rgb * dim_brightness);\n" +" else if (layer < grey_below_layer)\n" +" rgb = vec3(64.0);\n" +" }\n" " float f = 1.0 / 255.0f;\n" -" return f * vec3(r, g, b);\n" +" return f * rgb;\n" "}\n" "float lighting(vec3 eye_position, vec3 eye_normal) {\n" " float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n" @@ -264,9 +402,11 @@ static const char* Options_Vertex_Shader_ES = " height_width.y, 0.0, 0.0,\n" " 0.0, height_width.y, 0.0,\n" " 0.0, 0.0, height_width.x);\n" +// ORCA: section view - markers are cut away whole, by their centre +" clipping_plane_dot = dot(vec4(offset, 1.0), clipping_plane);\n" " vec3 eye_position = (view_matrix * vec4(scale_matrix * in_position + offset, 1.0)).xyz;\n" " vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n" -" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n" +" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r, id, int(texelFetch(position_tex, tex_coord(position_tex, id), 0).w));\n" " color = color_base * lighting(eye_position, eye_normal);\n" " gl_Position = projection_matrix * vec4(eye_position, 1.0);\n" "}\n"; @@ -275,8 +415,11 @@ static const char* Options_Fragment_Shader_ES = "#version 300 es\n" "precision highp float;\n" "in vec3 color;\n" +"in float clipping_plane_dot;\n" "out vec4 fragment_color;\n" "void main() {\n" +" if (clipping_plane_dot < 0.0)\n" +" discard;\n" " fragment_color = vec4(color, 1.0);\n" "}\n"; diff --git a/src/libvgcode/src/ToolMarker.cpp b/src/libvgcode/src/ToolMarker.cpp index 3e595faec0..f4447fe9ad 100644 --- a/src/libvgcode/src/ToolMarker.cpp +++ b/src/libvgcode/src/ToolMarker.cpp @@ -7,6 +7,7 @@ #include "Utils.hpp" #include +#include "../include/Types.hpp" #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS diff --git a/src/libvgcode/src/Types.cpp b/src/libvgcode/src/Types.cpp index 2aa8a40e9d..1badfae81b 100644 --- a/src/libvgcode/src/Types.cpp +++ b/src/libvgcode/src/Types.cpp @@ -5,6 +5,7 @@ #include "../include/Types.hpp" #include +#include namespace libvgcode { diff --git a/src/libvgcode/src/Utils.cpp b/src/libvgcode/src/Utils.cpp index aee2cd4875..46ed6a336c 100644 --- a/src/libvgcode/src/Utils.cpp +++ b/src/libvgcode/src/Utils.cpp @@ -6,6 +6,9 @@ #include #include +#include "../include/Types.hpp" +#include +#include namespace libvgcode { diff --git a/src/libvgcode/src/Utils.hpp b/src/libvgcode/src/Utils.hpp index 84c3deb3c5..4db67e426f 100644 --- a/src/libvgcode/src/Utils.hpp +++ b/src/libvgcode/src/Utils.hpp @@ -6,6 +6,8 @@ #define VGCODE_UTILS_HPP #include "../include/Types.hpp" +#include +#include #ifdef _WIN32 #define STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE) diff --git a/src/libvgcode/src/ViewRange.cpp b/src/libvgcode/src/ViewRange.cpp index ea2f1e916e..b5657da1b7 100644 --- a/src/libvgcode/src/ViewRange.cpp +++ b/src/libvgcode/src/ViewRange.cpp @@ -3,6 +3,7 @@ ///|/ libvgcode is released under the terms of the AGPLv3 or higher ///|/ #include "ViewRange.hpp" +#include "../include/Types.hpp" namespace libvgcode { diff --git a/src/libvgcode/src/ViewRange.hpp b/src/libvgcode/src/ViewRange.hpp index b9356fc760..7d5f9eb32e 100644 --- a/src/libvgcode/src/ViewRange.hpp +++ b/src/libvgcode/src/ViewRange.hpp @@ -6,6 +6,7 @@ #define VGCODE_VIEWRANGE_HPP #include "Range.hpp" +#include "../include/Types.hpp" namespace libvgcode { diff --git a/src/libvgcode/src/Viewer.cpp b/src/libvgcode/src/Viewer.cpp index 61d7310508..b082a6e29d 100644 --- a/src/libvgcode/src/Viewer.cpp +++ b/src/libvgcode/src/Viewer.cpp @@ -4,6 +4,12 @@ ///|/ #include "../include/Viewer.hpp" #include "ViewerImpl.hpp" +#include +#include +#include "../include/Types.hpp" +#include +#include +#include namespace libvgcode { @@ -52,11 +58,21 @@ void Viewer::set_shadow_map(int texture_unit, const Mat4x4& light_view_projectio m_impl->set_shadow_map(texture_unit, light_view_projection, intensity, texel_size); } +void Viewer::set_light_top_dir(const Vec3& direction) +{ + m_impl->set_light_top_dir(direction); +} + void Viewer::set_tone(float exposure, float saturation) { m_impl->set_tone(exposure, saturation); } +void Viewer::set_clipping_plane(const std::array& plane) +{ + m_impl->set_clipping_plane(plane); +} + EViewType Viewer::get_view_type() const { return m_impl->get_view_type(); diff --git a/src/libvgcode/src/ViewerImpl.cpp b/src/libvgcode/src/ViewerImpl.cpp index 8212717931..8dc908d6d8 100644 --- a/src/libvgcode/src/ViewerImpl.cpp +++ b/src/libvgcode/src/ViewerImpl.cpp @@ -9,14 +9,26 @@ #include "OpenGLUtils.hpp" #include "Utils.hpp" +#include +#include "../include/Types.hpp" +#include +#include "../include/PathVertex.hpp" +#include "Bitset.hpp" +#include "../include/ColorPrint.hpp" +#include +#include #include #include +#include #include #include #include #include #include #include +#include +#include +#include namespace libvgcode { @@ -349,7 +361,7 @@ void ViewerImpl::TextureData::init(size_t vertices_count) m_tex_ids = std::vector(m_count); } -void ViewerImpl::TextureData::set_positions(const std::vector& positions) +void ViewerImpl::TextureData::set_positions(const std::vector& positions) { if (m_count == 0) return; @@ -383,17 +395,17 @@ void ViewerImpl::TextureData::set_positions(const std::vector& positions) glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); if (remaining >= tex_capacity) { - glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast(w), static_cast(h), 0, GL_RGB, GL_FLOAT, &positions[offset])); + glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast(w), static_cast(h), 0, GL_RGBA, GL_FLOAT, &positions[offset])); m_tex_ids[i].positions.second = w * h; } else { // the last row is only partially fitted with data, send it separately - glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast(w), static_cast(h), 0, GL_RGB, GL_FLOAT, nullptr)); - glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast(w), static_cast(h - 1), GL_RGB, GL_FLOAT, &positions[offset])); - glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast(h - 1), static_cast(remaining % w), 1, GL_RGB, GL_FLOAT, &positions[offset + w * (h - 1)])); + glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast(w), static_cast(h), 0, GL_RGBA, GL_FLOAT, nullptr)); + glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast(w), static_cast(h - 1), GL_RGBA, GL_FLOAT, &positions[offset])); + glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast(h - 1), static_cast(remaining % w), 1, GL_RGBA, GL_FLOAT, &positions[offset + w * (h - 1)])); m_tex_ids[i].positions.second = w * (h - 1) + remaining % w; } - m_positions_size += m_tex_ids[i].positions.second * sizeof(Vec3); + m_positions_size += m_tex_ids[i].positions.second * sizeof(Vec4); remaining = (remaining > tex_capacity) ? remaining - tex_capacity: 0; } @@ -402,7 +414,7 @@ void ViewerImpl::TextureData::set_positions(const std::vector& positions) glsafe(glPixelStorei(GL_UNPACK_ALIGNMENT, curr_unpack_alignment)); } -void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector& heights_widths_angles) +void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector& heights_widths_angles) { if (m_count == 0) return; @@ -436,17 +448,17 @@ void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector& glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); if (remaining >= tex_capacity) { - glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast(w), static_cast(h), 0, GL_RGB, GL_FLOAT, &heights_widths_angles[offset])); + glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast(w), static_cast(h), 0, GL_RGBA, GL_FLOAT, &heights_widths_angles[offset])); m_tex_ids[i].heights_widths_angles.second = w * h; } else { // the last row is only partially fitted with data, send it separately - glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast(w), static_cast(h), 0, GL_RGB, GL_FLOAT, nullptr)); - glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast(w), static_cast(h - 1), GL_RGB, GL_FLOAT, &heights_widths_angles[offset])); - glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast(h - 1), static_cast(remaining % w), 1, GL_RGB, GL_FLOAT, &heights_widths_angles[offset + w * (h - 1)])); + glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast(w), static_cast(h), 0, GL_RGBA, GL_FLOAT, nullptr)); + glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast(w), static_cast(h - 1), GL_RGBA, GL_FLOAT, &heights_widths_angles[offset])); + glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast(h - 1), static_cast(remaining % w), 1, GL_RGBA, GL_FLOAT, &heights_widths_angles[offset + w * (h - 1)])); m_tex_ids[i].heights_widths_angles.second = w * (h - 1) + remaining % w; } - m_height_width_angle_size += m_tex_ids[i].heights_widths_angles.second * sizeof(Vec3); + m_height_width_angle_size += m_tex_ids[i].heights_widths_angles.second * sizeof(Vec4); remaining = (remaining > tex_capacity) ? remaining - tex_capacity : 0; } @@ -732,6 +744,21 @@ ViewerImpl::ViewerImpl() reset_default_options_colors(); } +void ViewerImpl::SegmentsUniforms::init(unsigned int shader_id) +{ + view_matrix = glGetUniformLocation(shader_id, "view_matrix"); + projection_matrix = glGetUniformLocation(shader_id, "projection_matrix"); + camera_position = glGetUniformLocation(shader_id, "camera_position"); + positions_tex = glGetUniformLocation(shader_id, "position_tex"); + height_width_angle_tex = glGetUniformLocation(shader_id, "height_width_angle_tex"); + colors_tex = glGetUniformLocation(shader_id, "color_tex"); + segment_index_tex = glGetUniformLocation(shader_id, "segment_index_tex"); + reverse_order = glGetUniformLocation(shader_id, "reverse_order"); + instances_count = glGetUniformLocation(shader_id, "instances_count"); + // ORCA: section view + clipping_plane = glGetUniformLocation(shader_id, "clipping_plane"); +} + void ViewerImpl::init(const std::string& opengl_context_version) { if (m_initialized) @@ -756,15 +783,7 @@ void ViewerImpl::init(const std::string& opengl_context_version) m_segments_shader_id = init_shader("segments", Segments_Vertex_Shader, Segments_Fragment_Shader); #endif // ENABLE_OPENGL_ES - m_uni_segments_view_matrix_id = glGetUniformLocation(m_segments_shader_id, "view_matrix"); - m_uni_segments_projection_matrix_id = glGetUniformLocation(m_segments_shader_id, "projection_matrix"); - m_uni_segments_camera_position_id = glGetUniformLocation(m_segments_shader_id, "camera_position"); - m_uni_segments_positions_tex_id = glGetUniformLocation(m_segments_shader_id, "position_tex"); - m_uni_segments_height_width_angle_tex_id = glGetUniformLocation(m_segments_shader_id, "height_width_angle_tex"); - m_uni_segments_colors_tex_id = glGetUniformLocation(m_segments_shader_id, "color_tex"); - m_uni_segments_segment_index_tex_id = glGetUniformLocation(m_segments_shader_id, "segment_index_tex"); - m_uni_segments_reverse_order_id = glGetUniformLocation(m_segments_shader_id, "reverse_order"); - m_uni_segments_instance_count_id = glGetUniformLocation(m_segments_shader_id, "instance_count"); + m_uni_segments.init(m_segments_shader_id); // ORCA: realistic view m_uni_segments_shadow_map_id = glGetUniformLocation(m_segments_shader_id, "shadow_map"); m_uni_segments_shadow_light_vp_id = glGetUniformLocation(m_segments_shader_id, "shadow_light_vp"); @@ -772,15 +791,29 @@ void ViewerImpl::init(const std::string& opengl_context_version) m_uni_segments_shadow_map_texel_id = glGetUniformLocation(m_segments_shader_id, "shadow_map_texel"); m_uni_segments_exposure_id = glGetUniformLocation(m_segments_shader_id, "exposure"); m_uni_segments_saturation_id = glGetUniformLocation(m_segments_shader_id, "saturation"); - m_uni_segments_bias_scale_id = glGetUniformLocation(m_segments_shader_id, "bias_scale"); + m_uni_segments_light_top_dir_id = glGetUniformLocation(m_segments_shader_id, "light_top_dir"); + m_uni_segments_layer_colors.init(m_segments_shader_id); + glcheck(); + assert(m_uni_segments.view_matrix != -1 && + m_uni_segments.projection_matrix != -1 && + m_uni_segments.camera_position != -1 && + m_uni_segments.positions_tex != -1 && + m_uni_segments.height_width_angle_tex != -1 && + m_uni_segments.colors_tex != -1 && + m_uni_segments.segment_index_tex != -1 && + m_uni_segments.reverse_order != -1 && + m_uni_segments.instances_count != -1); + + // ORCA: realistic view +#ifdef ENABLE_OPENGL_ES + m_segments_caster_shader_id = init_shader("segments_shadow_caster", Segments_Shadow_Caster_Vertex_Shader_ES, Segments_Shadow_Caster_Fragment_Shader_ES); +#else + m_segments_caster_shader_id = init_shader("segments_shadow_caster", Segments_Shadow_Caster_Vertex_Shader, Segments_Shadow_Caster_Fragment_Shader); +#endif // ENABLE_OPENGL_ES + m_uni_segments_caster.init(m_segments_caster_shader_id); + // The caster pulls its vertices from gl_VertexID, but a core profile needs a vertex array bound to draw. + glsafe(glGenVertexArrays(1, &m_segments_caster_vao_id)); glcheck(); - assert(m_uni_segments_view_matrix_id != -1 && - m_uni_segments_projection_matrix_id != -1 && - m_uni_segments_camera_position_id != -1 && - m_uni_segments_positions_tex_id != -1 && - m_uni_segments_height_width_angle_tex_id != -1 && - m_uni_segments_colors_tex_id != -1 && - m_uni_segments_segment_index_tex_id != -1); m_segment_template.init(); @@ -797,6 +830,9 @@ void ViewerImpl::init(const std::string& opengl_context_version) m_uni_options_height_width_angle_tex_id = glGetUniformLocation(m_options_shader_id, "height_width_angle_tex"); m_uni_options_colors_tex_id = glGetUniformLocation(m_options_shader_id, "color_tex"); m_uni_options_segment_index_tex_id = glGetUniformLocation(m_options_shader_id, "segment_index_tex"); + // ORCA: section view + m_uni_options_clipping_plane_id = glGetUniformLocation(m_options_shader_id, "clipping_plane"); + m_uni_options_layer_colors.init(m_options_shader_id); glcheck(); assert(m_uni_options_view_matrix_id != -1 && m_uni_options_projection_matrix_id != -1 && @@ -870,6 +906,14 @@ void ViewerImpl::shutdown() glsafe(glDeleteProgram(m_segments_shader_id)); m_segments_shader_id = 0; } + if (m_segments_caster_shader_id != 0) { + glsafe(glDeleteProgram(m_segments_caster_shader_id)); + m_segments_caster_shader_id = 0; + } + if (m_segments_caster_vao_id != 0) { + glsafe(glDeleteVertexArrays(1, &m_segments_caster_vao_id)); + m_segments_caster_vao_id = 0; + } m_initialized = false; OpenGLWrapper::unload_opengl(); } @@ -890,7 +934,7 @@ void ViewerImpl::reset() for (std::vector& times : m_layer_start_times) std::vector().swap(times); std::vector().swap(m_layer_first_vertex); - std::vector().swap(m_colors_scratch); + m_layers_in_vertex_order = false; m_valid_lines_bitset.clear(); #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS m_cog_marker.reset(); @@ -920,9 +964,8 @@ void ViewerImpl::reset() // On some graphic cards texture buffers using GL_RGB32F format do not work, see: // https://dev.prusa3d.com/browse/SPE-2411 // https://github.com/prusa3d/PrusaSlicer/issues/12908 -// To let all drivers be happy, we use GL_RGBA32F format, so we need to add an extra (currently unused) float +// To let all drivers be happy, we use GL_RGBA32F format, so we need to add an extra float // to position and heights_widths_angles vectors -using Vec4 = std::array; static void extract_pos_and_or_hwa(const std::vector& vertices, float travels_radius, float wipes_radius, BitSet<>& valid_lines_bitset, std::vector* positions = nullptr, std::vector* heights_widths_angles = nullptr, bool update_bitset = false) { @@ -959,8 +1002,8 @@ static void extract_pos_and_or_hwa(const std::vector& vertices, floa } if (positions != nullptr) { - // the last component is a dummy float to comply with GL_RGBA32F format - Vec4 position = { v.position[0], v.position[1], v.position[2], 0.0f }; + // ORCA: the last component, there to comply with GL_RGBA32F format, carries the layer the shaders grey and dim by + Vec4 position = { v.position[0], v.position[1], v.position[2], static_cast(v.layer_id) }; if (move_type == EMoveType::Extrude) // push down extrusion vertices by half height to render them at the right z position[2] -= 0.5f * v.height; @@ -1076,6 +1119,8 @@ void ViewerImpl::load(GCodeInputData&& gcode_data) } for (size_t i = m_layer_first_vertex.size() - 1; i > 0; --i) m_layer_first_vertex[i - 1] = std::min(m_layer_first_vertex[i - 1], m_layer_first_vertex[i]); + m_layers_in_vertex_order = std::is_sorted(m_vertices.begin(), m_vertices.end(), + [](const PathVertex& a, const PathVertex& b) { return a.layer_id < b.layer_id; }); // the running time at each layer's first vertex, summed in vertex order so that // get_estimated_time_at() matches a full accumulation exactly @@ -1270,17 +1315,6 @@ static float encode_color(const Color& color) { return static_cast(i_color); } -// ORCA: returns the encoded color scaled towards black by 'brightness', preserving its hue. -// 1.0 = no change, 0.0 = black. -static float encode_color_dimmed(const Color& color, float brightness) { - const int r = static_cast(color[0] * brightness); - const int g = static_cast(color[1] * brightness); - const int b = static_cast(color[2] * brightness); - const int i_color = r << 16 | g << 8 | b; - return static_cast(i_color); -} - - void ViewerImpl::update_colors_texture() { #if !defined(ENABLE_OPENGL_ES) @@ -1288,6 +1322,32 @@ void ViewerImpl::update_colors_texture() return; #endif // ENABLE_OPENGL_ES + // ORCA: the colors of the vertices alone; the layers greyed or dimmed around the one the sliders + // show are left to the shaders, see set_layer_colors(), so that a slider step uploads nothing. + #ifdef ENABLE_OPENGL_ES + if (!m_vertices_colors.empty()) + // update gpu buffer for colors + m_texture_data.set_colors(m_vertices_colors); + #else + m_colors_tex_size = m_vertices_colors.size() * sizeof(float); + + // update gpu buffer for colors + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_colors_buf_id)); + glsafe(glBufferData(GL_TEXTURE_BUFFER, m_vertices_colors.size() * sizeof(float), m_vertices_colors.data(), GL_STATIC_DRAW)); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0)); + #endif // ENABLE_OPENGL_ES +} + +void ViewerImpl::LayerColorsUniforms::init(unsigned int shader_id) +{ + lit_layers = glGetUniformLocation(shader_id, "lit_layers"); + grey_below_layer = glGetUniformLocation(shader_id, "grey_below_layer"); + dim_brightness = glGetUniformLocation(shader_id, "dim_brightness"); + kept_vertex = glGetUniformLocation(shader_id, "kept_vertex"); +} + +void ViewerImpl::set_layer_colors(const LayerColorsUniforms& uni) const +{ const size_t top_layer_id = m_settings.top_layer_only_view_range ? m_layers.get_view_range()[1] : 0; const bool color_top_layer_only = m_view_range.get_full()[1] != m_view_range.get_visible()[1]; @@ -1306,43 +1366,15 @@ void ViewerImpl::update_colors_texture() const bool dim_previous_layers = m_settings.dim_previous_layers && m_settings.top_layer_only_view_range && !m_layers.empty() && (inspecting_top_layer || inspecting_bottom_layer); - // Based on current settings and slider position, we might want to render some - // vertices as dark grey (or darkened, see above). Use either that or the normal color (from the cache). - // Reused across calls: this runs on every slider tick, and the allocation alone is - // 4 bytes per vertex of the whole print each time. - std::vector& colors = m_colors_scratch; - colors.resize(m_vertices_colors.size()); - assert(colors.size() == m_vertices.size() && m_vertices_colors.size() == m_vertices.size()); - for (size_t i=0; i(layers_range[0]) : -1, + dim_previous_layers && inspecting_top_layer ? static_cast(layers_range[1]) : -1)); + glsafe(glUniform1i(uni.grey_below_layer, color_top_layer_only ? static_cast(top_layer_id) : 0)); + glsafe(glUniform1f(uni.dim_brightness, dim_previous_layers ? m_settings.dim_previous_layers_brightness : -1.0f)); + glsafe(glUniform1i(uni.kept_vertex, m_settings.spiral_vase_mode ? static_cast(m_view_range.get_enabled()[0]) : -1)); } - void ViewerImpl::update_colors() { @@ -1362,7 +1394,7 @@ void ViewerImpl::update_colors() // Recalculate "normal" colors of all the vertices for current view settings. // If some part of the preview should be rendered in dark grey, it is taken - // care of in update_colors_texture. That is to avoid the need to recalculate + // care of in the shaders, see set_layer_colors(). That is to avoid the need to recalculate // the "normal" color on every slider move. for (size_t i = 0; i < m_vertices.size(); ++i) m_vertices_colors[i] = encode_color(get_vertex_color(m_vertices[i])); @@ -1449,8 +1481,6 @@ void ViewerImpl::set_layers_view_range(Interval::value_type min, Interval::value update_view_full_range(); m_view_range.set_visible(m_view_range.get_enabled()); m_settings.update_enabled_entities = true; - //m_settings.update_colors = true; - update_colors_texture(); } void ViewerImpl::toggle_top_layer_only_view_range() @@ -1459,8 +1489,6 @@ void ViewerImpl::toggle_top_layer_only_view_range() update_view_full_range(); m_view_range.set_visible(m_view_range.get_enabled()); m_settings.update_enabled_entities = true; - //m_settings.update_colors = true; - update_colors_texture(); } // ORCA: enable/disable darkening of the layers the layer slider is not scrubbed to @@ -1469,9 +1497,6 @@ void ViewerImpl::set_dim_previous_layers(bool value) if (m_settings.dim_previous_layers == value) return; m_settings.dim_previous_layers = value; - // defer the actual color/texture rebuild to the next render(), when the GL context is current - // (this may be toggled from the Preferences dialog, outside the canvas context) - m_settings.update_colors = true; } // ORCA: set how bright the darkened layers are rendered, 1.0 = unchanged, 0.0 = black @@ -1481,7 +1506,6 @@ void ViewerImpl::set_dim_previous_layers_brightness(float value) if (m_settings.dim_previous_layers_brightness == value) return; m_settings.dim_previous_layers_brightness = value; - m_settings.update_colors = true; } std::vector ViewerImpl::get_time_modes() const @@ -1589,8 +1613,6 @@ void ViewerImpl::set_view_visible_range(Interval::value_type min, Interval::valu update_view_full_range(); m_view_range.set_visible(min, max); update_enabled_entities(); - //m_settings.update_colors = true; - update_colors_texture(); } float ViewerImpl::get_estimated_time_at(size_t id) const @@ -1815,7 +1837,6 @@ size_t ViewerImpl::get_used_cpu_memory() const for (const std::vector& times : m_layer_start_times) ret += STDVEC_MEMSIZE(times, float); ret += STDVEC_MEMSIZE(m_layer_first_vertex, uint32_t); - ret += STDVEC_MEMSIZE(m_colors_scratch, float); ret += m_valid_lines_bitset.size_in_bytes_cpu(); ret += m_height_range.size_in_bytes_cpu(); ret += m_width_range.size_in_bytes_cpu(); @@ -1908,6 +1929,11 @@ void ViewerImpl::update_view_full_range() } auto last_it = first_it; + // ORCA: skip straight to the layer above the range rather than walking there + if (m_layers_in_vertex_order && layers_range[1] + 1 < m_layer_first_vertex.size()) + last_it = std::max(first_it, m_vertices.begin() + m_layer_first_vertex[layers_range[1] + 1]); + else if (m_layers_in_vertex_order) + last_it = m_vertices.end(); while (last_it != m_vertices.end() && last_it->layer_id <= layers_range[1]) { ++last_it; } @@ -1947,12 +1973,14 @@ void ViewerImpl::update_view_full_range() if (m_settings.top_layer_only_view_range) { const Interval& full_range = m_view_range.get_full(); - auto top_first_it = m_vertices.begin() + full_range[0]; - bool shortened = false; - while (top_first_it != m_vertices.end() && (top_first_it->layer_id < layers_range[1] || !is_visible(*top_first_it, m_settings))) { + const auto range_first_it = m_vertices.begin() + full_range[0]; + auto top_first_it = range_first_it; + // ORCA: skip straight to the top layer rather than walking there + if (m_layers_in_vertex_order) + top_first_it = std::max(top_first_it, m_vertices.begin() + m_layer_first_vertex[layers_range[1]]); + while (top_first_it != m_vertices.end() && (top_first_it->layer_id < layers_range[1] || !is_visible(*top_first_it, m_settings))) ++top_first_it; - shortened = true; - } + const bool shortened = top_first_it != range_first_it; if (shortened) --top_first_it; @@ -2034,7 +2062,7 @@ void ViewerImpl::update_color_ranges() void ViewerImpl::update_heights_widths() { #ifdef ENABLE_OPENGL_ES - std::vector heights_widths_angles; + std::vector heights_widths_angles; heights_widths_angles.reserve(m_vertices.size()); extract_pos_and_or_hwa(m_vertices, m_travels_radius, m_wipes_radius, m_valid_lines_bitset, nullptr, &heights_widths_angles); m_texture_data.set_heights_widths_angles(heights_widths_angles); @@ -2066,7 +2094,10 @@ void ViewerImpl::update_heights_widths() void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& camera_position) { - if (m_segments_shader_id == 0) + // ORCA: realistic view. The shadow caster pass draws depth only. + const unsigned int shader_id = m_rendering_shadow_casters ? m_segments_caster_shader_id : m_segments_shader_id; + const SegmentsUniforms& uni = m_rendering_shadow_casters ? m_uni_segments_caster : m_uni_segments; + if (shader_id == 0) return; #ifdef ENABLE_OPENGL_ES @@ -2083,41 +2114,54 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec const bool curr_cull_face = glIsEnabled(GL_CULL_FACE); glcheck(); - glsafe(glUseProgram(m_segments_shader_id)); + glsafe(glUseProgram(shader_id)); - glsafe(glUniform1i(m_uni_segments_positions_tex_id, 0)); - glsafe(glUniform1i(m_uni_segments_height_width_angle_tex_id, 1)); - glsafe(glUniform1i(m_uni_segments_colors_tex_id, 2)); - glsafe(glUniform1i(m_uni_segments_segment_index_tex_id, 3)); - glsafe(glUniformMatrix4fv(m_uni_segments_view_matrix_id, 1, GL_FALSE, view_matrix.data())); - glsafe(glUniformMatrix4fv(m_uni_segments_projection_matrix_id, 1, GL_FALSE, projection_matrix.data())); - glsafe(glUniform3fv(m_uni_segments_camera_position_id, 1, camera_position.data())); - // The segments come in print order, bottom layer first. Seen from above, that is back to front, - // and every hidden fragment is shaded before the one that covers it. Drawing them last to first - // lets the depth test reject the hidden ones instead. The camera looks down when the world's - // up axis points towards it, which is the view matrix's (2, 2) entry being positive. - const bool top_down = !m_rendering_shadow_casters && view_matrix[10] > 0.0f; - glsafe(glUniform1i(m_uni_segments_reverse_order_id, top_down ? 1 : 0)); -#ifndef ENABLE_OPENGL_ES - glsafe(glUniform1i(m_uni_segments_instance_count_id, static_cast(m_enabled_segments_count))); -#endif // ENABLE_OPENGL_ES - // ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades - // with the lookup off. - glsafe(glUniform1i(m_uni_segments_shadow_map_id, m_shadow_map_texture_unit)); - glsafe(glUniformMatrix4fv(m_uni_segments_shadow_light_vp_id, 1, GL_FALSE, m_shadow_light_vp.data())); - glsafe(glUniform1f(m_uni_segments_shadow_intensity_id, m_rendering_shadow_casters ? 0.0f : m_shadow_intensity)); - glsafe(glUniform1f(m_uni_segments_shadow_map_texel_id, m_shadow_map_texel)); - glsafe(glUniform1f(m_uni_segments_exposure_id, m_exposure)); - glsafe(glUniform1f(m_uni_segments_saturation_id, m_saturation)); - glsafe(glUniform1f(m_uni_segments_bias_scale_id, m_rendering_shadow_casters ? 0.0f : 1.0f)); + glsafe(glUniform1i(uni.positions_tex, 0)); + glsafe(glUniform1i(uni.height_width_angle_tex, 1)); + glsafe(glUniform1i(uni.colors_tex, 2)); + glsafe(glUniform1i(uni.segment_index_tex, 3)); + glsafe(glUniformMatrix4fv(uni.view_matrix, 1, GL_FALSE, view_matrix.data())); + glsafe(glUniformMatrix4fv(uni.projection_matrix, 1, GL_FALSE, projection_matrix.data())); + glsafe(glUniform3fv(uni.camera_position, 1, camera_position.data())); + // ORCA: view_matrix(2,2) > 0 is looking down, where the last segments printed are the nearest. + const bool reverse_order = view_matrix[10] > 0.0f; + glsafe(glUniform1i(uni.reverse_order, reverse_order ? 1 : 0)); + glsafe(glUniform4fv(uni.clipping_plane, 1, m_clipping_plane.data())); + if (!m_rendering_shadow_casters) { + // ORCA: realistic view + glsafe(glUniform1i(m_uni_segments_shadow_map_id, m_shadow_map_texture_unit)); + glsafe(glUniformMatrix4fv(m_uni_segments_shadow_light_vp_id, 1, GL_FALSE, m_shadow_light_vp.data())); + glsafe(glUniform1f(m_uni_segments_shadow_intensity_id, m_shadow_intensity)); + glsafe(glUniform1f(m_uni_segments_shadow_map_texel_id, m_shadow_map_texel)); + glsafe(glUniform1f(m_uni_segments_exposure_id, m_exposure)); + glsafe(glUniform1f(m_uni_segments_saturation_id, m_saturation)); + glsafe(glUniform3fv(m_uni_segments_light_top_dir_id, 1, m_light_top_dir.data())); + set_layer_colors(m_uni_segments_layer_colors); + } glsafe(glDisable(GL_CULL_FACE)); + auto draw = [this, &uni](size_t count) { + glsafe(glUniform1i(uni.instances_count, static_cast(count))); + if (!m_rendering_shadow_casters) { + m_segment_template.render(count); + return; + } + // ORCA: realistic view. 6 vertices per caster ribbon. + int curr_vertex_array = 0; + glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array)); + glsafe(glBindVertexArray(m_segments_caster_vao_id)); + glsafe(glDrawArrays(GL_TRIANGLES, 0, static_cast(6 * count))); + glsafe(glBindVertexArray(curr_vertex_array)); + }; + #ifdef ENABLE_OPENGL_ES int curr_bound_texture = 0; glsafe(glGetIntegerv(GL_TEXTURE_BINDING_2D, &curr_bound_texture)); - for (size_t i = 0; i < m_texture_data.get_count(); ++i) { + const size_t tex_count = m_texture_data.get_count(); + for (size_t n = 0; n < tex_count; ++n) { + const size_t i = reverse_order ? tex_count - 1 - n : n; const auto [id, count] = m_texture_data.get_enabled_segments_tex_id(i); if (count == 0) continue; @@ -2129,7 +2173,7 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec glsafe(glBindTexture(GL_TEXTURE_2D, m_texture_data.get_colors_tex_id(i).first)); glsafe(glActiveTexture(GL_TEXTURE3)); glsafe(glBindTexture(GL_TEXTURE_2D, id)); - m_segment_template.render(count); + draw(count); } #else std::array curr_bound_texture = { 0, 0, 0, 0 }; @@ -2152,7 +2196,7 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_segments_tex_id)); glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_enabled_segments_buf_id)); - m_segment_template.render(m_enabled_segments_count); + draw(m_enabled_segments_count); #endif // ENABLE_OPENGL_ES if (curr_cull_face) @@ -2197,6 +2241,8 @@ void ViewerImpl::render_options(const Mat4x4& view_matrix, const Mat4x4& project glsafe(glUniform1i(m_uni_options_segment_index_tex_id, 3)); glsafe(glUniformMatrix4fv(m_uni_options_view_matrix_id, 1, GL_FALSE, view_matrix.data())); glsafe(glUniformMatrix4fv(m_uni_options_projection_matrix_id, 1, GL_FALSE, projection_matrix.data())); + glsafe(glUniform4fv(m_uni_options_clipping_plane_id, 1, m_clipping_plane.data())); + set_layer_colors(m_uni_options_layer_colors); glsafe(glEnable(GL_CULL_FACE)); diff --git a/src/libvgcode/src/ViewerImpl.hpp b/src/libvgcode/src/ViewerImpl.hpp index 707f0f6bb7..0877e6265b 100644 --- a/src/libvgcode/src/ViewerImpl.hpp +++ b/src/libvgcode/src/ViewerImpl.hpp @@ -8,6 +8,12 @@ #include "Settings.hpp" #include "SegmentTemplate.hpp" #include "OptionTemplate.hpp" +#include "../include/Types.hpp" +#include +#include +#include +#include +#include #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS #include "CogMarker.hpp" #include "ToolMarker.hpp" @@ -89,6 +95,9 @@ public: // caller decides which of the two it varies with the realistic view setting. // void set_tone(float exposure, float saturation); + // ORCA: section view, see Viewer::set_clipping_plane() + void set_clipping_plane(const std::array& plane) { m_clipping_plane = plane; } + void set_light_top_dir(const Vec3& direction) { m_light_top_dir = direction; } EViewType get_view_type() const { return m_settings.view_type; } void set_view_type(EViewType type); @@ -262,9 +271,10 @@ private: // std::vector m_layer_first_vertex; // - // Scratch buffer for update_colors_texture(), kept alive across slider steps + // ORCA: whether the layer ids never decrease along the vertices, so that each layer's vertices + // follow m_layer_first_vertex. Not so for a print by object, whose layers start over per object. // - std::vector m_colors_scratch; + bool m_layers_in_vertex_order{ false }; // // Detected travel moves times // @@ -347,6 +357,9 @@ private: // OpenGL shaders ids // unsigned int m_segments_shader_id{ 0 }; + // ORCA: realistic view. Depth-only ribbons for the shadow caster pass, and the empty vertex array they draw with. + unsigned int m_segments_caster_shader_id{ 0 }; + unsigned int m_segments_caster_vao_id{ 0 }; unsigned int m_options_shader_id{ 0 }; #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS unsigned int m_cog_marker_shader_id{ 0 }; @@ -355,24 +368,44 @@ private: // // Caches for OpenGL uniforms id for segments shader // - int m_uni_segments_view_matrix_id{ -1 }; - int m_uni_segments_projection_matrix_id{ -1 }; - int m_uni_segments_camera_position_id{ -1 }; - int m_uni_segments_positions_tex_id{ -1 }; - int m_uni_segments_height_width_angle_tex_id{ -1 }; - int m_uni_segments_colors_tex_id{ -1 }; - int m_uni_segments_segment_index_tex_id{ -1 }; - int m_uni_segments_reverse_order_id{ -1 }; - int m_uni_segments_instance_count_id{ -1 }; + // ORCA: the ones the shaded and the shadow caster programs share. + struct SegmentsUniforms + { + int view_matrix{ -1 }; + int projection_matrix{ -1 }; + int camera_position{ -1 }; + int positions_tex{ -1 }; + int height_width_angle_tex{ -1 }; + int colors_tex{ -1 }; + int segment_index_tex{ -1 }; + int reverse_order{ -1 }; + int instances_count{ -1 }; + int clipping_plane{ -1 }; + + void init(unsigned int shader_id); + }; + SegmentsUniforms m_uni_segments; + SegmentsUniforms m_uni_segments_caster; int m_uni_segments_shadow_map_id{ -1 }; int m_uni_segments_shadow_light_vp_id{ -1 }; int m_uni_segments_shadow_intensity_id{ -1 }; int m_uni_segments_shadow_map_texel_id{ -1 }; int m_uni_segments_exposure_id{ -1 }; int m_uni_segments_saturation_id{ -1 }; - int m_uni_segments_bias_scale_id{ -1 }; + int m_uni_segments_light_top_dir_id{ -1 }; + // ORCA: the layers greyed or dimmed around the one the sliders show, in the segments and options shaders. + struct LayerColorsUniforms + { + int lit_layers{ -1 }; + int grey_below_layer{ -1 }; + int dim_brightness{ -1 }; + int kept_vertex{ -1 }; + + void init(unsigned int shader_id); + }; + LayerColorsUniforms m_uni_segments_layer_colors; // - // Caches for OpenGL uniforms id for options shader + // Caches for OpenGL uniforms id for options shader // int m_uni_options_view_matrix_id{ -1 }; int m_uni_options_projection_matrix_id{ -1 }; @@ -380,6 +413,8 @@ private: int m_uni_options_height_width_angle_tex_id{ -1 }; int m_uni_options_colors_tex_id{ -1 }; int m_uni_options_segment_index_tex_id{ -1 }; + int m_uni_options_clipping_plane_id{ -1 }; + LayerColorsUniforms m_uni_options_layer_colors; #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS // // Caches for OpenGL uniforms id for cog marker shader @@ -403,8 +438,8 @@ private: { public: void init(size_t vertices_count); - void set_positions(const std::vector& positions); - void set_heights_widths_angles(const std::vector& heights_widths_angles); + void set_positions(const std::vector& positions); + void set_heights_widths_angles(const std::vector& heights_widths_angles); void set_colors(const std::vector& colors); void set_enabled_segments(const std::vector& enabled_segments); void set_enabled_options(const std::vector& enabled_options); @@ -512,8 +547,7 @@ private: // // ORCA: realistic view. Shadow map state set by set_shadow_map(), consumed by the segments - // shader. m_rendering_shadow_casters forces the intensity to 0 for the depth pass, which - // must not sample the very map it is writing. + // shader. m_rendering_shadow_casters switches render_segments() to the depth-only program. // // Defaults past the four texture units render_segments() binds itself, so the sampler never // aliases one of the buffer textures before the owner of the map has said where it lives. @@ -529,6 +563,11 @@ private: // float m_exposure{ 1.0f }; float m_saturation{ 1.0f }; + // ORCA: the light the segments shader shades with, in eye space. + Vec3 m_light_top_dir{ -0.4574957f, 0.4574957f, 0.7624929f }; + + // ORCA: section view + std::array m_clipping_plane{ 0.0f, 0.0f, 0.0f, 1.0f }; void apply_pending_updates(); void update_view_full_range(); @@ -536,6 +575,8 @@ private: void update_heights_widths(); void render_segments(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& camera_position); void render_options(const Mat4x4& view_matrix, const Mat4x4& projection_matrix); + // ORCA: the program using uni must be current. + void set_layer_colors(const LayerColorsUniforms& uni) const; #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS void render_cog_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix); void render_tool_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix); diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 46c32ff238..b74247e338 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -503,6 +503,10 @@ set(SLIC3R_GUI_SOURCES GUI/SceneRaycaster.hpp GUI/SceneCache.cpp GUI/SceneCache.hpp + GUI/FrameProfiler.cpp + GUI/FrameProfiler.hpp + GUI/SceneBenchmark.cpp + GUI/SceneBenchmark.hpp GUI/PartSkipCommon.hpp GUI/PartSkipDialog.cpp GUI/PartSkipDialog.hpp diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index a7135eac6f..cf568432dc 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -1,5 +1,21 @@ #include "Snapshot.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/Exception.hpp" +#include "slic3r/Config/Version.hpp" +#include #include #include @@ -26,7 +42,10 @@ #include "../GUI/MainFrame.hpp" #include "../GUI/MsgDialog.hpp" +#include +#include #include +#include #define SLIC3R_SNAPSHOTS_DIR "snapshots" #define SLIC3R_SNAPSHOT_FILE "snapshot.ini" diff --git a/src/slic3r/Config/Snapshot.hpp b/src/slic3r/Config/Snapshot.hpp index f453006338..96a0c33771 100644 --- a/src/slic3r/Config/Snapshot.hpp +++ b/src/slic3r/Config/Snapshot.hpp @@ -1,6 +1,8 @@ #ifndef slic3r_GUI_Snapshot_ #define slic3r_GUI_Snapshot_ +#include +#include #include #include #include diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 092594ce51..f25577c9dc 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -1,9 +1,21 @@ #include "Version.hpp" +#include +#include +#include +#include #include #include #include +#include "libslic3r/Semver.hpp" +#include +#include +#include +#include +#include +#include +#include "libslic3r/Exception.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/Config.hpp" diff --git a/src/slic3r/Config/Version.hpp b/src/slic3r/Config/Version.hpp index 8249573dec..5e10e9ab95 100644 --- a/src/slic3r/Config/Version.hpp +++ b/src/slic3r/Config/Version.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_GUI_ConfigIndex_ #define slic3r_GUI_ConfigIndex_ +#include #include #include diff --git a/src/slic3r/GUI/2DBed.cpp b/src/slic3r/GUI/2DBed.cpp index 3257d05adc..4bf71c2d50 100644 --- a/src/slic3r/GUI/2DBed.cpp +++ b/src/slic3r/GUI/2DBed.cpp @@ -18,6 +18,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" #include "slic3r/GUI/Widgets/StateColor.hpp" #include +#include #include #include #include diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 0ba85775bd..a46707ff98 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1127,8 +1127,17 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo ); } else if (type == GLVolumeCollection::ERenderType::Opaque && list.size() > 1) { + // Orca: nearest first after the selected ones, so the depth test skips shading hidden surfaces. + for (GLVolumeWithIdAndZ& volume : list) { + volume.second.second = volume.first->transformed_bounding_box().transformed(view_matrix).max(2); + } + std::sort(list.begin(), list.end(), - [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.first->selected && !v2.first->selected; } + [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { + if (v1.first->selected != v2.first->selected) + return v1.first->selected; + return v1.second.second > v2.second.second; + } ); } diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 08e7d7a056..66e87ac3af 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/Widgets/Button.hpp" diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp index 79880a6ec5..0ecc8809be 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.hpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp @@ -16,6 +16,7 @@ #include "Widgets/TextInput.hpp" #include "Widgets/HyperLink.hpp" #include "slic3r/Utils/CalibUtils.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/AMSSetting.cpp b/src/slic3r/GUI/AMSSetting.cpp index d967fa37ab..f953dd115a 100644 --- a/src/slic3r/GUI/AMSSetting.cpp +++ b/src/slic3r/GUI/AMSSetting.cpp @@ -12,6 +12,7 @@ #include "slic3r/GUI/Widgets/AnimaController.hpp" #include "slic3r/GUI/Widgets/Label.hpp" #include "slic3r/GUI/Widgets/ComboBox.hpp" +#include #include #include #include "slic3r/GUI/GUI_Utils.hpp" diff --git a/src/slic3r/GUI/AMSSetting.hpp b/src/slic3r/GUI/AMSSetting.hpp index 24467f8d13..1d6b559981 100644 --- a/src/slic3r/GUI/AMSSetting.hpp +++ b/src/slic3r/GUI/AMSSetting.hpp @@ -12,6 +12,7 @@ #include "Widgets/CheckBox.hpp" #include "slic3r/GUI/DeviceCore/DevFilaAmsSetting.h" +#include #include #include #include diff --git a/src/slic3r/GUI/CAD/DesignCanvas.cpp b/src/slic3r/GUI/CAD/DesignCanvas.cpp index 517fbcee63..1abfd81feb 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.cpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include "libslic3r/CAD/SketchEngine.hpp" diff --git a/src/slic3r/GUI/CAD/DesignPanel.cpp b/src/slic3r/GUI/CAD/DesignPanel.cpp index 59e3aaac8e..d61d0aa11f 100644 --- a/src/slic3r/GUI/CAD/DesignPanel.cpp +++ b/src/slic3r/GUI/CAD/DesignPanel.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/CalibrationPanel.hpp b/src/slic3r/GUI/CalibrationPanel.hpp index f427b37871..adf03e4be9 100644 --- a/src/slic3r/GUI/CalibrationPanel.hpp +++ b/src/slic3r/GUI/CalibrationPanel.hpp @@ -6,6 +6,24 @@ #include "Lazy.hpp" #include "SelectMachinePop.hpp" #include "Widgets/SideTools.hpp" +#include +#include "libslic3r/calib.hpp" +#include +#include "slic3r/GUI/wxExtensions.hpp" +#include "slic3r/GUI/DeviceManager.hpp" +#include +#include +#include +#include "slic3r/GUI/Widgets/PopupWindow.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include "slic3r/GUI/StagedBuild.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/CapsuleButton.hpp b/src/slic3r/GUI/CapsuleButton.hpp index ac23f174e8..f8afdddabb 100644 --- a/src/slic3r/GUI/CapsuleButton.hpp +++ b/src/slic3r/GUI/CapsuleButton.hpp @@ -3,6 +3,7 @@ #include "wxExtensions.hpp" #include "Widgets/Label.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/ConfigExceptions.hpp b/src/slic3r/GUI/ConfigExceptions.hpp index 181442d4e3..e3c5b08cea 100644 --- a/src/slic3r/GUI/ConfigExceptions.hpp +++ b/src/slic3r/GUI/ConfigExceptions.hpp @@ -1,4 +1,8 @@ #include +#include + +#include "libslic3r/Exception.hpp" + namespace Slic3r { class ConfigError : public Slic3r::RuntimeError { diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 91c5f211e1..48c0cd0d5f 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.cpp index f02007593a..151d53810b 100644 --- a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.cpp +++ b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.cpp @@ -13,6 +13,7 @@ #include "slic3r/GUI/Widgets/StateColor.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp index 34cd85e692..dcc7654b41 100644 --- a/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp +++ b/src/slic3r/GUI/DeviceTab/uiAMSBestPositionPopup.hpp @@ -18,6 +18,7 @@ #include "libslic3r/ProjectTask.hpp" #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp index 5014743f2d..462fcf892e 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp @@ -14,6 +14,7 @@ #include "slic3r/GUI/Widgets/StateColor.hpp" +#include #include #include "slic3r/GUI/Widgets/Label.hpp" #include diff --git a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.h b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.h index 16cd311120..c433973e44 100644 --- a/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.h +++ b/src/slic3r/GUI/DeviceTab/wgtDeviceNozzleRack.h @@ -14,9 +14,16 @@ #include "slic3r/GUI/Widgets/StaticBox.hpp" #include "slic3r/GUI/Widgets/AnimaController.hpp" +#include +#include +#include +#include +#include #include #include #include +#include +#include // Previous definitions class Button; diff --git a/src/slic3r/GUI/ExtrusionCalibration.cpp b/src/slic3r/GUI/ExtrusionCalibration.cpp index e15470e462..a2d14fa370 100644 --- a/src/slic3r/GUI/ExtrusionCalibration.cpp +++ b/src/slic3r/GUI/ExtrusionCalibration.cpp @@ -6,6 +6,7 @@ #include #include "I18N.hpp" #include +#include #include #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/wxExtensions.hpp" diff --git a/src/slic3r/GUI/ExtrusionCalibration.hpp b/src/slic3r/GUI/ExtrusionCalibration.hpp index cbee1b56b1..3b500373da 100644 --- a/src/slic3r/GUI/ExtrusionCalibration.hpp +++ b/src/slic3r/GUI/ExtrusionCalibration.hpp @@ -16,6 +16,7 @@ #include "ParamsDialog.hpp" #include "GUI_App.hpp" #include "wx/hyperlink.h" +#include #include #include #include diff --git a/src/slic3r/GUI/FrameProfiler.cpp b/src/slic3r/GUI/FrameProfiler.cpp new file mode 100644 index 0000000000..d79a0eef99 --- /dev/null +++ b/src/slic3r/GUI/FrameProfiler.cpp @@ -0,0 +1,153 @@ +#include "libslic3r/libslic3r.h" +#include "FrameProfiler.hpp" + +#include "3DScene.hpp" + +#include + +#include +#include + +namespace Slic3r { +namespace GUI { + +void FrameProfiler::begin_frame() +{ + m_recording = nullptr; + // GL 3.3 or ARB_timer_query + if (glQueryCounter == nullptr) + return; + + collect(false); + Frame& frame = m_frames[m_next]; + // Every frame in flight still waits for the GPU: skip this one rather than stall. + if (frame.pending) + return; + + if (frame.queries[0] == 0) + glsafe(::glGenQueries(GLsizei(frame.queries.size()), frame.queries.data())); + glsafe(::glQueryCounter(frame.queries[0], GL_TIMESTAMP)); + frame.count = 0; + frame.averaged = m_averaging; + m_recording = &frame; + m_last_mark = std::chrono::steady_clock::now(); +} + +void FrameProfiler::mark(const char* name) +{ + if (m_recording == nullptr || m_recording->count == MAX_SECTIONS) + return; + + Frame& frame = *m_recording; + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + glsafe(::glQueryCounter(frame.queries[2 * frame.count + 1], GL_TIMESTAMP)); + // Else the GPU time would include the CPU time spent until the driver flushes on its own. + glsafe(::glFlush()); + // Sent with the next section's commands, so the time the GPU waits for them is not billed to it. + if (frame.count + 1 < MAX_SECTIONS) + glsafe(::glQueryCounter(frame.queries[2 * frame.count + 2], GL_TIMESTAMP)); + frame.names[frame.count] = name; + frame.cpu_ms[frame.count] = std::chrono::duration(now - m_last_mark).count(); + ++frame.count; + m_last_mark = now; +} + +void FrameProfiler::end_frame() +{ + if (m_recording == nullptr) + return; + + m_recording->pending = m_recording->count > 0; + m_recording = nullptr; + m_next = (m_next + 1) % FRAMES_IN_FLIGHT; +} + +void FrameProfiler::collect(bool wait) +{ + constexpr double SMOOTHING = 0.1; + + // Oldest first: a frame whose results are not in yet holds back the newer ones too. + for (size_t i = 0; i < FRAMES_IN_FLIGHT; ++i) { + Frame& frame = m_frames[(m_next + i) % FRAMES_IN_FLIGHT]; + if (!frame.pending) + continue; + + if (!wait) { + GLint available = 0; + glsafe(::glGetQueryObjectiv(frame.queries[2 * frame.count - 1], GL_QUERY_RESULT_AVAILABLE, &available)); + if (available == 0) + break; + } + + std::array stamps{}; + for (size_t j = 0; j < 2 * frame.count; ++j) + glsafe(::glGetQueryObjectui64v(frame.queries[j], GL_QUERY_RESULT, &stamps[j])); + frame.pending = false; + + const bool averaged = frame.averaged && m_averaging; + if (averaged) + ++m_averaged_frames; + std::vector
sections; + sections.reserve(frame.count); + for (size_t j = 0; j < frame.count; ++j) { + Section section{ frame.names[j], frame.cpu_ms[j], stamps[2 * j + 1] > stamps[2 * j] ? double(stamps[2 * j + 1] - stamps[2 * j]) * 1e-6 : 0.0 }; + if (averaged) { + auto sum = std::find_if(m_sums.begin(), m_sums.end(), [§ion](const Section& s) { return std::strcmp(s.name, section.name) == 0; }); + if (sum == m_sums.end()) + m_sums.push_back(section); + else { + sum->cpu_ms += section.cpu_ms; + sum->gpu_ms += section.gpu_ms; + } + } + for (const Section& prev : m_sections) { + if (std::strcmp(prev.name, section.name) == 0) { + section.cpu_ms = prev.cpu_ms + SMOOTHING * (section.cpu_ms - prev.cpu_ms); + section.gpu_ms = prev.gpu_ms + SMOOTHING * (section.gpu_ms - prev.gpu_ms); + break; + } + } + sections.push_back(section); + } + m_sections = std::move(sections); + } +} + +void FrameProfiler::start_averaging() +{ + m_averaging = true; + m_sums.clear(); + m_averaged_frames = 0; +} + +std::vector FrameProfiler::finish_averaging(bool wait) +{ + if (wait && glQueryCounter != nullptr) + collect(true); + std::vector
averages = std::move(m_sums); + for (Section& section : averages) { + section.cpu_ms /= double(m_averaged_frames); + section.gpu_ms /= double(m_averaged_frames); + } + m_averaging = false; + m_sums.clear(); + m_averaged_frames = 0; + return averages; +} + +void FrameProfiler::reset() +{ + for (Frame& frame : m_frames) { + if (frame.queries[0] != 0) + glsafe(::glDeleteQueries(GLsizei(frame.queries.size()), frame.queries.data())); + frame = Frame(); + } + m_recording = nullptr; + m_sections.clear(); + m_averaging = false; + m_sums.clear(); + m_averaged_frames = 0; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/FrameProfiler.hpp b/src/slic3r/GUI/FrameProfiler.hpp new file mode 100644 index 0000000000..cfda8a4d8a --- /dev/null +++ b/src/slic3r/GUI/FrameProfiler.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +// CPU and GPU time spent in the named sections of a frame, shown under the FPS overlay and averaged +// by the scene benchmark. A section runs from the previous mark to the one naming it; its GPU time +// leaves out any wait for the CPU to send its commands. GPU times are read back a few frames late, +// so profiling never waits on the GPU. +class FrameProfiler +{ +public: + struct Section + { + const char* name{ nullptr }; + double cpu_ms{ 0.0 }; + double gpu_ms{ 0.0 }; + }; + + void begin_frame(); + void mark(const char* name); + void end_frame(); + // The sections of the last frame read back, smoothed over the previous ones. + const std::vector
& sections() const { return m_sections; } + // Averages the sections of the frames begun from now on, until finish_averaging(). + void start_averaging(); + bool is_averaging() const { return m_averaging; } + // With wait, first reads back the averaged frames still on the GPU, with the context current. + std::vector
finish_averaging(bool wait); + // Frees the queries, with the context current. + void reset(); + +private: + static constexpr size_t FRAMES_IN_FLIGHT = 4; + static constexpr size_t MAX_SECTIONS = 32; + + struct Frame + { + // A begin and an end timestamp per section. + std::array queries{}; + std::array names{}; + std::array cpu_ms{}; + size_t count{ 0 }; + bool pending{ false }; + bool averaged{ false }; + }; + + void collect(bool wait); + + std::array m_frames; + Frame* m_recording{ nullptr }; + size_t m_next{ 0 }; + std::chrono::steady_clock::time_point m_last_mark; + std::vector
m_sections; + bool m_averaging{ false }; + std::vector
m_sums; + size_t m_averaged_frames{ 0 }; +}; + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 04c930dcfe..c31be41b25 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -80,6 +80,7 @@ #include #include +#include #include #include #include @@ -1759,6 +1760,26 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height) m_sequential_view.render_marker(!m_no_render_path, canvas_width, sequential_view_height(canvas_height), m_viewer.get_view_type()); } +size_t GCodeViewer::shadow_casters_signature() const +{ + size_t hash = m_viewer.get_vertices_count(); + const libvgcode::Interval& visible = m_viewer.get_view_visible_range(); + const libvgcode::Interval& layers = m_viewer.get_layers_view_range(); + for (size_t value : { size_t(visible[0]), size_t(visible[1]), size_t(layers[0]), size_t(layers[1]) }) + boost::hash_combine(hash, value); + for (double value : { m_paths_bounding_box.min.x(), m_paths_bounding_box.min.y(), m_paths_bounding_box.min.z(), + m_paths_bounding_box.max.x(), m_paths_bounding_box.max.y(), m_paths_bounding_box.max.z() }) + boost::hash_combine(hash, value); + boost::hash_combine(hash, m_viewer.is_top_layer_only_view_range()); + for (size_t i = 0; i < libvgcode::GCODE_EXTRUSION_ROLES_COUNT; ++i) + boost::hash_combine(hash, m_viewer.is_extrusion_role_visible(libvgcode::EGCodeExtrusionRole(i))); + boost::hash_combine(hash, m_viewer.is_option_visible(libvgcode::EOptionType::Travels)); + boost::hash_combine(hash, m_viewer.is_option_visible(libvgcode::EOptionType::Wipes)); + for (float value : m_clipping_plane) + boost::hash_combine(hash, value); + return hash; +} + void GCodeViewer::render_shadow_casters(const Transform3d& light_view_matrix, const Transform3d& light_projection_matrix, const Vec3d& light_position) { if (!has_data()) @@ -1777,11 +1798,26 @@ void GCodeViewer::set_shadow_map(int texture_unit, const Transform3d& light_view intensity, texel_size); } +void GCodeViewer::set_light_top_dir(const Vec3d& direction) +{ + m_viewer.set_light_top_dir(libvgcode::convert(static_cast(direction.cast()))); +} + void GCodeViewer::set_tone(float exposure, float saturation) { m_viewer.set_tone(exposure, saturation); } +void GCodeViewer::set_clipping_plane(const ClippingPlane& plane) +{ + // Flipped to match ClippingPlane::distance(). + const Vec3f normal = -plane.get_normal().cast(); + m_clipping_plane = plane.is_active() ? + std::array{ normal.x(), normal.y(), normal.z(), float(plane.get_offset()) } : + std::array{ 0.0f, 0.0f, 0.0f, 1.0f }; + m_viewer.set_clipping_plane(m_clipping_plane); +} + void GCodeViewer::render_overlay(int canvas_width, int canvas_height, int right_margin) { if (m_viewer.get_extrusion_roles().empty()) diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 5154726aba..50bfdee38d 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -260,6 +260,8 @@ mutable bool m_no_render_path { false }; bool m_is_dark = false; libvgcode::Viewer m_viewer; + // ORCA: section view, as the viewer has it. What it cuts away casts no shadow. + std::array m_clipping_plane{ 0.0f, 0.0f, 0.0f, 1.0f }; bool m_loaded_as_preview{ false }; public: @@ -300,6 +302,9 @@ public: // ORCA: tone applied to the shaded toolpaths, paying back the light the lighting term, // the shadow and the SSAO pass each take off. 1.0/1.0 is a no-op. void set_tone(float exposure, float saturation); + // ORCA: section view + void set_clipping_plane(const ClippingPlane& plane); + void set_light_top_dir(const Vec3d& direction); //BBS // void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager); // void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager); @@ -322,6 +327,10 @@ public: std::vector get_layers_times() const { return m_viewer.get_layers_estimated_times(); } const std::array &get_layers_z_range() const { return m_viewer.get_layers_view_range(); } + size_t get_vertices_count() const { return m_viewer.get_vertices_count(); } + size_t get_layers_count() const { return m_viewer.get_layers_count(); } + // ORCA: realistic view. Changes whenever the toolpaths casting shadows do. + size_t shadow_casters_signature() const; const SequentialView& get_sequential_view() const { return m_sequential_view; } void update_sequential_view_current(unsigned int first, unsigned int last); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ea116587ac..622568e291 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1303,6 +1303,7 @@ GLCanvas3D::~GLCanvas3D() { if (_set_current()) { m_scene_cache.reset(); + m_frame_profiler.reset(); if (m_fxaa_texture_id != 0) { glsafe(::glDeleteTextures(1, &m_fxaa_texture_id)); m_fxaa_texture_id = 0; @@ -1324,8 +1325,11 @@ GLCanvas3D::~GLCanvas3D() m_shadow_map_fbo = 0; } m_plate_shadow_mask.reset(); + m_section_view_caps.clear(); } m_plate_shadow_mask_key.clear(); + if (m_section_view->owner == this) + m_section_view->owner = nullptr; reset_volumes(); @@ -1474,6 +1478,7 @@ void GLCanvas3D::reset_volumes() m_selection.clear(); m_volumes.clear(); + m_section_view_caps.clear(); m_dirty = true; _set_warning_notification(EWarning::ObjectOutside, false); @@ -1624,6 +1629,42 @@ ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state(ObjectFil return state; } +void GLCanvas3D::set_section_view_ratio(double ratio) +{ + ratio = std::clamp(ratio, 0., 1.); + if (ratio == m_section_view->ratio) + return; + + if (ratio == 0.) + m_section_view->last_ratio = m_section_view->ratio; + m_section_view->ratio = ratio; + // Only the first cut faces the camera; later ones keep their angle until it is set again. + if (m_section_view->normal.isZero()) + align_section_view_to_camera(); + else + _on_section_view_changed(); +} + +void GLCanvas3D::toggle_section_view() +{ + const double last_ratio = m_section_view->last_ratio; + set_section_view_ratio(is_section_view_active() ? 0. : last_ratio > 0. ? last_ratio : 0.5); +} + +void GLCanvas3D::align_section_view_to_camera() +{ + m_section_view->normal = -wxGetApp().plater()->get_camera().get_dir_forward(); + _on_section_view_changed(); +} + +void GLCanvas3D::_on_section_view_changed() +{ + m_gizmos.update_section_view(); + // Set from the overlay, after this frame's scene was drawn. + set_as_dirty(); + request_extra_frame(); +} + void GLCanvas3D::toggle_world_axes_visibility(bool force_show) { if (force_show) { @@ -2126,7 +2167,7 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init) wxGetApp().imgui()->new_frame(); - if (m_picking_enabled) { + if (m_picking_enabled && !m_benchmarking) { if (m_rectangle_selection.is_dragging()) // picking pass using rectangle selection _rectangular_selection_picking_pass(); @@ -2151,22 +2192,30 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init) // An overlay-only frame reuses the last scene pass. The overlay is rebuilt either way, and drawn // below once it is known whether the frame differs from the one on screen. const bool reuse_scene = !scene_dirty && _can_reuse_cached_scene(camera); + // Only frames that redraw the scene are profiled. + if (!reuse_scene && (_is_render_timings_enabled() || m_frame_profiler.is_averaging())) + m_frame_profiler.begin_frame(); + Slic3r::ScopeGuard profiler_guard([this]() { m_frame_profiler.end_frame(); }); if (!reuse_scene) { _render_scene(camera, cnv_size); if (!overlay_tick) m_render_stats.increment_scene_fps_counter(); } - if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) + if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) { // BBS: GUI refactor: add canvas size as parameters _render_gcode_overlay(cnv_size.get_width(), cnv_size.get_height()); + m_frame_profiler.mark("legend"); + } // draw overlays _render_overlays(); + m_frame_profiler.mark("ui"); const int current_fps = m_render_stats.get_fps_and_reset_if_needed(); - if (_is_fps_overlay_enabled()) { + if (_is_fps_overlay_enabled() || _is_render_timings_enabled()) _render_fps_overlay(current_fps); + if (_is_fps_overlay_enabled()) { // The timer requests an overlay-only frame a second from now. A frame it requested // re-arms it only while a count is above zero. if (!overlay_tick || current_fps > 0 || m_render_stats.get_scene_fps() > 0) @@ -2256,12 +2305,14 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init) wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); wxGetApp().plater()->get_dailytips()->render(); } + m_frame_profiler.mark("notifications"); ImDrawData* draw_data = wxGetApp().imgui()->end_frame(); std::optional signature; if (_is_frame_skipping_enabled()) signature = _overlay_signature(draw_data); + m_frame_profiler.mark("imgui end"); if (reuse_scene) { // A reused scene under an unchanged overlay is the frame already on screen. @@ -2271,13 +2322,16 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init) } _render_overlay_toolbars(); + m_frame_profiler.mark("toolbars"); wxGetApp().imgui()->render(draw_data); + m_frame_profiler.mark("imgui draw"); // On Wayland, eglSwapBuffers blocks when the canvas is hidden or // occluded. Skip the swap to avoid stalling the render loop. if (m_canvas->IsShownOnScreen()) { m_canvas->SwapBuffers(); + m_frame_profiler.mark("swap"); if (!overlay_tick) m_render_stats.increment_fps_counter(); m_presented_signature = signature; @@ -2322,32 +2376,44 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) // floating would read as a rendering fault rather than a deliberate view option. if (show_bed) _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes); + m_frame_profiler.mark("bed"); if (show_bed) //BBS: add outline logic _render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid); if (m_axes_at_bed_center && show_bed) // Design tab: replace the plate's corner-origin grid with the origin-centred CAD grid. _render_cad_grid(camera.get_view_matrix(), camera.get_projection_matrix()); + m_frame_profiler.mark("plates"); //BBS: add outline logic // Depth pass for object-on-object and self shadows; consumed by the gouraud shader below. _render_shadows(camera.get_view_matrix(), camera.get_projection_matrix()); + m_frame_profiler.mark("shadows"); _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); + m_frame_profiler.mark("objects"); _render_sla_slices(); _render_selection(); _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running()); _render_wireframe_overlay(); + m_frame_profiler.mark("transparent"); } /* preview render */ else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) { + // Before the shadow pass, so the cut away part casts no shadow. + m_gcode_viewer.set_clipping_plane(_get_section_view_plane()); _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); _render_sla_slices(); _render_selection(); + m_frame_profiler.mark("objects"); _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes); + m_frame_profiler.mark("bed"); _render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id); + m_frame_profiler.mark("plates"); // Realistic view: the print casts a shadow onto the plate here as it does in View3D. _render_shadows(camera.get_view_matrix(), camera.get_projection_matrix()); + m_frame_profiler.mark("shadows"); // BBS: GUI refactor: add canvas size as parameters _render_gcode(cnv_size.get_width(), cnv_size.get_height()); + m_frame_profiler.mark("gcode"); } /* assemble render*/ else if (m_canvas_type == ECanvasType::CanvasAssembleView) { @@ -2364,6 +2430,7 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) // BBS: add outline logic _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running()); _render_wireframe_overlay(); + m_frame_profiler.mark("objects"); } _render_sequential_clearance(); @@ -2386,12 +2453,17 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) if (m_picking_enabled && m_rectangle_selection.is_dragging()) m_rectangle_selection.render(*this); + m_frame_profiler.mark("gizmos"); - if (_is_ssao_enabled()) + if (_is_ssao_enabled()) { _render_ssao_pass(static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height())); + m_frame_profiler.mark("ssao"); + } - if (_is_fxaa_enabled()) + if (_is_fxaa_enabled()) { _render_fxaa_pass(static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height())); + m_frame_profiler.mark("fxaa"); + } // Design tab: interactive 2D sketch overlay, drawn over the scene but // beneath the UI overlays (toolbars, labels). @@ -2401,6 +2473,7 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size) #endif _capture_scene_cache(camera); + m_frame_profiler.mark("cache"); } void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data, @@ -3121,7 +3194,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Bed); m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Volume); m_gizmos.update_data(); - m_gizmos.update_assemble_view_data(); m_gizmos.refresh_on_off_state(); // Update the toolbar @@ -3394,7 +3466,7 @@ void GLCanvas3D::unbind_event_handlers() void GLCanvas3D::on_idle(wxIdleEvent& evt) { - if (!m_initialized) + if (!m_initialized || m_benchmarking) return; // Toolbar states, notifications and ImGui's own layout settling only touch the overlay. @@ -3837,12 +3909,18 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) m_key_down = { keyCode, key_repeats(keyCode) }; else if (evt.GetEventType() == wxEVT_KEY_UP) key_released(keyCode); + const bool alt_wheel_released = evt.GetEventType() == wxEVT_KEY_UP && keyCode == WXK_ALT && std::exchange(m_alt_wheel_used, false); auto imgui = wxGetApp().imgui(); if (imgui->update_key_data(evt)) render(); else { + // Before the gizmos and the selection, which Esc also closes. + if (evt.GetEventType() == wxEVT_KEY_DOWN && keyCode == WXK_ESCAPE && std::exchange(m_section_view->panel_open, false)) { + _set_overlay_as_dirty(); + return; + } if (!m_gizmos.on_key(evt)) { if (evt.GetEventType() == wxEVT_KEY_UP) { if (evt.ShiftDown() && evt.ControlDown() && keyCode == WXK_SPACE) { @@ -3911,7 +3989,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) && keyCode != WXK_LEFT && keyCode != WXK_UP && keyCode != WXK_RIGHT - && keyCode != WXK_DOWN) { + && keyCode != WXK_DOWN + && !alt_wheel_released) { evt.Skip(); // Needed to have EVT_CHAR generated as well } } @@ -3931,6 +4010,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) if (evt.MiddleIsDown()) return; + m_alt_wheel_used |= evt.AltDown(); + #if ENABLE_RETINA_GL const float scale = m_retina_helper->get_scale_factor(); evt.SetX(evt.GetX() * scale); @@ -3976,25 +4057,21 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) if (m_gizmos.on_mouse_wheel(evt)) return; - if (m_canvas_type == CanvasAssembleView && (evt.AltDown() || evt.CmdDown()) && m_gizmos.m_assemble_view_data != nullptr) { + if (evt.AltDown()) { + set_section_view_ratio(get_section_view_ratio() + (evt.GetWheelRotation() < 0 ? -0.01 : 0.01)); + return; + } + + if (m_canvas_type == CanvasAssembleView && evt.CmdDown()) { float rotation = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); - if (evt.AltDown()) { - auto clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position(); - clp_dist = rotation < 0.f - ? std::max(0., clp_dist - 0.01) - : std::min(1., clp_dist + 0.01); - m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true); - } - else if (evt.CmdDown()) { - m_explosion_ratio = rotation < 0.f - ? std::max(1., m_explosion_ratio - 0.01) - : std::min(3., m_explosion_ratio + 0.01); - if (m_explosion_ratio != GLVolume::explosion_ratio) { - for (GLVolume* volume : m_volumes.volumes) { - volume->set_bounding_boxes_as_dirty(); - } - GLVolume::explosion_ratio = m_explosion_ratio; + m_explosion_ratio = rotation < 0.f + ? std::max(1., m_explosion_ratio - 0.01) + : std::min(3., m_explosion_ratio + 0.01); + if (m_explosion_ratio != GLVolume::explosion_ratio) { + for (GLVolume* volume : m_volumes.volumes) { + volume->set_bounding_boxes_as_dirty(); } + GLVolume::explosion_ratio = m_explosion_ratio; } return; } @@ -7827,7 +7904,51 @@ int GLCanvas3D::_get_effective_fps_cap() const bool GLCanvas3D::_is_fps_overlay_enabled() const { - return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY); + return !m_benchmarking && wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY); +} + +// Above the front left of the plate. +static const Vec3d STATIC_LIGHT_DIR = Vec3d(-0.4, -0.6, 1.0).normalized(); + +std::optional GLCanvas3D::_static_light_dir_eye() const +{ + if (!_is_realistic_view_enabled() || _shadow_mode() != EShadowMode::Static) + return std::nullopt; + const Matrix3d view_rot = wxGetApp().plater()->get_camera().get_view_matrix().matrix().block<3, 3>(0, 0); + return Vec3d((view_rot * STATIC_LIGHT_DIR).normalized()); +} + +GLCanvas3D::EShadowMode GLCanvas3D::_shadow_mode() const +{ + const std::string mode = wxGetApp().app_config != nullptr ? wxGetApp().app_config->get(SETTING_OPENGL_REALISTIC_SHADOWS) : std::string(); + return mode == "static" ? EShadowMode::Static : mode == "orbit" ? EShadowMode::Orbit : EShadowMode::Off; +} + +size_t GLCanvas3D::_shadow_casters_signature(bool toolpath_casters) const +{ + if (toolpath_casters) + return m_gcode_viewer.shadow_casters_signature(); + + size_t hash = 1; + for (const GLVolume* volume : m_volumes.volumes) { + if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower) + continue; + boost::hash_combine(hash, volume); + boost::hash_combine(hash, volume->model.vertices_count()); + boost::hash_combine(hash, volume->model.indices_count()); + const BoundingBoxf3& bb = volume->model.get_bounding_box(); + for (double value : { bb.min.x(), bb.min.y(), bb.min.z(), bb.max.x(), bb.max.y(), bb.max.z() }) + boost::hash_combine(hash, value); + const Transform3d world = volume->world_matrix(); + for (int i = 0; i < 16; ++i) + boost::hash_combine(hash, world.matrix().data()[i]); + } + return hash; +} + +bool GLCanvas3D::_is_render_timings_enabled() const +{ + return !m_benchmarking && wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SHOW_RENDER_TIMINGS); } bool GLCanvas3D::_is_scene_cache_enabled() const @@ -7862,14 +7983,22 @@ bool GLCanvas3D::_is_frame_skipping_enabled() const void GLCanvas3D::_render_fps_overlay(int fps) const { - if (fps < 0) + const bool show_fps = _is_fps_overlay_enabled() && fps >= 0; + const std::vector& sections = m_frame_profiler.sections(); + const bool show_timings = _is_render_timings_enabled() && !sections.empty(); + if (!show_fps && !show_timings) return; ImGuiWrapper& imgui = *wxGetApp().imgui(); const float margin = 10.0f * get_scale(); const ImVec2 display_size = ImGui::GetIO().DisplaySize; - ImGui::SetNextWindowPos(ImVec2(display_size.x - margin, margin), ImGuiCond_Always, ImVec2(1.0f, 0.0f)); + ImVec2 pos(display_size.x - margin, margin); + // The Preview legend takes the top-right corner. + if (const ImGuiWindow* legend = ImGui::FindWindowByName("Legend"); m_canvas_type == ECanvasType::CanvasPreview && legend != nullptr && legend->Active) + pos = ImVec2(legend->Pos.x - margin, legend->Pos.y); + ImGui::SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(1.0f, 0.0f)); ImGui::SetNextWindowBgAlpha(0.35f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f * get_scale()); imgui.begin( std::string("###fps_overlay"), ImGuiWindowFlags_AlwaysAutoResize | @@ -7879,10 +8008,38 @@ void GLCanvas3D::_render_fps_overlay(int fps) const ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); - imgui.text(std::string("FPS: ") + std::to_string(fps)); - // The subset of those frames that redrew the scene rather than reusing the cached one. - imgui.text(std::string("3D: ") + std::to_string(m_render_stats.get_scene_fps())); + if (show_fps) { + imgui.text(std::string("FPS: ") + std::to_string(fps)); + ImGui::SameLine(); + // The subset of those frames that redrew the scene rather than reusing the cached one. + imgui.text(std::string("3D: ") + std::to_string(m_render_stats.get_scene_fps())); + } + if (show_timings && ImGui::BeginTable("frame_sections", 3, ImGuiTableFlags_SizingFixedFit)) { + ImGui::TableSetupColumn("ms"); + ImGui::TableSetupColumn("CPU"); + ImGui::TableSetupColumn("GPU"); + ImGui::TableHeadersRow(); + double cpu_ms = 0.0; + double gpu_ms = 0.0; + auto row = [](const char* name, double cpu, double gpu) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::TextUnformatted(name); + ImGui::TableSetColumnIndex(1); + ImGui::Text("%.2f", cpu); + ImGui::TableSetColumnIndex(2); + ImGui::Text("%.2f", gpu); + }; + for (const FrameProfiler::Section& section : sections) { + row(section.name, section.cpu_ms, section.gpu_ms); + cpu_ms += section.cpu_ms; + gpu_ms += section.gpu_ms; + } + row("total", cpu_ms, gpu_ms); + ImGui::EndTable(); + } imgui.end(); + ImGui::PopStyleVar(); } void GLCanvas3D::_render_fxaa_pass(unsigned int width, unsigned int height) @@ -8232,7 +8389,8 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform return; if (!_is_realistic_view_enabled()) return; - if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS)) + const EShadowMode mode = _shadow_mode(); + if (mode == EShadowMode::Off) return; // The preview canvas holds no volumes of its own for FFF. Once slicing has run its printed @@ -8247,10 +8405,11 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform if (OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Arb) { - // Light direction (same as used in shading and plate shading) + // Orbit: the light used for shading, fixed to the camera. Static: a world light, also used for shading. const Vec3d light_dir_eye = Vec3d(-0.4574957, 0.4574957, 0.7624929).normalized(); const Matrix3d view_rot = view_matrix.matrix().block<3, 3>(0, 0); - const Vec3d dir_to_light = (view_rot.transpose() * light_dir_eye).normalized(); + const Vec3d dir_to_light = mode == EShadowMode::Static ? STATIC_LIGHT_DIR : + Vec3d((view_rot.transpose() * light_dir_eye).normalized()); // Bounding box of the printable objects (the shadow casters). BoundingBoxf3 obj_bb; @@ -8302,11 +8461,19 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform lmin = lmin.cwiseMin(lp); lmax = lmax.cwiseMax(lp); }; + // The plate area a shadow can reach: the casters' footprint and where their corners land on z = 0. + Vec2d reach_min(DBL_MAX, DBL_MAX); + Vec2d reach_max(-DBL_MAX, -DBL_MAX); + auto reach = [&](const Vec3d& p) { + reach_min = reach_min.cwiseMin(Vec2d(p.x(), p.y())); + reach_max = reach_max.cwiseMax(Vec2d(p.x(), p.y())); + }; for (int i = 0; i < 8; ++i) { const Vec3d corner((i & 1) ? obj_bb.max.x() : obj_bb.min.x(), (i & 2) ? obj_bb.max.y() : obj_bb.min.y(), (i & 4) ? obj_bb.max.z() : obj_bb.min.z()); enclose(corner); + reach(corner); // Where this corner's shadow lands on z = 0, clamped to the plate so a grazing angle // (t -> infinity) stays bounded. if (ray_dir.z() < -1e-6) { @@ -8316,6 +8483,7 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform s.y() = std::min(std::max(s.y(), plate_bb.min.y()), plate_bb.max.y()); s.z() = 0.0; enclose(s); + reach(s); } } @@ -8349,6 +8517,11 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform // Create / resize the depth texture and FBO const unsigned int size = 2048; + + // Padded by the filter's 2 texel reach, stretched where the light grazes the plate. + const double reach_margin = 3.0 * 2.0 * std::max(halfx, halfy) / size / std::max(0.1, std::abs(dir_to_light.z())); + m_shadow_plate_bounds = { float(reach_min.x() - reach_margin), float(reach_min.y() - reach_margin), + float(reach_max.x() + reach_margin), float(reach_max.y() + reach_margin) }; if (m_shadow_map_texture_id == 0) { glsafe(::glGenTextures(1, &m_shadow_map_texture_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_shadow_map_texture_id)); @@ -8368,66 +8541,80 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform if (m_shadow_map_fbo == 0) glsafe(::glGenFramebuffers(1, &m_shadow_map_fbo)); - // Save OpenGL state that we will modify - GLint prev_viewport[4] = { 0, 0, 0, 0 }; - glsafe(::glGetIntegerv(GL_VIEWPORT, prev_viewport)); - GLint prev_fbo = 0; - glsafe(::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo)); - GLboolean prev_color_mask[4] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE }; - glsafe(::glGetBooleanv(GL_COLOR_WRITEMASK, prev_color_mask)); - const GLboolean prev_cull = ::glIsEnabled(GL_CULL_FACE); - GLint prev_depth_func = GL_LESS; - glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func)); - GLboolean prev_depth_mask = GL_TRUE; - glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &prev_depth_mask)); - glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, m_shadow_map_fbo)); - glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadow_map_texture_id, 0)); - glsafe(::glDrawBuffer(GL_NONE)); - glsafe(::glReadBuffer(GL_NONE)); - - if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, static_cast(prev_fbo))); - m_shadow_map_valid = false; - } else { - glsafe(::glViewport(0, 0, size, size)); - glsafe(::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)); - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glDepthMask(GL_TRUE)); - glsafe(::glDepthFunc(GL_LESS)); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); - glsafe(::glPolygonOffset(4.0f, 4.0f)); - glsafe(::glDisable(GL_CULL_FACE)); - - if (toolpath_casters) - m_gcode_viewer.render_shadow_casters(Transform3d(light_view), Transform3d(light_proj), eye); - // Only this branch draws through "flat"; the toolpaths bring their own program. - else if (GLShaderProgram* shader = wxGetApp().get_shader("flat"); shader != nullptr) { - shader->start_using(); - shader->set_uniform("projection_matrix", Transform3d(light_proj)); - for (GLVolume* volume : m_volumes.volumes) { - if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower) - continue; - const Transform3d view_model = Transform3d(light_view) * volume->world_matrix(); - shader->set_uniform("view_model_matrix", view_model); - volume->model.render(shader); - } - shader->stop_using(); - } - - // Restore state - glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); - glsafe(::glColorMask(prev_color_mask[0], prev_color_mask[1], prev_color_mask[2], prev_color_mask[3])); - if (prev_cull) - glsafe(::glEnable(GL_CULL_FACE)); - else - glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glDepthFunc(prev_depth_func)); - glsafe(::glDepthMask(prev_depth_mask)); - glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, static_cast(prev_fbo))); - glsafe(::glViewport(prev_viewport[0], prev_viewport[1], prev_viewport[2], prev_viewport[3])); - + // A static light keeps the map until its frustum or the casters change. + size_t cache_key = 0; + if (mode == EShadowMode::Static) { + cache_key = _shadow_casters_signature(toolpath_casters); + for (int i = 0; i < 16; ++i) + boost::hash_combine(cache_key, m_shadow_light_vp.matrix().data()[i]); + } + if (cache_key != 0 && cache_key == m_shadow_map_key) m_shadow_map_valid = true; + else { + m_shadow_map_key = 0; + // Save OpenGL state that we will modify + GLint prev_viewport[4] = { 0, 0, 0, 0 }; + glsafe(::glGetIntegerv(GL_VIEWPORT, prev_viewport)); + GLint prev_fbo = 0; + glsafe(::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo)); + GLboolean prev_color_mask[4] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE }; + glsafe(::glGetBooleanv(GL_COLOR_WRITEMASK, prev_color_mask)); + const GLboolean prev_cull = ::glIsEnabled(GL_CULL_FACE); + GLint prev_depth_func = GL_LESS; + glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func)); + GLboolean prev_depth_mask = GL_TRUE; + glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &prev_depth_mask)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, m_shadow_map_fbo)); + glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadow_map_texture_id, 0)); + glsafe(::glDrawBuffer(GL_NONE)); + glsafe(::glReadBuffer(GL_NONE)); + + if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, static_cast(prev_fbo))); + m_shadow_map_valid = false; + } else { + glsafe(::glViewport(0, 0, size, size)); + glsafe(::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_TRUE)); + glsafe(::glDepthFunc(GL_LESS)); + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); + glsafe(::glPolygonOffset(4.0f, 4.0f)); + glsafe(::glDisable(GL_CULL_FACE)); + + if (toolpath_casters) + m_gcode_viewer.render_shadow_casters(Transform3d(light_view), Transform3d(light_proj), eye); + // Only this branch draws through "flat"; the toolpaths bring their own program. + else if (GLShaderProgram* shader = wxGetApp().get_shader("flat"); shader != nullptr) { + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d(light_proj)); + for (GLVolume* volume : m_volumes.volumes) { + if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower) + continue; + const Transform3d view_model = Transform3d(light_view) * volume->world_matrix(); + shader->set_uniform("view_model_matrix", view_model); + volume->model.render(shader); + } + shader->stop_using(); + } + + // Restore state + glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); + glsafe(::glColorMask(prev_color_mask[0], prev_color_mask[1], prev_color_mask[2], prev_color_mask[3])); + if (prev_cull) + glsafe(::glEnable(GL_CULL_FACE)); + else + glsafe(::glDisable(GL_CULL_FACE)); + glsafe(::glDepthFunc(prev_depth_func)); + glsafe(::glDepthMask(prev_depth_mask)); + glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, static_cast(prev_fbo))); + glsafe(::glViewport(prev_viewport[0], prev_viewport[1], prev_viewport[2], prev_viewport[3])); + + m_shadow_map_valid = true; + } + if (m_shadow_map_valid) + m_shadow_map_key = cache_key; } } else { m_shadow_map_valid = false; @@ -8527,6 +8714,7 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform plate_shader->set_uniform("shadow_light_vp", m_shadow_light_vp); plate_shader->set_uniform("shadow_intensity", 0.35f); plate_shader->set_uniform("shadow_map_texel", 1.0f / static_cast(m_shadow_map_size)); + plate_shader->set_uniform("shadow_bounds", m_shadow_plate_bounds); m_plate_shadow_mask.render(plate_shader); plate_shader->stop_using(); @@ -8556,7 +8744,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with glsafe(::glEnable(GL_DEPTH_TEST)); - m_camera_clipping_plane = m_gizmos.get_clipping_plane(); + m_camera_clipping_plane = _get_volumes_clipping_plane(); if (m_picking_enabled) // Update the layer editing selection to the first object selected, update the current object maximum Z. @@ -8599,10 +8787,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with GLGizmosManager& gm = get_gizmos_manager(); GLGizmoBase* current_gizmo = gm.get_current(); - if (m_canvas_type == CanvasAssembleView) { - m_volumes.set_clipping_plane(m_gizmos.get_assemble_view_clipping_plane().get_data()); - } - else if (current_gizmo && !current_gizmo->apply_clipping_plane()) { + if (current_gizmo && !current_gizmo->apply_clipping_plane()) { m_volumes.set_clipping_plane(ClippingPlane::ClipsNothing().get_data()); } else { @@ -8654,6 +8839,10 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } else shader->set_uniform("shadow_intensity", 0.0f); + const std::optional static_light = _static_light_dir_eye(); + shader->set_uniform("use_static_light", static_light.has_value()); + if (static_light.has_value()) + shader->set_uniform("static_light_dir", *static_light); const Size& cvn_size = get_canvas_size(); { @@ -8711,6 +8900,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } } + _render_section_view_caps(); break; } case GLVolumeCollection::ERenderType::Transparent: @@ -8732,12 +8922,6 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } }, partly_inside_enable, printable_heights); - if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) { - const GLGizmosManager& gm = get_gizmos_manager(); - shader->stop_using(); - gm.render_painter_assemble_view(); - shader->start_using(); - } break; } } @@ -8751,6 +8935,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); glsafe(::glActiveTexture(GL_TEXTURE0)); } + shader->set_uniform("use_static_light", false); shader->stop_using(); } @@ -8758,6 +8943,42 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with m_camera_clipping_plane = ClippingPlane::ClipsNothing(); } +void GLCanvas3D::_render_section_view_caps() +{ + // A gizmo with its own clipper draws its own cut faces. + const ClippingPlane plane = m_gizmos.get_clipping_plane().has_value() ? ClippingPlane::ClipsNothing() : _get_section_view_plane(); + if (!plane.is_active() || m_model == nullptr) { + m_section_view_caps.clear(); + return; + } + + // Last frame's clippers are reused, so unchanged cuts are not recomputed. + std::map caps; + for (const GLVolume* volume : m_volumes.volumes) { + if (!volume->is_active || volume->is_modifier || volume->is_wipe_tower || volume->volume_idx() < 0 || + volume->object_idx() >= int(m_model->objects.size())) + continue; + const ModelObject* object = m_model->objects[volume->object_idx()]; + if (volume->volume_idx() >= int(object->volumes.size())) + continue; + // Skip volumes the plane misses. + const BoundingBoxf3& box = volume->transformed_bounding_box(); + if (std::abs(plane.distance(box.center())) > 0.5 * box.size().dot(plane.get_normal().cwiseAbs())) + continue; + + auto node = m_section_view_caps.extract(volume); + MeshClipper& clipper = node ? caps.insert(std::move(node)).position->second : caps[volume]; + clipper.set_mesh(object->volumes[volume->volume_idx()]->mesh().its); + clipper.set_plane(plane); + clipper.set_transformation(Geometry::Transformation(volume->world_matrix())); + // No cut face below the plate. + if (m_canvas_type != CanvasAssembleView) + clipper.set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); + clipper.render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }); + } + m_section_view_caps = std::move(caps); +} + bool GLCanvas3D::_is_xray_view_active() const { if (m_canvas_type == ECanvasType::CanvasPreview || !wxGetApp().plater()->is_show_xray()) @@ -8864,8 +9085,9 @@ void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height) // again - realistic view with at least one lossy pass on - else the lift would just clip. const AppConfig* cfg = wxGetApp().app_config; const bool lossy_passes = cfg != nullptr && _is_realistic_view_enabled() && - (cfg->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS) || cfg->get_bool(SETTING_OPENGL_PHONG_SSAO)); + (_shadow_mode() != EShadowMode::Off || cfg->get_bool(SETTING_OPENGL_PHONG_SSAO)); m_gcode_viewer.set_tone(lossy_passes ? 1.1f : 1.0f, 1.15f); + m_gcode_viewer.set_light_top_dir(_static_light_dir_eye().value_or(Vec3d(-0.4574957, 0.4574957, 0.7624929))); m_gcode_viewer.render_scene(canvas_width, canvas_height); @@ -9846,7 +10068,31 @@ void GLCanvas3D::_render_canvas_toolbar() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding , padding); // without padding images clipping imgui.begin(_L("Canvas Toolbar"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse);// + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollWithMouse);// + + // Section view, on top so its panel opens above the toolbar. + const bool section_view = is_section_view_active(); + ImTextureID s_normal_id = m_gizmos.get_icon_texture_id(section_view ? + (m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_ACTIVE_DARK : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_ACTIVE) : + (m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_DARK : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION)); + ImTextureID s_hover_id = m_gizmos.get_icon_texture_id(section_view ? + (m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_ACTIVE_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_ACTIVE_HOVER) : + (m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_SECTION_HOVER)); + + if (ImGui::ImageButton3(s_normal_id, s_hover_id, btn_size)) + m_section_view->panel_open = !m_section_view->panel_open; + else if (ImGui::IsItemHovered()) { + if (const float wheel = ImGui::GetIO().MouseWheel; wheel != 0.f) + set_section_view_ratio(get_section_view_ratio() + (wheel < 0.f ? -0.01 : 0.01)); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) + toggle_section_view(); + else if (ImGui::IsMouseClicked(ImGuiMouseButton_Middle)) + align_section_view_to_camera(); + imgui.tooltip(_L("Section view"), ImGui::GetFontSize() * 20.0f); + } + const ImVec2 section_panel_pos = ImGui::GetItemRectMin() - ImVec2(0.f, spacing.y); + + ImGui::Dummy({ 0, spacing.y}); ImTextureID m_normal_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_DARK : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU); ImTextureID m_hover_id = m_gizmos.get_icon_texture_id(m_is_dark ? GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_DARK_HOVER : GLGizmosManager::MENU_ICON_NAME::IC_CANVAS_MENU_HOVER); @@ -10012,6 +10258,76 @@ void GLCanvas3D::_render_canvas_toolbar() ImGui::PopStyleVar(6); imgui.end(); + + _render_section_view_panel(section_panel_pos); +} + +void GLCanvas3D::_render_section_view_panel(const ImVec2& bottom_left) +{ + if (!m_section_view->panel_open) + return; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + const float sc = get_scale(); + + ImGuiWrapper::push_toolbar_style(sc); + ImGui::PushStyleColor(ImGuiCol_WindowBg, m_is_dark ? ImGuiWrapper::COL_TOOLBAR_BG_DARK : ImGuiWrapper::COL_TOOLBAR_BG); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.f * sc); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.f, 8.f) * sc); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.f, 4.f) * sc); + + ImGui::SetNextWindowPos(bottom_left, ImGuiCond_Always, ImVec2(0.f, 1.f)); + imgui.begin(std::string("##CanvasSectionView"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar); + + const wxString alt = GUI::shortkey_alt_prefix(); + const std::vector> tips = { + { alt + _L("Mouse wheel"), _L("Move section plane") }, + { _L("Mouse wheel on icon"), _L("Move section plane") }, + { _L("Right click on icon"), _L("Toggle section view") }, + { _L("Middle click on icon"), _L("Set viewing angle") }, + }; + // render_tooltip_button() puts the tips below y plus the panel height; they go above the panel. + const ImGuiStyle& style = ImGui::GetStyle(); + const float tips_h = tips.size() * (ImGui::GetTextLineHeight() + style.ItemSpacing.y) - style.ItemSpacing.y + 2.f * style.WindowPadding.y; + GLGizmoUtils::render_tooltip_button(&imgui, *this, tips, ImGui::GetWindowPos().x, + ImGui::GetWindowPos().y - style.ItemSpacing.y - tips_h - ImGui::GetContentRegionMax().y - ImGui::GetFrameHeight()); + + ImGui::SameLine(); + ImGui::AlignTextToFramePadding(); + imgui.text(_L("Section view")); + + float ratio = float(get_section_view_ratio()); + ImGui::SameLine(); + ImGui::SetNextItemWidth(imgui.scaled(7.f)); + bool changed = imgui.bbl_slider_float_style("##section_view", &ratio, 0.f, 1.f, "%.2f", 1.0f, true); + ImGui::SameLine(); + ImGui::SetNextItemWidth(1.5f * imgui.get_slider_icon_size().x); + changed |= ImGui::BBLDragFloat("##section_view_input", &ratio, 0.05f, 0.0f, 0.0f, "%.2f"); + if (changed) + set_section_view_ratio(ratio); + + ImGui::SameLine(); + if (imgui.button(_L("Set viewing angle"))) + align_section_view_to_camera(); + + imgui.disabled_begin(!is_section_view_active()); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.f, 0.f, 0.f, 0.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.f, 0.f, 0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.f); + if (imgui.button(wxString(ImGui::RevertBtn) + "##section_view_reset", _L("Reset"))) + set_section_view_ratio(0.); + ImGui::PopStyleVar(); + ImGui::PopStyleColor(3); + imgui.disabled_end(); + + imgui.end(); + + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(); + ImGuiWrapper::pop_toolbar_style(); } void GLCanvas3D::_render_separator_toolbar_right() const @@ -10259,17 +10575,12 @@ float GLCanvas3D::_render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) c //BBS void GLCanvas3D::_render_assemble_control() { - if(m_gizmos.m_assemble_view_data == nullptr) - return; - if (m_canvas_type != ECanvasType::CanvasAssembleView) { GLVolume::explosion_ratio = m_explosion_ratio = 1.0; return; } - if (m_gizmos.get_current_type() == GLGizmosManager::EType::MmSegmentation) { - m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(0.0, true); + if (m_gizmos.get_current_type() == GLGizmosManager::EType::MmSegmentation) return; - } ImGuiWrapper* imgui = wxGetApp().imgui(); @@ -10279,8 +10590,6 @@ void GLCanvas3D::_render_assemble_control() auto canvas_h = float(get_canvas_size().get_height()); const float text_padding = 7.0f; - const float text_size_x = std::max(imgui->calc_text_size(_L("Reset direction")).x + 2 * ImGui::GetStyle().FramePadding.x, - std::max(imgui->calc_text_size(_L("Explosion Ratio")).x, imgui->calc_text_size(_L("Section View")).x)); const float slider_width = 60.0f; const float value_size = imgui->calc_text_size("3.00"sv).x + text_padding * 2; const float item_spacing = imgui->get_item_spacing().x; @@ -10295,34 +10604,6 @@ void GLCanvas3D::_render_assemble_control() tooltip_button_width = _render_assembly_tooltip_button(imgui); } float same_line_width = tooltip_button_width; - { - float clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position(); - if (clp_dist == 0.f) { - ImGui::AlignTextToFramePadding(); - imgui->text(_L("Section View")); - } - else { - if (imgui->button(_L("Reset direction"))) { - wxGetApp().CallAfter([this]() { - m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(-1., false); - }); - } - } - same_line_width += (text_size_x + item_spacing); - ImGui::SameLine(same_line_width); - ImGui::PushItemWidth(slider_width); - bool view_slider_changed = imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - - same_line_width += (slider_width + item_spacing); - ImGui::SameLine(same_line_width); - ImGui::PushItemWidth(value_size); - bool view_input_changed = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - - if (view_slider_changed || view_input_changed) - m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true); - - same_line_width += (value_size + item_spacing * 2); - } { auto temp_x = imgui->calc_text_size(_L("Explosion Ratio")).x; ImGui::SameLine(same_line_width); @@ -10746,12 +11027,42 @@ Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos) return mouse_ray(mouse_pos).intersect_plane(0.0); } +ClippingPlane GLCanvas3D::_get_section_view_plane() const +{ + const SectionView& section_view = *m_section_view; + if (section_view.ratio == 0.) + return ClippingPlane::ClipsNothing(); + + // The owner's objects, so Preview cuts where Prepare does. + const GLCanvas3D& owner = section_view.owner != nullptr ? *section_view.owner : *this; + BoundingBoxf3 box = owner.volumes_bounding_box(true); + if (!box.defined) + box = owner.volumes_bounding_box(); + // G-code without objects: its toolpaths, merged by corner as a flat box is undefined. + if (!box.defined && m_gcode_viewer.has_data()) { + box.merge(m_gcode_viewer.get_paths_bounding_box().min); + box.merge(m_gcode_viewer.get_paths_bounding_box().max); + } + if (!box.defined) + return ClippingPlane::ClipsNothing(); + + // Sweeps the bounding sphere from the camera side (0) to the far side (1), as ObjectClipper does. + const double radius = box.radius(); + return ClippingPlane(section_view.normal, section_view.normal.dot(box.center()) + radius - 2. * radius * section_view.ratio); +} + +ClippingPlane GLCanvas3D::_get_volumes_clipping_plane() const +{ + const std::optional gizmo_plane = m_gizmos.get_clipping_plane(); + return gizmo_plane.has_value() ? *gizmo_plane : _get_section_view_plane().inverted_normal(); +} + ClippingPlane GLCanvas3D::get_raycaster_clipping_plane() const { // Orca: Ignore the gizmo clipping plane when the active tool does not apply it, and // invert the result into the convention expected by SceneRaycaster. GLGizmoBase* current_gizmo = m_gizmos.get_current(); - return ((!current_gizmo || current_gizmo->apply_clipping_plane()) ? m_gizmos.get_clipping_plane() : + return ((!current_gizmo || current_gizmo->apply_clipping_plane()) ? _get_volumes_clipping_plane() : ClippingPlane::ClipsNothing()) .inverted_normal(); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f861e15ca1..9bb2d68b42 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -37,6 +37,7 @@ #include "Camera.hpp" #include "SceneRaycaster.hpp" #include "SceneCache.hpp" +#include "FrameProfiler.hpp" #include "IMToolbar.hpp" #include "slic3r/GUI/3DBed.hpp" #include "libslic3r/Slicing.hpp" @@ -619,6 +620,19 @@ private: std::array m_clipping_planes; ClippingPlane m_camera_clipping_plane; bool m_use_clipping_planes; + struct SectionView + { + explicit SectionView(const GLCanvas3D* owner) : owner(owner) {} + double ratio{ 0. }; // 0 = off + double last_ratio{ 0. }; // before it was switched off + Vec3d normal{ Vec3d::Zero() }; // zero until first aimed + bool panel_open{ false }; + const GLCanvas3D* owner; // whose objects place the plane + }; + std::shared_ptr m_section_view{ std::make_shared(this) }; + std::map m_section_view_caps; + // Its release would open the hidden window menu on Windows. + bool m_alt_wheel_used{ false }; std::array m_sla_caps; std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false @@ -701,6 +715,8 @@ private: bool m_reload_delayed; RenderStats m_render_stats; + FrameProfiler m_frame_profiler; + bool m_benchmarking{ false }; std::chrono::time_point m_last_frame_start_time{ std::chrono::steady_clock::now() }; int m_imgui_undo_redo_hovered_pos{ -1 }; @@ -833,6 +849,10 @@ public: unsigned int m_shadow_map_size{ 0 }; Transform3d m_shadow_light_vp{ Transform3d::Identity() }; bool m_shadow_map_valid{ false }; + // Casters and light frustum the map was last rendered for, under a static light. 0 when none. + size_t m_shadow_map_key{ 0 }; + // Plate rectangle a shadow can reach, min xy then max xy. + std::array m_shadow_plate_bounds{ { 0.0f, 0.0f, 0.0f, 0.0f } }; public: explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed); ~GLCanvas3D(); @@ -943,6 +963,14 @@ public: void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); } void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); } + bool is_section_view_active() const { return m_section_view->ratio > 0.; } + double get_section_view_ratio() const { return m_section_view->ratio; } + const Vec3d& get_section_view_normal() const { return m_section_view->normal; } + void set_section_view_ratio(double ratio); + void toggle_section_view(); + void align_section_view_to_camera(); + void share_section_view(const GLCanvas3D& owner) { m_section_view = owner.m_section_view; } + void toggle_world_axes_visibility(bool force_show = false); void refresh_camera_scene_box(); void set_color_by(const std::string& value); @@ -1251,6 +1279,10 @@ public: void schedule_extra_frame(int milliseconds); + // The scene benchmark draws every frame itself, without picking or the FPS and timings overlays. + void set_benchmarking(bool benchmarking) { m_benchmarking = benchmarking; } + FrameProfiler& get_frame_profiler() { return m_frame_profiler; } + int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); } void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); } void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); } @@ -1364,6 +1396,12 @@ private: bool _is_ssao_enabled() const; int _get_effective_fps_cap() const; bool _is_fps_overlay_enabled() const; + bool _is_render_timings_enabled() const; + enum class EShadowMode { Off, Static, Orbit }; + EShadowMode _shadow_mode() const; + // Direction to the static shadow light in eye space, when it lights the scene. + std::optional _static_light_dir_eye() const; + size_t _shadow_casters_signature(bool toolpath_casters) const; bool _is_scene_cache_enabled() const; bool _is_scene_cacheable() const; bool _is_frame_skipping_enabled() const; @@ -1392,6 +1430,7 @@ private: void _render_cad_grid(const Transform3d& view_matrix, const Transform3d& projection_matrix); //BBS: add outline drawing logic void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true); + void _render_section_view_caps(); void _render_wireframe_overlay(); bool _is_xray_view_active() const; void _render_xray_volumes(); @@ -1418,6 +1457,7 @@ private: void _render_assemble_view_toolbar() const; void _render_return_toolbar() const; void _render_canvas_toolbar(); + void _render_section_view_panel(const ImVec2& bottom_left); void _render_separator_toolbar_right() const; void _render_separator_toolbar_left() const; void _render_collapse_toolbar() const; @@ -1449,6 +1489,11 @@ private: Gesture }; + void _on_section_view_changed(); + // In the ClippingPlane::is_point_clipped() convention. + ClippingPlane _get_section_view_plane() const; + // In the volume shaders' convention: the open gizmo's own plane, else the section view's. + ClippingPlane _get_volumes_clipping_plane() const; // Orca: These helpers keep clipping, orbit pivots, and perspective-pan depth selection consistent. ClippingPlane get_raycaster_clipping_plane() const; bool is_bed_visible() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7eaa0aad85..94ef20e9fd 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -6735,8 +6735,10 @@ void GUI_App::reload_settings() tab->reload_config(); tab->update_changed_ui(); } - if (plater_) + if (plater_) { plater_->sidebar().update_all_preset_comboboxes(); + plater_->normalize_bed_types(false); + } }; if (is_main_thread_active()) refresh_synced_ui(); @@ -8631,8 +8633,8 @@ void GUI_App::open_preferences(PreferencesTab tab, const std::string& highlight_ { // Render settings the canvas reads every frame; a change needs one redraw to show. static constexpr const char* opengl_render_setting_keys[] = { - SETTING_OPENGL_FXAA_ENABLED, SETTING_OPENGL_FPS_CAP, SETTING_OPENGL_SHOW_FPS_OVERLAY, SETTING_OPENGL_SCENE_CACHE, - SETTING_OPENGL_SKIP_IDENTICAL_FRAMES + SETTING_OPENGL_FXAA_ENABLED, SETTING_OPENGL_FPS_CAP, SETTING_OPENGL_SHOW_FPS_OVERLAY, SETTING_OPENGL_SHOW_RENDER_TIMINGS, + SETTING_OPENGL_SCENE_CACHE, SETTING_OPENGL_SKIP_IDENTICAL_FRAMES, SETTING_OPENGL_REALISTIC_SHADOWS }; std::vector previous_opengl_render_settings; for (const char* key : opengl_render_setting_keys) diff --git a/src/slic3r/GUI/GUI_AuxiliaryList.hpp b/src/slic3r/GUI/GUI_AuxiliaryList.hpp index 8604259371..88bab94a3d 100644 --- a/src/slic3r/GUI/GUI_AuxiliaryList.hpp +++ b/src/slic3r/GUI/GUI_AuxiliaryList.hpp @@ -6,10 +6,14 @@ #include #include +#include #include +#include #include #include #include +#include +#include #include "AuxiliaryDataViewModel.hpp" diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index e2226b3d3e..38633dc86a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp index fbca655a24..949abfcb13 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp @@ -15,6 +15,7 @@ #include "I18N.hpp" #include "ConfigManipulation.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.hpp b/src/slic3r/GUI/GUI_ObjectTableSettings.hpp index 24e3d427a9..490df76a75 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.hpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.hpp @@ -1,15 +1,21 @@ #ifndef slic3r_GUI_ObjectTableSettings_hpp_ #define slic3r_GUI_ObjectTableSettings_hpp_ +#include #include +#include #include +#include #include +#include #include "wxExtensions.hpp" +#include "libslic3r/PrintConfig.hpp" class wxBoxSizer; namespace Slic3r { class DynamicPrintConfig; +class ModelObject; class ModelConfig; namespace GUI { class ConfigOptionsGroup; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp index 7f52b2cc0c..944cfaad7a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBrimEars.cpp @@ -85,7 +85,6 @@ bool GLGizmoBrimEars::on_init() m_shortcut = Shortcut::GizmoBrimEars; const wxString ctrl = GUI::shortkey_ctrl_prefix(); - const wxString alt = GUI::shortkey_alt_prefix(); m_desc["brim_ear_radius"] = _L("Brim ear radius"); m_desc["max_angle"] = _L("Max angle"); @@ -96,13 +95,11 @@ bool GLGizmoBrimEars::on_init() m_desc["create"] = _L("Create"); m_desc["auto_generate"] = _L("Auto-generate"); m_desc["auto-generate-tooltip"] = _L("Generate brim ears using Max angle and Detection radius"); - m_desc["section_view"] = _L("Section view"); m_shortcuts = { {_L("Left mouse button"), _L("Add or Select")}, {_L("Right mouse button"), _L("Remove")}, {ctrl + _L("Mouse wheel"), m_desc["brim_ear_radius"]}, - {alt + _L("Mouse wheel"), m_desc["section_view"]}, }; return true; @@ -551,26 +548,6 @@ bool GLGizmoBrimEars::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_p apply_radius_change(); } - if (action == SLAGizmoEventType::MouseWheelUp && alt_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position_by_ratio(pos, false, true); - return true; - } - - if (action == SLAGizmoEventType::MouseWheelDown && alt_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::max(0., pos - 0.01); - m_c->object_clipper()->set_position_by_ratio(pos, false, true); - return true; - } - - // reset clipper position - if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position_by_ratio(-1., false); - return true; - } - return false; } @@ -692,8 +669,8 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); float space_size = m_imgui->get_style_scaling() * 8; - std::vector text_list = {m_desc["brim_ear_radius"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["clipping_of_view"], - m_desc["create"], m_desc["remove"]}; + std::vector text_list = {m_desc["brim_ear_radius"], m_desc["max_angle"], m_desc["detection_radius"], m_desc["create"], + m_desc["remove"]}; float widest_text = m_imgui->find_widest_text(text_list); float caption_size = widest_text + space_size + ImGui::GetStyle().WindowPadding.x; float input_text_size = m_imgui->scaled(10.0f); @@ -782,21 +759,6 @@ void GLGizmoBrimEars::on_render_input_window(float x, float y, float bottom_limi } } m_imgui->disabled_end(); - - ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - float clp_dist = float(m_c->object_clipper()->get_position()); - m_imgui->text(m_desc["section_view"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(slider_width); - bool slider_clp_dist = m_imgui->bbl_slider_float_style("##section_view", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - ImGui::SameLine(drag_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - bool b_clp_dist_input = ImGui::BBLDragFloat("##section_view_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, false, true); - } ImGui::Separator(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index ebd0821ded..69999155af 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -32,6 +32,7 @@ #include "slic3r/GUI/3DScene.hpp" #include "libslic3r/Config.hpp" #include "libslic3r/Line.hpp" +#include #include #include "libslic3r/TriangleMesh.hpp" #include "slic3r/GUI/MeshUtils.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 5bf94c7d77..38aeb26bdf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -75,6 +75,7 @@ #include #include "slic3r/GUI/Jobs/Worker.hpp" #include +#include #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6a6288a71c..7ed567ac33 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -112,36 +112,30 @@ bool GLGizmoFdmSupports::on_init() m_desc["highlight_by_angle"] = _L("Highlight overhangs"); m_desc["tool_type"] = _L("Tool type"); m_desc["gap_fill"] = _L("Gap fill"); - m_desc["reset_direction"] = _L("Reset direction"); - m_desc["clipping_of_view"] = _L("Section view"); m_desc["cursor_size"] = _L("Brush size"); m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["gap_area"] = _L("Gap area"); const wxString ctrl = GUI::shortkey_ctrl_prefix(); - const wxString alt = GUI::shortkey_alt_prefix(); const wxString shift = GUI::shortkey_shift_prefix(); std::pair enforce_shortcut = {_L("Left mouse button"), _L("Enforce supports")}; std::pair block_shortcut = {_L("Right mouse button"), _L("Block supports")}; std::pair remove_shortcut = {shift + _L("Left mouse button"), _L("Erase")}; - std::pair clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]}; m_shortcuts_brush = { enforce_shortcut, block_shortcut, remove_shortcut, - {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]}, - clipping_shortcut + {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]} }; m_shortcuts_bucket_fill = { enforce_shortcut, block_shortcut, remove_shortcut, - {ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]}, - clipping_shortcut + {ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]} }; m_shortcuts_gap_fill = { @@ -237,11 +231,9 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float gap_fill_slider_left = m_imgui->calc_text_size(m_desc.at("gap_fill")).x + m_imgui->scaled(1.5f); const float highlight_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.5f); - const float reset_button_slider_left = m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2; const float on_overhangs_only_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(1.5f); const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.5f); const float gap_area_txt_width = m_imgui->calc_text_size(m_desc.at("gap_area")).x + m_imgui->scaled(1.5f); @@ -254,14 +246,14 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l float caption_max = 0.f; float total_text_max = 0.f; - for (const auto &t : std::array{"enforce", "block", "remove", "cursor_size", "clipping_of_view"}) { + for (const auto &t : std::array{"enforce", "block", "remove", "cursor_size"}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float sliders_left_width = std::max(gap_area_txt_width, std::max(smart_fill_angle_txt_width, std::max(reset_button_slider_left, std::max(std::max(cursor_slider_left, clipping_slider_left), std::max(highlight_slider_left, gap_fill_slider_left))))); + const float sliders_left_width = std::max(gap_area_txt_width, std::max(smart_fill_angle_txt_width, std::max(cursor_slider_left, std::max(highlight_slider_left, gap_fill_slider_left)))); const float slider_icon_width = m_imgui->get_slider_icon_size().x; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; @@ -458,29 +450,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##angle_threshold_deg_input", &m_highlight_by_angle_threshold_deg, 0.05f, 0.0f, 0.0f, "%.2f"); - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); - } - } - auto clp_dist = float(m_c->object_clipper()->get_position()); - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(sliders_width); - bool b_bbl_slider_float = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - - ImGui::SameLine(drag_left_width + sliders_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - bool b_drag_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - - if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - ImGui::Separator(); render_tooltip_button(x, y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp index 7f36e85e80..e03912456a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFuzzySkin.cpp @@ -51,10 +51,8 @@ bool GLGizmoFuzzySkin::on_init() m_shortcut = Shortcut::GizmoFuzzySkin; const wxString ctrl = GUI::shortkey_ctrl_prefix(); - const wxString alt = GUI::shortkey_alt_prefix(); const wxString shift = GUI::shortkey_shift_prefix(); - m_desc["reset_direction"] = _L("Reset direction"); m_desc["remove_all"] = _L("Erase all"); m_desc["circle"] = _L("Circle"); m_desc["sphere"] = _L("Sphere"); @@ -62,7 +60,6 @@ bool GLGizmoFuzzySkin::on_init() m_desc["tool_type"] = _L("Tool type"); m_desc["tool_brush"] = _L("Brush"); m_desc["tool_smart_fill"] = _L("Smart fill"); - m_desc["clipping_of_view"] = _L("Section view"); m_desc["cursor_size"] = _L("Brush size"); m_desc["add_fuzzy_skin"] = _L("Add fuzzy skin"); m_desc["remove_fuzzy_skin"] = _L("Remove fuzzy skin"); @@ -70,26 +67,22 @@ bool GLGizmoFuzzySkin::on_init() std::pair add_fuzzy_skin_shortcut = {_L("Left mouse button"), m_desc["add_fuzzy_skin"]}; std::pair remove_fuzzy_skin_shortcut = {shift + _L("Left mouse button"), m_desc["remove_fuzzy_skin"]}; - std::pair clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]}; m_shortcuts_brush = { add_fuzzy_skin_shortcut, remove_fuzzy_skin_shortcut, - {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]}, - clipping_shortcut + {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]} }; m_shortcuts_triangle = { add_fuzzy_skin_shortcut, - remove_fuzzy_skin_shortcut, - clipping_shortcut + remove_fuzzy_skin_shortcut }; m_shortcuts_smart_fill = { add_fuzzy_skin_shortcut, remove_fuzzy_skin_shortcut, - {ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]}, - clipping_shortcut + {ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]} }; return true; @@ -162,8 +155,6 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); @@ -187,9 +178,7 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float circle_max_width = std::max(clipping_slider_left, cursor_slider_left); - - const float sliders_left_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left)); + const float sliders_left_width = std::max(smart_fill_slider_left, cursor_slider_left); const float slider_icon_width = m_imgui->get_slider_icon_size().x; float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; const float empty_button_width = m_imgui->calc_button_size("").x; @@ -259,10 +248,10 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(circle_max_width); + ImGui::SameLine(cursor_slider_left); ImGui::PushItemWidth(sliders_width); m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true); - ImGui::SameLine(drag_left_width + circle_max_width); + ImGui::SameLine(drag_left_width + cursor_slider_left); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f"); } else if (m_current_tool == ImGui::TriangleButtonIcon) { @@ -291,30 +280,6 @@ void GLGizmoFuzzySkin::on_render_input_window(float x, float y, float bottom_lim ImGui::BBLDragFloat("##smart_fill_angle_input", &m_smart_fill_angle, 0.05f, 0.0f, 0.0f, "%.2f"); } - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); - } - } - - auto clp_dist = float(m_c->object_clipper()->get_position()); - ImGui::SameLine(sliders_left_width); - - ImGui::PushItemWidth(sliders_width); - bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - - ImGui::SameLine(drag_left_width + sliders_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } - ImGui::Separator(); render_tooltip_button(x, y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 2a19cf3ee7..a08ded3003 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -118,8 +118,6 @@ bool GLGizmoMmuSegmentation::on_init() const wxString alt = GUI::shortkey_alt_prefix(); const wxString shift = GUI::shortkey_shift_prefix(); - m_desc["clipping_of_view"] = _L("Section view"); - m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Brush size"); m_desc["cursor_type"] = _L("Brush shape"); m_desc["paint"] = _L("Paint"); @@ -146,14 +144,12 @@ bool GLGizmoMmuSegmentation::on_init() std::pair paint_shortcut = {_L("Left mouse button"), m_desc["paint"]}; std::pair erase_shortcut = {shift + _L("Left mouse button"), m_desc["erase"]}; - std::pair clipping_shortcut = {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]}; std::pair toggle_wireframe_shortcut = {alt + shift + _L_CONTEXT("Enter", "Keyboard Shortcut"), m_desc["toggle_wireframe"]}; m_shortcuts_brush = { paint_shortcut, erase_shortcut, {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]}, - clipping_shortcut, toggle_wireframe_shortcut }; @@ -161,7 +157,6 @@ bool GLGizmoMmuSegmentation::on_init() paint_shortcut, erase_shortcut, {ctrl + _L("Mouse wheel"), m_desc["smart_fill_angle"]}, - clipping_shortcut, toggle_wireframe_shortcut }; @@ -397,8 +392,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); @@ -413,18 +406,15 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott float caption_max = 0.f; float total_text_max = 0.f; - for (const auto &t : std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range", "clipping_of_view"}) { + for (const auto &t : std::array{"paint", "erase", "cursor_size", "smart_fill_angle", "height_range"}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float circle_max_width = std::max(clipping_slider_left,cursor_slider_left); - const float height_max_width = std::max(clipping_slider_left,height_range_slider_left); const float sliders_left_width = std::max(smart_fill_slider_left, - std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(gap_area_slider_left, std::max(height_range_slider_left, - clipping_slider_left))))) + space_size; + std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(gap_area_slider_left, height_range_slider_left)))) + space_size; const float slider_icon_width = m_imgui->get_slider_icon_size().x; float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; const int max_filament_items_per_line = 8; @@ -658,28 +648,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott } } - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this]() { m_c->object_clipper()->set_position_by_ratio(-1., false); }); - } - } - - auto clp_dist = float(m_c->object_clipper()->get_position()); - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(sliders_width); - bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - ImGui::SameLine(drag_left_width + sliders_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - - if (slider_clp_dist || b_clp_dist_input) { - m_c->object_clipper()->set_position_by_ratio(clp_dist, true); - } - ImGui::Separator(); render_tooltip_button(x, y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index bed2c42267..87ffbb762f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -25,6 +25,7 @@ #include "libslic3r/Geometry.hpp" #include #include "libslic3r/Model.hpp" +#include #include namespace Slic3r { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index c9847afcde..75d2905a86 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -750,20 +750,6 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; } } - else if (alt_down) { - // BBS - double pos = m_c->object_clipper()->get_position(); - pos = action == SLAGizmoEventType::MouseWheelDown - ? std::max(0., pos - 0.01) - : std::min(1., pos + 0.01); - m_c->object_clipper()->set_position_by_ratio(pos, true); - return true; - } - } - - if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position_by_ratio(-1., false); - return true; } if (action == SLAGizmoEventType::LeftDown diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index a223749b6c..56c0944da9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -24,6 +24,7 @@ #include "slic3r/GUI/GLShader.hpp" #include #include "libslic3r/Geometry.hpp" +#include #include namespace Slic3r { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 3ae5604226..1d6d31a047 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -46,11 +46,8 @@ bool GLGizmoSeam::on_init() m_shortcut = Shortcut::GizmoSeam; const wxString ctrl = GUI::shortkey_ctrl_prefix(); - const wxString alt = GUI::shortkey_alt_prefix(); const wxString shift = GUI::shortkey_shift_prefix(); - m_desc["clipping_of_view"] = _L("Section view"); - m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Brush size"); m_desc["tool_type"] = _L("Tool type"); m_desc["enforce"] = _L("Enforce seam"); @@ -64,8 +61,7 @@ bool GLGizmoSeam::on_init() {_L("Left mouse button"), m_desc["enforce"]}, {_L("Right mouse button"), m_desc["block"]}, {shift + _L("Left mouse button"), m_desc["remove"]}, - {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]}, - {alt + _L("Mouse wheel"), m_desc["clipping_of_view"]} + {ctrl + _L("Mouse wheel"), m_desc["cursor_size"]} }; return true; @@ -155,20 +151,17 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, - m_imgui->calc_text_size(m_desc.at("reset_direction")).x + ImGui::GetStyle().FramePadding.x * 2) - + m_imgui->scaled(1.5f); const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float empty_button_width = m_imgui->calc_button_size("").x; float caption_max = 0.f; float total_text_max = 0.f; - for (const auto &t : std::array{"enforce", "block", "remove", "cursor_size", "clipping_of_view"}) { + for (const auto &t : std::array{"enforce", "block", "remove", "cursor_size"}) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } - const float sliders_left_width = std::max(cursor_size_slider_left, clipping_slider_left); + const float sliders_left_width = cursor_size_slider_left; const float slider_icon_width = m_imgui->get_slider_icon_size().x; const float sliders_width = m_imgui->scaled(7.0f); @@ -242,28 +235,6 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only); - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position_by_ratio(-1., false); - }); - } - } - - auto clp_dist = float(m_c->object_clipper()->get_position()); - ImGui::SameLine(sliders_left_width); - ImGui::PushItemWidth(sliders_width); - bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); - ImGui::SameLine(drag_left_width + sliders_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); - if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); } - ImGui::Separator(); GLGizmoUtils::render_tooltip_button(m_imgui, m_parent, m_shortcuts, x, y); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp index 3577ba8b3b..96b1458122 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp @@ -5153,7 +5153,7 @@ void GLGizmoTextureDisplacement::render_debug_stage_panel(ModelVolume *mv) m_imgui->scaled(20.f)); ImGui::SameLine(); - ImGui::Checkbox(_u8L("Check topology").c_str(), &m_debug_check_topology); + m_imgui->bbl_checkbox(_L("Check topology"), m_debug_check_topology); if (ImGui::IsItemHovered()) m_imgui->tooltip(_u8L("Count open and non-manifold edges after each stage, which is how a stage " "that tore the mesh is spotted. It scans every edge, so it adds noticeably " @@ -5343,6 +5343,8 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float GizmoImguiBegin(get_name(), flags); ensure_panel_icons(); process_uv_commands(); // clicks from the UV editor pane, run here where the GL context is current + const float previous_body_h = m_panel_body_h; + const float previous_footer_h = m_panel_footer_h; // Pinned every frame while Standard is active, so what Preview shows is always what Bake will do. if (!pro_mode() && apply_standard_mode_presets(mv)) @@ -5364,20 +5366,16 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float const float card_pad = std::round(m_imgui->scaled(0.55f)); const float wrap_w = m_imgui->scaled(20.f); const ImVec4 orca = ImGuiWrapper::COL_ORCA; - const ImVec4 col_link = dark ? ImVec4(0.30f, 0.71f, 0.67f, 1.f) : ImVec4(0.f, 0.47f, 0.42f, 1.f); - const ImVec4 col_frame = dark ? ImVec4(0.212f, 0.212f, 0.235f, 1.f) : ImVec4(0.808f, 0.808f, 0.808f, 1.f); - const ImU32 col_card = dark ? IM_COL32(255, 255, 255, 10) : IM_COL32(0, 0, 0, 12); - const ImU32 col_line = dark ? IM_COL32(255, 255, 255, 18) : IM_COL32(0, 0, 0, 23); + const ImVec4 col_link = ImGuiWrapper::COL_ORCA; + const ImVec4 col_frame = ImGui::GetStyleColorVec4(ImGuiCol_Separator); + const ImU32 col_card = ImGui::GetColorU32(ImGuiCol_Text, dark ? 0.045f : 0.047f); + const ImU32 col_line = ImGui::GetColorU32(ImGuiCol_Text, dark ? 0.08f : 0.09f); const ImU32 col_sep = ImGui::GetColorU32(ImGuiCol_Separator); - // Combo drop-downs otherwise inherit ImGui's near-black default popup background; under the light - // theme that leaves the dark item text unreadable ("the dropbox is black"). Pushed only around each - // Combo below (never around a tooltip, whose own near-black default is what makes it readable). - const ImVec4 combo_popup_bg = dark ? ImVec4(0.18f, 0.18f, 0.19f, 1.f) : ImVec4(0.93f, 0.93f, 0.93f, 1.f); const auto scoped_combo = [&](const char *id, int *v, const char *const items[], int n) { - ImGui::PushStyleColor(ImGuiCol_PopupBg, combo_popup_bg); + ImGuiWrapper::push_combo_style(m_parent.get_scale()); const bool changed = ImGui::Combo(id, v, items, n); - ImGui::PopStyleColor(); + ImGuiWrapper::pop_combo_style(); return changed; }; const auto hover_tip = [&](const auto &text) { @@ -5796,10 +5794,10 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float wf_toggle = true; const std::string auto_label = _u8L("Auto"); - const float auto_w = frame_h + style.ItemInnerSpacing.x + ImGui::CalcTextSize(auto_label.c_str()).x; + const float auto_w = frame_h * 0.78f /*ratio from BBLCheckbox*/ + style.ItemInnerSpacing.x + ImGui::CalcTextSize(auto_label.c_str()).x; ImGui::SameLine(); ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(), ImGui::GetWindowContentRegionMax().x - auto_w)); - if (ImGui::Checkbox((auto_label + "##auto_update").c_str(), &m_auto_update) && m_auto_update) + if (m_imgui->bbl_checkbox(wxString::FromUTF8(auto_label) + "##auto_update", m_auto_update) && m_auto_update) rebuild_preview(); // catch up anything that changed while it was off hover_tip(_u8L("Rebuilds the preview as soon as anything changes. Turn it off on a heavy model if painting " "or dragging a slider starts to stutter - the preview then waits until you let go.")); @@ -6034,7 +6032,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float "costs fine detail.")); // Edge fade: the relief flattens toward the boundary of the painted area. - m_preview_params_dirty |= ImGui::Checkbox((_u8L("Edge fade") + "##edge_smoothing").c_str(), &layer.edge_smoothing); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Edge fade") + "##edge_smoothing", layer.edge_smoothing); hover_tip(_u8L("Flattens the relief as it approaches the edge of the painted area, so it " "blends into the bare surface instead of stopping at a step.")); ImGui::SameLine(); @@ -6049,7 +6047,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float // Invert and Colours share a row. { const float x0 = ImGui::GetCursorPosX(); - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Invert").c_str(), &layer.invert); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Invert"), layer.invert); hover_tip(_u8L("Turns the relief inside out: what stood out is cut in, and the other way " "round. The same as using a negative of the image.")); ImGui::SameLine(); @@ -6061,7 +6059,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float const bool has_color = decode_height_texture(layer).has_color(); bool color_enabled = layer.color_enabled && has_color; m_imgui->disabled_begin(!has_color); - if (ImGui::Checkbox(_u8L("Colours").c_str(), &color_enabled)) { + if (m_imgui->bbl_checkbox(_L("Colours"), color_enabled)) { layer.color_enabled = color_enabled; m_preview_params_dirty = true; } @@ -6079,7 +6077,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float // under whichever layer turned colour on. if (color_enabled) { TextureDisplacementOptions &opts = mv->texture_displacement_options; - if (ImGui::Checkbox(_u8L("Mix filaments").c_str(), &opts.color_mix_enabled)) + if (m_imgui->bbl_checkbox(_L("Mix filaments"), opts.color_mix_enabled)) m_preview_params_dirty = true; hover_tip(_u8L("Interleaves two filaments to fake the colours in between, so a handful " "of filaments can cover a photo or a gradient. An image of flat colours " @@ -6198,7 +6196,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float "a slide projector. Faces turned away from you stretch, so line the view up with " "the surface you care about first.")); - if (ImGui::Checkbox(_u8L("Project only on visible").c_str(), &m_project_only_visible)) { + if (m_imgui->bbl_checkbox(_L("Project only on visible"), m_project_only_visible)) { if (m_project_only_visible && select_visible_faces() == 0) show_error(nullptr, _u8L("Nothing is visible from this angle - turn the model to face the " "part you want to project onto.")); @@ -6209,7 +6207,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float "behind anything - and projects onto those. Replaces what the layer had painted.")); bool projector_open = m_projector_frame != nullptr && m_projector_frame->IsShown(); - if (ImGui::Checkbox(_u8L("Projection frame").c_str(), &projector_open)) + if (m_imgui->bbl_checkbox(_L("Projection frame"), projector_open)) show_projector(projector_open); hover_tip(_u8L("Opens a window you drag over the model. Whatever you can see through it is what " "gets the texture, and its border becomes the edge of the projection.")); @@ -6250,7 +6248,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float // Tile, and how it repeats. { const float x0 = ImGui::GetCursorPosX(); - m_preview_params_dirty |= ImGui::Checkbox((_u8L("Tile") + "##tile_enabled").c_str(), &layer.tile_enabled); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Tile") + "##tile_enabled", layer.tile_enabled); hover_tip(_u8L("Repeats the texture across the painted area. Off places one copy, like a decal, " "at the size set by Tile size.")); ImGui::SameLine(); @@ -6438,7 +6436,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float const ImVec2 mn(mouse.x - inner - 0.5f * grip_w, mouse.y - 0.5f * row_h); const ImVec2 mx(mn.x + (content_rx - list_x), mn.y + row_h); fg->AddRectFilled(ImVec2(mn.x + 2.f, mn.y + 4.f), ImVec2(mx.x + 2.f, mx.y + 4.f), IM_COL32(0, 0, 0, 70), rounding); - fg->AddRectFilled(mn, mx, dark ? IM_COL32(0x3a, 0x3a, 0x40, 245) : IM_COL32(255, 255, 255, 245), rounding); + fg->AddRectFilled(mn, mx, ImGui::GetColorU32(ImGuiCol_WindowBg, 245.f / 255.f), rounding); fg->AddRect(mn, mx, ImGui::GetColorU32(orca), rounding, 0, 1.5f); float x = mn.x + inner; @@ -6477,7 +6475,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float ImGui::Separator(); heading(_L("Subdivision")); - if (ImGui::Checkbox(_u8L("Only painted area (adaptive)").c_str(), &m_subdivide_adaptive)) { + if (m_imgui->bbl_checkbox(_L("Only painted area (adaptive)"), m_subdivide_adaptive)) { if (m_subdivide_editing) rebuild_subdivide_preview(); // switch the wireframe between the uniform and adaptive result m_parent.set_as_dirty(); @@ -6508,7 +6506,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float m_parent.set_as_dirty(); }; - if (ImGui::Checkbox(_u8L("Follow texture detail").c_str(), &m_subdivide_feature)) + if (m_imgui->bbl_checkbox(_L("Follow texture detail"), m_subdivide_feature)) preview_live(); hover_tip(_u8L("Spends the triangles where the texture actually bends - packed along ridges and edges, " "sparse over flat ground - instead of spreading them evenly. The same detail for fewer " @@ -6635,7 +6633,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float hover_tip(_u8L("Triangle size the whole model is rebuilt with, in millimetres. Displacement works best on an " "even mesh; this is what makes one out of an uneven import.")); - ImGui::Checkbox((_u8L("Keep sharp edges") + "##remesh_sharp").c_str(), &m_remesh_keep_sharp_edges); + m_imgui->bbl_checkbox(_L("Keep sharp edges") + "##remesh_sharp", m_remesh_keep_sharp_edges); hover_tip(_u8L("Holds hard edges and open borders in place while the rest is remeshed. Without it " "the remesher slides vertices along the surface and rounds every crisp edge off - " "a cube comes back with wobbly edges.")); @@ -6662,12 +6660,12 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float ImGui::Separator(); heading(_L("Result")); - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Displace up to the border").c_str(), &opts.displace_border); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Displace up to the border"), opts.displace_border); hover_tip(_u8L("Lets the relief run right to the edge of the painted area. Turn it off to hold that " "outer ring flat, which keeps the displacement strictly inside your paint but flattens " "the pattern at the border.")); - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Smooth result").c_str(), &opts.smooth_enabled); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Smooth result"), opts.smooth_enabled); hover_tip(_u8L("Smooths the geometry after the texture has been applied, to take the hard steps out of a " "low-resolution image. Only what the displacement moved is touched. The Smoothing slider " "on a layer is a different thing: it blurs the image before it is used.")); @@ -6684,7 +6682,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float hover_tip(_u8L("How many smoothing passes to run. More passes spread the smoothing further across " "the surface; Strength decides how much each one moves.")); - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Ignore outer ring").c_str(), &opts.smooth_skip_border); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Ignore outer ring"), opts.smooth_skip_border); hover_tip(_u8L("Keeps the outer ring of the painted area out of the smoothing. Its neighbours " "outside the paint never move, so smoothing it drags the relief down and leaves the " "pattern half-melted at the border.")); @@ -6709,7 +6707,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float // The classic path is the opt-in: the one-run pipeline is the default, and its resolution // control lives in the footer next to Bake (see below). bool classic = !opts.pipeline_v2; - if (ImGui::Checkbox(_u8L("Experimental: classic bake pipeline").c_str(), &classic)) { + if (m_imgui->bbl_checkbox(_L("Experimental: classic bake pipeline"), classic)) { opts.pipeline_v2 = !classic; m_preview_params_dirty = true; } @@ -6738,13 +6736,13 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float if (SHOW_PIPELINE_DEV_CONTROLS && opts.pipeline_v2) { // Keeping the relief above the plate is not a checkbox: it is unconditional, in both pipelines // (see build_texture_displacement()). - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Align mesh to texture edges").c_str(), &opts.v2_relocate); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Align mesh to texture edges"), opts.v2_relocate); hover_tip(_u8L("Slide vertices sideways onto the edges in the texture before displacing them. " "Displacement can only move vertices up and down, so without this a sharp step " "in the image lands wherever the triangles happen to be and comes out as a " "staircase. Moving the vertices onto the step first gives a straight wall at the " "same triangle count.")); - m_preview_params_dirty |= ImGui::Checkbox(_u8L("Clean up slivers").c_str(), &opts.v2_regularize); + m_preview_params_dirty |= m_imgui->bbl_checkbox(_L("Clean up slivers"), opts.v2_regularize); hover_tip(_u8L("Collapse the thin triangles refinement inherits from the model's own " "tessellation, before displacement samples them. A sliver's three corners " "land on three unrelated parts of the texture, which is what makes the " @@ -6824,7 +6822,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float // a fixed value, seeded with the recommendation so it starts from something sensible. bool auto_res = opts.v2_refine_mm <= 0.f; m_imgui->disabled_begin(busy); - if (ImGui::Checkbox("##v2auto", &auto_res)) { + if (m_imgui->bbl_checkbox(wxString::FromUTF8("##v2auto"), auto_res)) { if (auto_res) { opts.v2_refine_mm = 0.f; opts.v2_max_triangles_k = -1; @@ -6922,11 +6920,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float const std::string bake_label = m_prepare_in_progress ? _u8L("Preparing...") : m_bake_in_progress ? _u8L("Baking...") : into_u8(m_desc.at("bake")); - ImGui::PushStyleColor(ImGuiCol_Button, orca); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiWrapper::COL_ORCA_HOVER); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, orca); - ImGui::PushStyleColor(ImGuiCol_Border, orca); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); + GLGizmoUtils::push_orca_button_style(); m_imgui->push_bold_font(); m_imgui->disabled_begin(!can_bake); if (ImGui::Button((bake_label + "##bake").c_str(), ImVec2(x0 + panel_w - ImGui::GetCursorPosX(), button_h))) { @@ -6939,7 +6933,7 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float } m_imgui->disabled_end(); m_imgui->pop_bold_font(); - ImGui::PopStyleColor(5); + GLGizmoUtils::pop_orca_button_style(); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) m_imgui->tooltip(mv != nullptr && !mv->is_texture_displacement_painted() ? (m_seam_edit_mode ? _u8L("Nothing is painted yet. The UV editor's seam tool is on, so " @@ -6978,7 +6972,17 @@ void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float } } m_panel_footer_h = ImGui::GetCursorScreenPos().y - footer_top; - + constexpr float resize_epsilon = 0.5f; + const float content_bottom = ImGui::GetCursorPosY() - style.ItemSpacing.y; + const float window_bottom = ImGui::GetWindowContentRegionMax().y; + const bool outer_window_needs_fit = content_bottom < window_bottom - resize_epsilon || + (content_bottom > window_bottom + resize_epsilon && + ImGui::GetWindowHeight() < ImGui::GetMainViewport()->Size.y - + 2.f * style.DisplaySafeAreaPadding.y - resize_epsilon); + if (std::abs(m_panel_body_h - previous_body_h) > resize_epsilon || + std::abs(m_panel_footer_h - previous_footer_h) > resize_epsilon || outer_window_needs_fit) { + m_parent.request_extra_frame(); + } GizmoImguiEnd(); ImGuiWrapper::pop_toolbar_style(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 18308b81b2..9d684cdb88 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -380,22 +380,19 @@ std::vector ObjectClipper::point_per_contour() const } -void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal, bool vertical_normal) +void ObjectClipper::set_position_by_ratio(double pos, const Vec3d& normal) { const ModelObject* mo = get_pool()->selection_info()->model_object(); int active_inst = get_pool()->selection_info()->get_active_instance(); double z_shift = get_pool()->selection_info()->get_sla_shift(); - - Vec3d normal; - if(vertical_normal) { - normal = {0, 0, 1}; - }else { - //Vec3d camera_dir = wxGetApp().plater()->get_camera().get_dir_forward(); - //if (abs(camera_dir(0)) > EPSILON || abs(camera_dir(1)) > EPSILON) - // camera_dir(2) = 0; - - normal = (keep_normal && m_clp) ? m_clp->get_normal() : /*-camera_dir;*/ -wxGetApp().plater()->get_camera().get_dir_forward(); + if (pos == 0. || mo == nullptr || active_inst < 0) { + // No plane, so the raycasts are not clipped. + m_clp_ratio = 0.; + m_clp.reset(); + get_pool()->get_canvas()->set_as_dirty(); + return; } + Vec3d center; if (get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) { @@ -410,9 +407,6 @@ void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal, bool ver float dist = normal.dot(center); - if (pos < 0.) - pos = m_clp_ratio; - m_clp_ratio = pos; m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2 * m_active_inst_bb_radius))); @@ -445,171 +439,5 @@ void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contou } -using namespace AssembleViewDataObjects; -AssembleViewDataPool::AssembleViewDataPool(GLCanvas3D* canvas) - : m_canvas(canvas) -{ - using c = AssembleViewDataID; - m_data[c::ModelObjectsInfo].reset(new ModelObjectsInfo(this)); - m_data[c::ModelObjectsClipper].reset(new ModelObjectsClipper(this)); -} - -void AssembleViewDataPool::update(AssembleViewDataID required) -{ - assert(check_dependencies(required)); - for (auto& [id, data] : m_data) { - if (int(required) & int(AssembleViewDataID(id))) - data->update(); - else - if (data->is_valid()) - data->release(); - } -} - - -ModelObjectsInfo* AssembleViewDataPool::model_objects_info() const -{ - ModelObjectsInfo* sel_info = dynamic_cast(m_data.at(AssembleViewDataID::ModelObjectsInfo).get()); - assert(sel_info); - return sel_info->is_valid() ? sel_info : nullptr; -} - - -ModelObjectsClipper* AssembleViewDataPool::model_objects_clipper() const -{ - ModelObjectsClipper* oc = dynamic_cast(m_data.at(AssembleViewDataID::ModelObjectsClipper).get()); - // ObjectClipper is used from outside the gizmos to report current clipping plane. - // This function can be called when oc is nullptr. - return (oc && oc->is_valid()) ? oc : nullptr; -} - -#ifndef NDEBUG -// Check the required resources one by one and return true if all -// dependencies are met. -bool AssembleViewDataPool::check_dependencies(AssembleViewDataID required) const -{ - // This should iterate over currently required data. Each of them should - // be asked about its dependencies and it must check that all dependencies - // are also in required and before the current one. - for (auto& [id, data] : m_data) { - // in case we don't use this, the deps are irrelevant - if (!(int(required) & int(AssembleViewDataID(id)))) - continue; - - - AssembleViewDataID deps = data->get_dependencies(); - assert(int(deps) == (int(deps) & int(required))); - } - - -return true; -} -#endif // NDEBUG - - - - -void ModelObjectsInfo::on_update() -{ - if (!get_pool()->get_canvas()->get_model()->objects.empty()) { - m_model_objects = get_pool()->get_canvas()->get_model()->objects; - } - else { - m_model_objects.clear(); - } -} - -void ModelObjectsInfo::on_release() -{ - m_model_objects.clear(); -} - -//int ModelObjectsInfo::get_active_instance() const -//{ -// const Selection& selection = get_pool()->get_canvas()->get_selection(); -// return selection.get_instance_idx(); -//} - - -void ModelObjectsClipper::on_update() -{ - const ModelObjectPtrs model_objects = get_pool()->model_objects_info()->model_objects(); - if (model_objects.empty()) - return; - - // which mesh should be cut? - std::vector meshes; - - if (meshes.empty()) - for (auto mo : model_objects) { - for (const ModelVolume* mv : mo->volumes) - meshes.push_back(&mv->mesh()); - } - - if (meshes != m_old_meshes) { - m_clippers.clear(); - for (const TriangleMesh* mesh : meshes) { - m_clippers.emplace_back(new MeshClipper); - m_clippers.back()->set_mesh(mesh->its); - } - m_old_meshes = meshes; - - m_active_inst_bb_radius = get_pool()->get_canvas()->volumes_bounding_box().radius(); - } -} - - -void ModelObjectsClipper::on_release() -{ - m_clippers.clear(); - m_old_meshes.clear(); - m_clp.reset(); - m_clp_ratio = 0.; - -} - -void ModelObjectsClipper::render_cut() const -{ - if (m_clp_ratio == 0.) - return; - const ModelObjectPtrs model_objects = get_pool()->model_objects_info()->model_objects(); - - size_t clipper_id = 0; - for (const ModelObject* mo : model_objects) { - Geometry::Transformation assemble_objects_trafo = mo->instances[0]->get_assemble_transformation(); - auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly(); - for (const ModelVolume* mv : mo->volumes) { - Geometry::Transformation vol_trafo = mv->get_transformation(); - Geometry::Transformation trafo = assemble_objects_trafo * vol_trafo; - trafo.set_offset(trafo.get_offset() + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0) + offset_to_assembly * (GLVolume::explosion_ratio - 1.0)); - - auto& clipper = m_clippers[clipper_id]; - clipper->set_plane(*m_clp); - clipper->set_transformation(trafo); - // BBS - clipper->render_cut({0.25f, 0.25f, 0.25f, 1.0f}); - - ++clipper_id; - } - } -} - - -void ModelObjectsClipper::set_position(double pos, bool keep_normal) -{ - Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward(); - const Vec3d& center = get_pool()->get_canvas()->volumes_bounding_box().center(); - float dist = normal.dot(center); - - if (pos < 0.) - pos = m_clp_ratio; - - m_clp_ratio = pos; - m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius * GLVolume::explosion_ratio) - m_clp_ratio * 2 * m_active_inst_bb_radius * GLVolume::explosion_ratio))); - get_pool()->get_canvas()->set_as_dirty(); - -} - - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index d2eeda4f64..f89914e445 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -52,7 +52,6 @@ enum class SLAGizmoEventType : unsigned char { class CommonGizmosDataBase; -class AssembleViewDataBase; namespace CommonGizmosDataObjects { class SelectionInfo; class InstancesHider; @@ -62,11 +61,6 @@ namespace CommonGizmosDataObjects { class SupportsClipper; } -namespace AssembleViewDataObjects { - class ModelObjectsInfo; - class ModelObjectsClipper; -} - // Some of the gizmos use the same data that need to be updated ocassionally. // It is also desirable that the data are not recalculated when the gizmos // are just switched, but on the other hand, they should be released when @@ -245,7 +239,7 @@ public: void set_position_to_init_layer(); const ClippingPlane* get_clipping_plane(bool ignore_hide_clipped = false) const; void render_cut(const std::vector* ignore_idxs = nullptr) const; - void set_position_by_ratio(double pos, bool keep_normal, bool vertical_normal=false); + void set_position_by_ratio(double pos, const Vec3d& normal); void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos); void set_behavior(bool hide_clipped, bool fill_cut, double contour_width); @@ -272,121 +266,6 @@ private: } // namespace CommonGizmosDataObjects -enum class AssembleViewDataID { - None = 0, - ModelObjectsInfo = 1 << 0, - ModelObjectsClipper = 1 << 4, -}; - -class AssembleViewDataPool { -public: - AssembleViewDataPool(GLCanvas3D* canvas); - - // Update all resources and release what is not used. - // Accepts a bitmask of currently required resources. - void update(AssembleViewDataID required); - - // Getters for the data that need to be accessed from the gizmos directly. - AssembleViewDataObjects::ModelObjectsInfo* model_objects_info() const; - AssembleViewDataObjects::ModelObjectsClipper* model_objects_clipper() const; - - GLCanvas3D* get_canvas() const { return m_canvas; } - -private: - std::map> m_data; - GLCanvas3D* m_canvas; - -#ifndef NDEBUG - bool check_dependencies(AssembleViewDataID required) const; -#endif -}; - -// Base class for a wrapper object managing a single resource. -// Each of the enum values above (safe None) will have an object of this kind. -class AssembleViewDataBase { -public: - // Pass a backpointer to the pool, so the individual - // objects can communicate with one another. - explicit AssembleViewDataBase(AssembleViewDataPool* cgdp) - : m_common{ cgdp } {} - virtual ~AssembleViewDataBase() {} - - // Update the resource. - void update() { on_update(); m_is_valid = true; } - - // Release any data that are stored internally. - void release() { on_release(); m_is_valid = false; } - - // Returns whether the resource is currently maintained. - bool is_valid() const { return m_is_valid; } - -#ifndef NDEBUG - // Return a bitmask of all resources that this one relies on. - // The dependent resource must have higher ID than the one - // it depends on. - virtual AssembleViewDataID get_dependencies() const { return AssembleViewDataID::None; } -#endif // NDEBUG - -protected: - virtual void on_release() = 0; - virtual void on_update() = 0; - AssembleViewDataPool* get_pool() const { return m_common; } - - -private: - bool m_is_valid = false; - AssembleViewDataPool* m_common = nullptr; -}; - -namespace AssembleViewDataObjects -{ -class ModelObjectsInfo : public AssembleViewDataBase -{ -public: - explicit ModelObjectsInfo(AssembleViewDataPool* cgdp) - : AssembleViewDataBase(cgdp) {} - - ModelObjectPtrs model_objects() const { return m_model_objects; } - //int get_active_instance() const; - float get_sla_shift() const { return m_z_shift; } - -protected: - void on_update() override; - void on_release() override; - -private: - ModelObjectPtrs m_model_objects; - float m_z_shift = 0.f; -}; - -class ModelObjectsClipper : public AssembleViewDataBase -{ -public: - explicit ModelObjectsClipper(AssembleViewDataPool* cgdp) - : AssembleViewDataBase(cgdp) {} -#ifndef NDEBUG - AssembleViewDataID get_dependencies() const override { return AssembleViewDataID::ModelObjectsInfo; } -#endif // NDEBUG - - void set_position(double pos, bool keep_normal); - double get_position() const { return m_clp_ratio; } - ClippingPlane* get_clipping_plane() const { return m_clp.get(); } - void render_cut() const; - - -protected: - void on_update() override; - void on_release() override; - -private: - std::vector m_old_meshes; - std::vector> m_clippers; - std::unique_ptr m_clp; - double m_clp_ratio = 0.; - double m_active_inst_bb_radius = 0.; -}; -} - } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index f9d88b67b8..3eaaf814b6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -278,8 +278,6 @@ bool GLGizmosManager::init() //m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", sprite_id++)); m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); - if(!m_assemble_view_data) - m_assemble_view_data.reset(new AssembleViewDataPool(&m_parent)); for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { @@ -374,7 +372,17 @@ bool GLGizmosManager::init_icon_textures() icon_list.insert(std::make_pair((int) IC_CANVAS_ZOOM_DARK_HOVER, texture_id)); else return false; - + + for (const auto& [icon, name] : std::initializer_list>{ + { IC_CANVAS_SECTION, "canvas_section" }, { IC_CANVAS_SECTION_HOVER, "canvas_section_hover" }, + { IC_CANVAS_SECTION_DARK, "canvas_section_dark" }, { IC_CANVAS_SECTION_DARK_HOVER, "canvas_section_dark_hover" }, + { IC_CANVAS_SECTION_ACTIVE, "canvas_section_active" }, { IC_CANVAS_SECTION_ACTIVE_HOVER, "canvas_section_active_hover" }, + { IC_CANVAS_SECTION_ACTIVE_DARK, "canvas_section_active_dark" }, { IC_CANVAS_SECTION_ACTIVE_DARK_HOVER, "canvas_section_active_dark_hover" } }) { + if (!IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/" + name + ".svg", 72, 72, texture_id)) + return false; + icon_list.insert(std::make_pair((int) icon, texture_id)); + } + return true; } @@ -476,14 +484,17 @@ void GLGizmosManager::set_hover_id(int id) m_gizmos[m_current]->set_hover_id(id); } -void GLGizmosManager::update_assemble_view_data() +void GLGizmosManager::update_section_view() { - if (m_assemble_view_data) { - if (!wxGetApp().plater()->get_assmeble_canvas3D()->get_wxglcanvas()->IsShown()) - m_assemble_view_data->update(AssembleViewDataID(0)); - else - m_assemble_view_data->update(AssembleViewDataID((int)AssembleViewDataID::ModelObjectsInfo | (int)AssembleViewDataID::ModelObjectsClipper)); - } + if (m_current != FdmSupports && m_current != Seam && m_current != MmSegmentation && m_current != FuzzySkin && m_current != BrimEars) + return; + + CommonGizmosDataObjects::ObjectClipper* clipper = m_common_gizmos_data ? m_common_gizmos_data->object_clipper() : nullptr; + if (clipper == nullptr) + return; + + // Brim ears always cut horizontally. + clipper->set_position_by_ratio(m_parent.get_section_view_ratio(), m_current == BrimEars ? Vec3d::UnitZ() : m_parent.get_section_view_normal()); } void GLGizmosManager::update_data() @@ -496,6 +507,7 @@ void GLGizmosManager::update_data() m_common_gizmos_data->update(get_current() ? get_current()->get_requirements() : CommonGizmosDataID(0)); + update_section_view(); if (m_current != Undefined) m_gizmos[m_current]->data_changed(m_serializing); // Orca: hack: Fix issue that flatten gizmo faces not updated after reload from disk @@ -609,11 +621,11 @@ bool GLGizmosManager::is_allow_select_all() { return false; } -ClippingPlane GLGizmosManager::get_clipping_plane() const +std::optional GLGizmosManager::get_clipping_plane() const { - if (! m_common_gizmos_data - || ! m_common_gizmos_data->object_clipper() - || m_common_gizmos_data->object_clipper()->get_position() == 0.) + if (! m_common_gizmos_data || ! m_common_gizmos_data->object_clipper()) + return std::nullopt; + else if (m_common_gizmos_data->object_clipper()->get_position() == 0.) return ClippingPlane::ClipsNothing(); else { const ClippingPlane& clp = *m_common_gizmos_data->object_clipper()->get_clipping_plane(); @@ -621,18 +633,6 @@ ClippingPlane GLGizmosManager::get_clipping_plane() const } } -ClippingPlane GLGizmosManager::get_assemble_view_clipping_plane() const -{ - if (!m_assemble_view_data - || !m_assemble_view_data->model_objects_clipper() - || m_assemble_view_data->model_objects_clipper()->get_position() == 0.) - return ClippingPlane::ClipsNothing(); - else { - const ClippingPlane& clp = *m_assemble_view_data->model_objects_clipper()->get_clipping_plane(); - return ClippingPlane(-clp.get_normal(), clp.get_data()[3]); - } -} - bool GLGizmosManager::wants_reslice_supports_on_undo() const { return false; @@ -665,12 +665,6 @@ void GLGizmosManager::render_painter_gizmo() gizmo->render_painter_gizmo(); } -void GLGizmosManager::render_painter_assemble_view() const -{ - if (m_assemble_view_data && m_assemble_view_data->model_objects_clipper()) - m_assemble_view_data->model_objects_clipper()->render_cut(); -} - // The icon bar, drawn with GL. void GLGizmosManager::render_overlay() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 63207f741b..855e26c102 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -22,6 +22,7 @@ #include #include #include +#include //BBS: GUI refactor: to support top layout #define BBS_TOOLBAR_ON_TOP 1 @@ -181,7 +182,6 @@ private: bool gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event); public: - std::unique_ptr m_assemble_view_data; enum MENU_ICON_NAME { IC_TOOLBAR_RESET = 0, IC_TOOLBAR_RESET_HOVER, @@ -198,6 +198,14 @@ public: IC_CANVAS_ZOOM_HOVER, IC_CANVAS_ZOOM_DARK, IC_CANVAS_ZOOM_DARK_HOVER, + IC_CANVAS_SECTION, + IC_CANVAS_SECTION_HOVER, + IC_CANVAS_SECTION_DARK, + IC_CANVAS_SECTION_DARK_HOVER, + IC_CANVAS_SECTION_ACTIVE, + IC_CANVAS_SECTION_ACTIVE_HOVER, + IC_CANVAS_SECTION_ACTIVE_DARK, + IC_CANVAS_SECTION_ACTIVE_DARK_HOVER, }; explicit GLGizmosManager(GLCanvas3D& parent); @@ -266,7 +274,8 @@ public: /// Should be called when selection changed ///
void update_data(); - void update_assemble_view_data(); + // Passes the canvas' section view to the object clipper of the painting and brim ears gizmos. + void update_section_view(); EType get_current_type() const { return m_current; } GLGizmoBase* get_current() const; @@ -297,8 +306,8 @@ public: bool is_paint_gizmo(); bool is_allow_select_all(); - ClippingPlane get_clipping_plane() const; - ClippingPlane get_assemble_view_clipping_plane() const; + // Empty when the open gizmo has no object clipper. + std::optional get_clipping_plane() const; bool wants_reslice_supports_on_undo() const; bool is_in_editing_mode(bool error_notification = false) const; @@ -307,7 +316,6 @@ public: void on_change_color_mode(bool is_dark); void render_current_gizmo() const; void render_painter_gizmo(); - void render_painter_assemble_view() const; void render_overlay(); void render_overlay_input_window(); diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp index 84ff8ebe62..e43a129734 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp @@ -1,11 +1,16 @@ #ifndef slic3r_GizmoObjectManipulation_hpp_ #define slic3r_GizmoObjectManipulation_hpp_ +#include #include #include "libslic3r/Point.hpp" #include "libslic3r/Geometry.hpp" #include +#include +#include +#include +#include #include "slic3r/GUI/GUI_Geometry.hpp" @@ -14,6 +19,7 @@ namespace Slic3r { namespace GUI { +class ImGuiWrapper; class Selection; class GLCanvas3D; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 64bb5e11ca..41663d147e 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2656,11 +2656,7 @@ void ImGuiWrapper::push_toolbar_style(const float scale) ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10 ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 12 - // The checkbox/radio frame behind this is drawn fully transparent (see FrameBg above, - // alpha 0), showing the light window background through it - a white check mark there is - // invisible. Dark mode doesn't have this problem (its window background is dark), so only - // this branch needs a check mark color with real contrast against a light background. - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 156 / 255.f, 136 / 255.f, 1.00f));//13 + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//13 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); diff --git a/src/slic3r/GUI/Jobs/PlaterWorker.hpp b/src/slic3r/GUI/Jobs/PlaterWorker.hpp index f22bd6d511..9b149ab91b 100644 --- a/src/slic3r/GUI/Jobs/PlaterWorker.hpp +++ b/src/slic3r/GUI/Jobs/PlaterWorker.hpp @@ -1,13 +1,26 @@ #ifndef PLATERWORKER_HPP #define PLATERWORKER_HPP +#include +#include +#include +#include +#include #include #include #include "Worker.hpp" #include "BusyCursorJob.hpp" +#include "slic3r/GUI/Jobs/Job.hpp" +#include +#include +#include +#include +#include + #include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/I18N.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp index 5bb101b74a..68ad749726 100644 --- a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp +++ b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp @@ -3,7 +3,14 @@ #include "SLAImportJob.hpp" +#include +#include +#include "libslic3r/Point.hpp" +#include #include +#include +#include +#include #include #include #include diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index f7c0f23ae8..903ce4c43a 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -34,6 +34,7 @@ #include "Widgets/StaticLine.hpp" #include "Widgets/TabCtrl.hpp" #include +#include #include #include #include @@ -196,13 +197,13 @@ void KBShortcutsDialog::fill_pages() mouse(Section::Camera, _L("Middle mouse"), "middle_mouse_drag_action"), mouse(Section::Camera, _L("Right mouse"), "right_mouse_drag_action"), fixed(Section::Camera, { wheel }, L("Zoom View")), + fixed(Section::Display, { alt, wheel }, L("Move section plane")), }); page(_L("Painting"), _L("Available while a painting gizmo is open: supports, seam, fuzzy skin or color painting."), ShortcutContext::Painting, { fixed(Section::Gizmos, { esc }, L("Deselect All")), fixed(Section::Gizmos, { shift, left_button }, L("Move: press to snap by 1mm")), fixed(Section::PaintingTools, { ctrl, wheel }, L("Support/Color Painting: adjust pen radius")), - fixed(Section::PaintingTools, { alt, wheel }, L("Support/Color Painting: adjust section position")), }); page(_L("Objects list"), _L("Available while the object list has focus."), ShortcutContext::ObjectList, { @@ -216,6 +217,7 @@ void KBShortcutsDialog::fill_pages() page(_L("Preview"), _L("Available while the 3D view on the Preview tab has focus."), ShortcutContext::Preview, { fixed(Section::Sliders, { shift_ctrl, any_key }, L("Move slider 5x faster")), fixed(Section::Sliders, { shift_ctrl, wheel }, L("Scroll slider 5x faster")), + fixed(Section::Display, { alt, wheel }, L("Move section plane")), }); } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index f8f1fcc199..07d51f9f0c 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -117,6 +117,7 @@ #include "NotificationManager.hpp" #include "MarkdownTip.hpp" #include "NetworkTestDialog.hpp" +#include "SceneBenchmark.hpp" #include "ConfigWizard.hpp" #include "Widgets/WebView.hpp" #include "DailyTips.hpp" @@ -2786,6 +2787,10 @@ wxMenu* MainFrame::generate_help_menu() dlg.ShowModal(); }); + if (wxGetApp().is_editor()) + append_menu_item(helpMenu, wxID_ANY, _L("Benchmark 3D Scene"), _L("Measure how fast the 3D scene renders in Prepare and Preview"), + [](wxCommandEvent&) { run_scene_benchmark(); }); + helpMenu->AppendSeparator(); append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the Day"), _L("Show Tip of the Day"), [](wxCommandEvent&) { @@ -3865,6 +3870,8 @@ bool MainFrame::load_config_file(const std::string &path) return false; } wxGetApp().load_current_presets(); + if (Plater *plater = wxGetApp().plater()) + plater->normalize_bed_types(false); return true; } diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 8c4fc58d03..8c25b31770 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -184,7 +184,8 @@ class MainFrame : public DPIFrame std::string m_name{ "prepare_layout" }; wxSize m_laid_out_size; } m_prepare_layout_prebuild{ *this }; - // Every LazyPage, in and out of the book; prebuild_pages_when_idle() registers them. + // Every built-in LazyPage, in and out of the book; prebuild_pages_when_idle() registers them. + // Plugin pages stay out: PluginPages destroys them at runtime. std::vector m_lazy_pages; // The latest EVT_LOAD_PRINTER_URL, applied when the web Device view is built. wxString m_printer_url; diff --git a/src/slic3r/GUI/MarkdownTip.cpp b/src/slic3r/GUI/MarkdownTip.cpp index 70422a4232..9a80870fe0 100644 --- a/src/slic3r/GUI/MarkdownTip.cpp +++ b/src/slic3r/GUI/MarkdownTip.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/MultiChoiceDialog.cpp b/src/slic3r/GUI/MultiChoiceDialog.cpp index e106d7869f..e78f5d1856 100644 --- a/src/slic3r/GUI/MultiChoiceDialog.cpp +++ b/src/slic3r/GUI/MultiChoiceDialog.cpp @@ -2,6 +2,7 @@ #include "GUI_App.hpp" #include "MainFrame.hpp" +#include #include #include #include "slic3r/GUI/GUI_Utils.hpp" diff --git a/src/slic3r/GUI/NativeCommands.cpp b/src/slic3r/GUI/NativeCommands.cpp index 1725c94fcc..cd983d7e47 100644 --- a/src/slic3r/GUI/NativeCommands.cpp +++ b/src/slic3r/GUI/NativeCommands.cpp @@ -17,6 +17,7 @@ #include "Plater.hpp" #include "PluginsDialog.hpp" #include "PlateSettingsDialog.hpp" +#include "SceneBenchmark.hpp" #include "DeviceCore/DevManager.h" #include "libslic3r/Config.hpp" @@ -591,6 +592,10 @@ std::vector build_command_catalog() dlg.ShowModal(); return AppActionRunResult{AppActionRunResult::Level::Success}; }); + add("help_benchmark_3d_scene", _u8L("Benchmark 3D Scene"), _u8L("Help"), [](const std::string&) { + run_scene_benchmark(); + return AppActionRunResult{AppActionRunResult::Level::Success}; + }); add_with_icon("help_tip_of_the_day", _u8L("Show Tip of the Day"), _u8L("Help"), "info", [](const std::string&) { if (Plater* plater = wxGetApp().plater()) { plater->get_dailytips()->open(); diff --git a/src/slic3r/GUI/ParamsDialog.cpp b/src/slic3r/GUI/ParamsDialog.cpp index 87888848a6..008f71d6d1 100644 --- a/src/slic3r/GUI/ParamsDialog.cpp +++ b/src/slic3r/GUI/ParamsDialog.cpp @@ -3,6 +3,7 @@ #include "ParamsPanel.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" +#include "Plater.hpp" #include "Tab.hpp" #include "libslic3r/Utils.hpp" @@ -70,6 +71,18 @@ ParamsDialog::ParamsDialog(wxWindow * parent) } Hide(); + if (tab && tab->type() == Preset::TYPE_PRINTER) { + // Normalize only after the dialog closes, when the final capability is known. + auto &preset_bundle = *wxGetApp().preset_bundle; + const bool supports_multiple_bed_types = preset_bundle.is_bbl_vendor() || + preset_bundle.printers.get_edited_preset().config.opt_bool("support_multi_bed_types"); + if (m_initial_multi_bed_types != supports_multiple_bed_types) { + wxGetApp().plater()->normalize_bed_types(true); + if (auto *plate_tab = dynamic_cast(wxGetApp().get_plate_tab())) + plate_tab->update_model_config(); + } + } + if (!m_editing_filament_id.empty()) { Filamentinformation *filament_info = new Filamentinformation(); filament_info->filament_id = m_editing_filament_id; @@ -93,7 +106,15 @@ void ParamsDialog::Popup() if (m_panel && m_panel->get_current_tab()) { bool just_edit = false; if (!m_editing_filament_id.empty()) just_edit = true; - dynamic_cast(m_panel->get_current_tab())->set_just_edit(just_edit); + auto *tab = dynamic_cast(m_panel->get_current_tab()); + tab->set_just_edit(just_edit); + if (tab->type() == Preset::TYPE_PRINTER) { + // Remember the initial capability and compare it when the dialog closes. + // Bambu profiles support multiple bed types even when this option is unset. + auto &preset_bundle = *wxGetApp().preset_bundle; + m_initial_multi_bed_types = preset_bundle.is_bbl_vendor() || + preset_bundle.printers.get_edited_preset().config.opt_bool("support_multi_bed_types"); + } } Show(); } diff --git a/src/slic3r/GUI/ParamsDialog.hpp b/src/slic3r/GUI/ParamsDialog.hpp index 9ad34e165e..80c9c3d2fe 100644 --- a/src/slic3r/GUI/ParamsDialog.hpp +++ b/src/slic3r/GUI/ParamsDialog.hpp @@ -43,6 +43,7 @@ protected: private: std::string m_editing_filament_id; + bool m_initial_multi_bed_types = false; ParamsPanel * m_panel; wxWindowDisabler *m_winDisabler = nullptr; }; diff --git a/src/slic3r/GUI/PartSkipCommon.hpp b/src/slic3r/GUI/PartSkipCommon.hpp index bd158edbf8..ae7ad6f6a5 100644 --- a/src/slic3r/GUI/PartSkipCommon.hpp +++ b/src/slic3r/GUI/PartSkipCommon.hpp @@ -1,6 +1,8 @@ #ifndef PARTSKIPCOMMON_H #define PARTSKIPCOMMON_H +#include +#include namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/PlateSettingsDialog.cpp b/src/slic3r/GUI/PlateSettingsDialog.cpp index b640b2cb84..31b8367774 100644 --- a/src/slic3r/GUI/PlateSettingsDialog.cpp +++ b/src/slic3r/GUI/PlateSettingsDialog.cpp @@ -431,8 +431,9 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title } } - if (!wxGetApp().preset_bundle->is_bbl_vendor()) - m_bed_type_choice->Disable(); + auto &preset_bundle = *wxGetApp().preset_bundle; + const auto &printer_config = preset_bundle.printers.get_edited_preset().config; + m_bed_type_choice->Enable(preset_bundle.is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types")); wxStaticText* m_bed_type_txt = new wxStaticText(this, wxID_ANY, _L("Bed type")); m_bed_type_txt->SetFont(Label::Body_14); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 142e4e2482..158991a92f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6,6 +6,7 @@ #include "libslic3r/Config.hpp" #include "libslic3r_version.h" +#include #include #include #include @@ -7401,7 +7402,8 @@ struct Plater::priv std::vector load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi = false, - bool* published_out = nullptr); + bool* published_out = nullptr, + bool* config_loaded_out = nullptr); std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true); // Texture-to-color import: a mesh loaded with UVs + a texture map gets its faces clustered @@ -7891,6 +7893,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D = new View3D(panel_3d, bed, &model, config, &background_process); //BBS: use partplater's gcode preview = new Preview(panel_3d, bed, &model, config, &background_process, partplate_list.get_current_slice_result(), [this]() { schedule_background_process(); }); + preview->get_canvas3d()->share_section_view(*view3D->get_canvas3d()); assemble_view = new AssembleView(panel_3d, bed, &model, config, &background_process); @@ -8871,8 +8874,12 @@ void read_binary_stl(const std::string& filename, std::string& model_id, std::st std::vector Plater::priv::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi, - bool* published_out) + bool* published_out, + bool* config_loaded_out) { + if (config_loaded_out != nullptr) + *config_loaded_out = false; + std::vector empty_result; bool dlg_cont = true; bool is_user_cancel = false; @@ -9557,6 +9564,8 @@ std::vector Plater::priv::load_files(const std::vector& input_ id = agent->to_orca_filament_id(id); } preset_bundle->load_config_model(filename.string(), std::move(config), file_version, &published_config); + if (config_loaded_out != nullptr) + *config_loaded_out = true; // Mixed-filament definitions that collided with one of the // receiver's real slots were relocated during the preset load. @@ -12779,6 +12788,8 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt) // update plater with new config q->on_config_change(wxGetApp().preset_bundle->full_config()); + if (auto *plate_tab = dynamic_cast(wxGetApp().get_plate_tab())) + plate_tab->update_model_config(); // update app_config AppConfig* app_config = wxGetApp().app_config; @@ -15478,6 +15489,38 @@ void Plater::reset_project_dirty_initial_presets() { p->reset_project_dirty_init void Plater::render_project_state_debug_window() const { p->render_project_state_debug_window(); } #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW +void Plater::normalize_bed_types(bool printer_setting_changed) +{ + if (only_gcode_mode() || is_gcode_3mf()) + return; + + auto &preset_bundle = *wxGetApp().preset_bundle; + // Keep FFF plate settings intact while an SLA printer is selected. + if (preset_bundle.printers.get_edited_preset().printer_technology() != ptFFF) + return; + + const auto &printer_config = preset_bundle.printers.get_edited_preset().config; + + const bool supports_multiple_bed_types = + preset_bundle.is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types"); + // Clear local overrides for single-bed printers. + const bool overrides_reset = !supports_multiple_bed_types && + !p->partplate_list.check_all_plate_local_bed_type({}); + + if (overrides_reset) { + set_plater_dirty(true); + show_info(this, + _L("The selected printer does not support multiple bed types.\nBed type overrides were reset to the global bed type."), + _L("Plate bed types reset")); + } + + // Refresh the controls after a capability change, even when no override was reset. + if (printer_setting_changed || overrides_reset) { + sidebar().update_all_preset_comboboxes(); + wxGetApp().obj_list()->update_and_show_object_settings_item(); + } +} + std::vector Plater::mixed_filament_config_indices() const { std::vector indices; @@ -16058,6 +16101,9 @@ void Plater::load_project(wxString const& filename2, p->dirty_state.update_from_undo_redo_stack(true); up_to_date(true, true); + // Clear plate overrides that are incompatible with the selected printer. + normalize_bed_types(false); + wxGetApp().params_panel()->switch_to_object_if_has_object_configs(); auto has_modify = is_flush_config_modified(); @@ -17690,7 +17736,11 @@ std::vector Plater::load_files(const std::vector& input_files, p->m_slice_all_only_has_gcode = false; //BBS: wish to reset all plates stats item selected state when load a new file p->preview->get_canvas3d()->reset_select_plate_toolbar_selection(); - return p->load_files(input_files, strategy, ask_multi, published_out); + bool config_loaded = false; + std::vector result = p->load_files(input_files, strategy, ask_multi, published_out, &config_loaded); + if (config_loaded && !is_loading_project()) + normalize_bed_types(false); + return result; } bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index a887805f8a..17534ebf7d 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -343,6 +343,7 @@ public: bool is_presets_dirty() const; void set_plater_dirty(bool is_dirty); void update_project_dirty_from_presets(); + void normalize_bed_types(bool printer_setting_changed); int save_project_if_dirty(const wxString& reason); void reset_project_dirty_after_save(); void reset_project_dirty_initial_presets(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 61ce51112e..6575465198 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -65,6 +65,7 @@ #include #include #include "NetworkTestDialog.hpp" +#include "SceneBenchmark.hpp" #include "Widgets/StaticLine.hpp" #include "Widgets/RadioGroup.hpp" #include "Shortcuts.hpp" @@ -1999,11 +2000,14 @@ void PreferencesDialog::create_items() ); g_sizer->Add(item_realistic_ssao); - auto item_realistic_shadows = create_item_checkbox( + std::vector ShadowsLabels = { _L("Off"), _L("Static"), _L("Orbit") }; + std::vector ShadowsValues = { "off", "static", "orbit" }; + auto item_realistic_shadows = create_item_combobox( _L("Shadows"), - _L("Renders cast shadows on the plate, other objects, and each object onto itself in realistic view."), - SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS - ); + _L("Renders cast shadows on the plate, other objects, and each object onto itself in realistic view.\n" + "Static: the light stays fixed in the world, so the shadows are only recomputed when the scene changes.\n" + "Orbit: the light turns with the camera, recomputing the shadows every frame the camera moves."), + SETTING_OPENGL_REALISTIC_SHADOWS, ShadowsLabels, ShadowsValues); g_sizer->Add(item_realistic_shadows); //// GRAPHICS > Anti-aliasing @@ -2076,6 +2080,26 @@ void PreferencesDialog::create_items() ); g_sizer->Add(item_fps_overlay); + auto item_render_timings = create_item_checkbox( + _L("Show render timings"), + _L("Displays how many milliseconds each part of a frame that redraws the 3D scene takes, in the top-right corner of the viewport.") + "\n" + + _L("CPU: time spent issuing the drawing commands.") + "\n" + + _L("GPU: time the graphics card spent running them.") + "\n" + + _L("Adds a small overhead to each frame while enabled."), + SETTING_OPENGL_SHOW_RENDER_TIMINGS + ); + g_sizer->Add(item_render_timings); + + if (wxGetApp().is_editor()) { + auto item_benchmark = create_item_button(_L("3D scene benchmark"), _L("Run") + " " + dots, "", + _L("Replaces the current project with the OrcaSliced Combo, then measures the frame rate and render timings while the camera turns around it in Prepare and Preview, and while the layer slider moves through the sliced layers."), + [this]() { + EndModal(wxID_OK); + wxGetApp().CallAfter([] { run_scene_benchmark(); }); + }); + g_sizer->Add(item_benchmark); + } + //// GRAPHICS > G-code Preview g_sizer->Add(create_item_title(_L("G-code Preview")), 1, wxEXPAND); diff --git a/src/slic3r/GUI/PrinterWebView.cpp b/src/slic3r/GUI/PrinterWebView.cpp index 4ea2ba0a72..1993748cc6 100644 --- a/src/slic3r/GUI/PrinterWebView.cpp +++ b/src/slic3r/GUI/PrinterWebView.cpp @@ -119,33 +119,13 @@ PrinterWebView::PrinterWebView(wxWindow *parent) wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); // Create the webview - m_browser = WebView::CreateWebView(this, ""); - if (m_browser == nullptr) { - wxLogError("Could not init m_browser"); - return; - } - -#ifdef __linux__ - inject_vue_resize_workaround(m_browser); - - auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db"); - auto wv = static_cast(m_browser->GetNativeBackend()); - auto wv_ctx = webkit_web_view_get_context(wv); - auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx); - webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE); -#endif - - m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this); - m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this); - m_browser->Bind(wxEVT_WEBVIEW_NEWWINDOW, &PrinterWebView::OnNewWindow, this); - m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterWebView::OnScriptMessage, this); + create_browser(); + m_reset_on_show = WebView::NeedsRecreateOnShow(); SetSizer(topsizer); topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); - update_mode(); - // Log backend information /* m_browser->GetUserAgent() may lead crash if (wxGetApp().get_mode() == comDevelop) { @@ -177,12 +157,44 @@ PrinterWebView::~PrinterWebView() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " End"; } +void PrinterWebView::create_browser() +{ + m_browser = WebView::CreateWebView(this, ""); + +#ifdef __linux__ + inject_vue_resize_workaround(m_browser); + + auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db"); + auto wv = static_cast(m_browser->GetNativeBackend()); + auto wv_ctx = webkit_web_view_get_context(wv); + auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx); + webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE); +#endif + + m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this); + m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this); + m_browser->Bind(wxEVT_WEBVIEW_NEWWINDOW, &PrinterWebView::OnNewWindow, this); + m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &PrinterWebView::OnScriptMessage, this); + update_mode(); +} + +void PrinterWebView::reset_browser() +{ + m_browser->Destroy(); // also removes it from the sizer + create_browser(); + GetSizer()->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); + Layout(); + + // OnLoaded may have cleared m_url_deferred already, so requeue the last url for Show(). + m_apikey_sent = false; + m_url_deferred = m_url; +} + void PrinterWebView::load_url(wxString& url, wxString apikey) { // this->Show(); // this->Raise(); - if (m_browser == nullptr) - return; + m_url = url; m_apikey = apikey; m_apikey_sent = false; m_handler = create_printer_webview_handler(*this); @@ -200,6 +212,8 @@ void PrinterWebView::load_url(wxString& url, wxString apikey) bool PrinterWebView::Show(bool show) { + if (show && std::exchange(m_reset_on_show, false)) + reset_browser(); if (show && !m_url_deferred.empty()) { m_browser->LoadURL(m_url_deferred); //ORCA: m_url_deferred will be cleared on load success diff --git a/src/slic3r/GUI/PrinterWebView.hpp b/src/slic3r/GUI/PrinterWebView.hpp index 9bd8ff51a8..53c4f30557 100644 --- a/src/slic3r/GUI/PrinterWebView.hpp +++ b/src/slic3r/GUI/PrinterWebView.hpp @@ -58,13 +58,18 @@ private: friend class PrinterWebViewHandler; void SendAPIKey(); + void create_browser(); + void reset_browser(); wxWebView* m_browser; long m_zoomFactor; wxString m_apikey; bool m_apikey_sent; + // Last url passed to load_url(), reloaded after reset_browser(). + wxString m_url; wxString m_url_deferred; std::unique_ptr m_handler; + bool m_reset_on_show{false}; // DECLARE_EVENT_TABLE() }; diff --git a/src/slic3r/GUI/Project.cpp b/src/slic3r/GUI/Project.cpp index 47945e1179..d8e7d6b806 100644 --- a/src/slic3r/GUI/Project.cpp +++ b/src/slic3r/GUI/Project.cpp @@ -80,16 +80,10 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); - m_browser = WebView::CreateWebView(this, m_project_home_url); - if (m_browser == nullptr) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("load web view of project page failed"); - return; - } + create_browser(); + m_reset_on_show = WebView::NeedsRecreateOnShow(); //m_browser->Hide(); main_sizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); - m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this); - m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this, m_browser->GetId()); Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this); @@ -117,6 +111,23 @@ void ProjectPanel::shutdown() m_reload_task.reset(); } +void ProjectPanel::create_browser() +{ + m_browser = WebView::CreateWebView(this, m_project_home_url); + m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this); + m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId()); + m_browser->Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this); +} + +void ProjectPanel::reset_browser() +{ + m_browser->Destroy(); // also removes it from the sizer + create_browser(); + GetSizer()->Insert(0, m_browser, wxSizerFlags().Expand().Proportion(1)); + Layout(); + m_web_init_completed.store(false, std::memory_order_release); +} + // Helper to convert newlines to
static std::string convert_newlines_to_br(const std::string& text) { std::string result = text; @@ -281,12 +292,13 @@ void ProjectPanel::on_reload(wxCommandEvent& evt) wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', false, json::error_handler_t::ignore)); - if (m_web_init_completed.load(std::memory_order_acquire) && - !cancel_token->load(std::memory_order_acquire) && wxTheApp != nullptr && !wxGetApp().is_closing()) { + if (!cancel_token->load(std::memory_order_acquire) && wxTheApp != nullptr && !wxGetApp().is_closing()) { wxGetApp().CallAfter([this, cancel_token, strJS] { if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing()) return; - RunScript(strJS.ToStdString()); + m_info_script = strJS.ToStdString(); + if (m_web_init_completed.load(std::memory_order_acquire)) + RunScript(m_info_script); }); } }); @@ -327,6 +339,11 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt) } else if (strCmd == "request_3mf_info") { m_web_init_completed.store(true, std::memory_order_release); + // Replay the stored info after each page load. + CallAfter([this] { + if (!m_info_script.empty()) + RunScript(m_info_script); + }); } else if (strCmd == "edit_project_info") { show_info_editor(true); @@ -383,6 +400,8 @@ void ProjectPanel::clear_model_info() wxGetApp().CallAfter([this, cancel_token, strJS] { if (cancel_token->load(std::memory_order_acquire) || wxTheApp == nullptr || wxGetApp().is_closing()) return; + // Runs after any store queued by an earlier reload pass, so stale info is never replayed. + m_info_script.clear(); RunScript(strJS.ToStdString()); }); } @@ -523,10 +542,12 @@ void ProjectPanel::RunScript(std::string content) WebView::RunScript(m_browser, content); } -bool ProjectPanel::Show(bool show) +bool ProjectPanel::Show(bool show) { + if (show && std::exchange(m_reset_on_show, false)) + reset_browser(); if (show) update_model_data(); - return wxPanel::Show(show); + return wxPanel::Show(show); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp index c7a85bce74..90e6eda1f1 100644 --- a/src/slic3r/GUI/Project.hpp +++ b/src/slic3r/GUI/Project.hpp @@ -80,9 +80,14 @@ private: AuxiliaryPanel* m_auxiliary{nullptr}; wxString m_project_home_url; wxString m_root_dir; + // Last show_3mf_info script, also sent whenever the page asks for it. + std::string m_info_script; + bool m_reset_on_show{false}; static inline std::atomic m_sequence_id{8000}; void show_info_editor(bool show); + void create_browser(); + void reset_browser(); public: diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index 7aff669668..7f280debf5 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/SavePresetDialog.hpp b/src/slic3r/GUI/SavePresetDialog.hpp index 10cf25883b..3bbeeb0cde 100644 --- a/src/slic3r/GUI/SavePresetDialog.hpp +++ b/src/slic3r/GUI/SavePresetDialog.hpp @@ -12,6 +12,7 @@ #include "Widgets/Label.hpp" #include "Widgets/TextInput.hpp" #include +#include #include #include #include diff --git a/src/slic3r/GUI/SceneBenchmark.cpp b/src/slic3r/GUI/SceneBenchmark.cpp new file mode 100644 index 0000000000..d4609d1f1f --- /dev/null +++ b/src/slic3r/GUI/SceneBenchmark.cpp @@ -0,0 +1,555 @@ +#include "SceneBenchmark.hpp" + +#include "3DScene.hpp" +#include "BuildCommit.hpp" +#include "Camera.hpp" +#include "GLCanvas3D.hpp" +#include "GUI.hpp" +#include "GUI_App.hpp" +#include "GUI_Factories.hpp" +#include "I18N.hpp" +#include "IMSlider.hpp" +#include "MainFrame.hpp" +#include "MsgDialog.hpp" +#include "NotificationManager.hpp" +#include "OpenGLManager.hpp" +#include "Plater.hpp" +#include "Widgets/DialogButtons.hpp" +#include "Widgets/Label.hpp" +#include "Widgets/ProgressBar.hpp" +#include "Widgets/StateColor.hpp" + +#include "libslic3r/AppConfig.hpp" +#include "libslic3r/libslic3r.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +FrameTimeStats frame_time_stats(std::vector frame_ms) +{ + FrameTimeStats stats; + if (frame_ms.empty()) + return stats; + + std::sort(frame_ms.begin(), frame_ms.end()); + const double total_ms = std::accumulate(frame_ms.begin(), frame_ms.end(), 0.0); + auto percentile = [&frame_ms](double p) { + const size_t rank = size_t(std::ceil(p * double(frame_ms.size()) / 100.0)); + return frame_ms[std::clamp(rank, 1, frame_ms.size()) - 1]; + }; + stats.fps = total_ms > 0.0 ? 1000.0 * double(frame_ms.size()) / total_ms : 0.0; + stats.average_ms = total_ms / double(frame_ms.size()); + stats.median_ms = percentile(50.0); + stats.p95_ms = percentile(95.0); + stats.p99_ms = percentile(99.0); + stats.max_ms = frame_ms.back(); + return stats; +} + +namespace { + +constexpr size_t WARMUP_FRAMES = 30; +// A scene runs the camera path twice: timing the frames, then averaging the render timings. +constexpr size_t PASS_FRAMES = 360; +constexpr size_t SCENE_FRAMES = WARMUP_FRAMES + 2 * PASS_FRAMES; + +struct SceneResult +{ + std::string name; + std::vector frame_ms; + std::vector sections; +}; + +class SceneBenchmarkDialog : public DPIDialog +{ +public: + SceneBenchmarkDialog(); + ~SceneBenchmarkDialog() override; + + bool is_running() const { return m_stage != Stage::Done; } + +protected: + void on_dpi_changed(const wxRect& suggested_rect) override; + +private: + enum class Stage { Loading, Prepare, Slicing, Preview, Layers, Done }; + + void on_timer(wxTimerEvent& evt); + void on_idle(wxIdleEvent& evt); + void on_first_frame(); + void begin_scene(GLCanvas3D* canvas, Stage stage); + void end_scene(); + void stop_scene(); + void start_slicing(); + void set_camera(size_t pass_frame); + void set_top_layer(size_t pass_frame); + void set_status(const wxString& status); + void finish(const wxString& error = wxString()); + void show_report(const wxString& error); + std::string report() const; + + Stage m_stage{ Stage::Loading }; + std::unique_ptr m_disabler; + wxTimer m_timer; + int m_polls{ 0 }; + Label* m_status{ nullptr }; + ProgressBar* m_progress{ nullptr }; + + GLCanvas3D* m_canvas{ nullptr }; + Camera m_saved_camera; + Vec3d m_target{ Vec3d::Zero() }; + double m_zoom{ 1.0 }; + size_t m_frame{ 0 }; + std::chrono::steady_clock::time_point m_last_frame; + // The layer slider's top before the Layers scene moved it, -1 outside that scene. + int m_saved_top_layer{ -1 }; + int m_swap_interval{ wxGLCanvas::DefaultSwapInterval }; + bool m_restore_swap_interval{ false }; + std::vector m_results; + + // Read on the first frame, with the context current. + std::string m_vsync; + int m_msaa_samples{ 0 }; + int m_viewport_width{ 0 }; + int m_viewport_height{ 0 }; + std::string m_camera_type; +}; + +SceneBenchmarkDialog* s_benchmark = nullptr; + +SceneBenchmarkDialog::SceneBenchmarkDialog() + : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Benchmark 3D Scene"), wxDefaultPosition, wxDefaultSize, + wxCAPTION | wxCLOSE_BOX) + , m_timer(this) +{ + s_benchmark = this; + SetBackgroundColour(*wxWHITE); + SetFont(Label::Body_14); + + auto* sizer = new wxBoxSizer(wxVERTICAL); + sizer->SetMinSize(wxSize(FromDIP(360), -1)); + m_status = new Label(this, _L("Loading the benchmark model") + dots); + m_progress = new ProgressBar(this, wxID_ANY, 100); + m_progress->SetHeight(FromDIP(8)); + m_progress->SetMaxSize(wxSize(-1, FromDIP(8))); + m_progress->SetProgressForedColour(StateColor::darkModeColorFor(wxColour("#DFDFDF"))); + sizer->Add(m_status, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, FromDIP(15)); + sizer->Add(m_progress, 0, wxEXPAND | wxALL, FromDIP(15)); + auto* buttons = new DialogButtons(this, {"Cancel"}); + buttons->GetCANCEL()->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { Close(); }); + sizer->Add(buttons, 0, wxEXPAND); + SetSizerAndFit(sizer); + wxGetApp().UpdateDlgDarkUI(this); + + Bind(wxEVT_TIMER, &SceneBenchmarkDialog::on_timer, this); + Bind(wxEVT_IDLE, &SceneBenchmarkDialog::on_idle, this); + Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& evt) { + if (evt.GetKeyCode() == WXK_ESCAPE) + Close(); + else + evt.Skip(); + }); + Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent&) { + m_timer.Stop(); + stop_scene(); + m_disabler.reset(); + Destroy(); + }); + + // A corner of the 3D view, away from the model. + const wxRect view = wxGetApp().plater()->get_current_canvas3D()->get_wxglcanvas()->GetScreenRect(); + SetPosition(wxPoint(view.GetLeft() + FromDIP(20), view.GetBottom() - GetSize().GetHeight() - FromDIP(20))); + + m_disabler = std::make_unique(this); + m_timer.Start(100); +} + +SceneBenchmarkDialog::~SceneBenchmarkDialog() +{ + // At shutdown the windows it disabled may be gone already. + if (wxGetApp().is_closing()) + (void) m_disabler.release(); + if (s_benchmark == this) + s_benchmark = nullptr; +} + +void SceneBenchmarkDialog::on_dpi_changed(const wxRect&) +{ + Fit(); + Refresh(); +} + +void SceneBenchmarkDialog::on_timer(wxTimerEvent&) +{ + Plater* plater = wxGetApp().plater(); + if (wxGetApp().is_closing() || plater == nullptr) { + m_timer.Stop(); + return; + } + + if (m_stage == Stage::Loading) { + if (!plater->get_ui_job_worker().is_idle()) + return; + m_timer.Stop(); + GLCanvas3D* canvas = plater->get_view3D_canvas3D(); + const BoundingBoxf3 box = canvas->volumes_bounding_box(true); + if (!box.defined) { + finish(_L("The benchmark model could not be loaded.")); + return; + } + m_target = box.center(); + const Size size = canvas->get_canvas_size(); + m_zoom = double(std::min(size.get_width(), size.get_height())) / (1.1 * box.size().norm()); + plater->deselect_all(); + begin_scene(canvas, Stage::Prepare); + } else if (m_stage == Stage::Slicing) { + if (plater->is_background_process_slicing()) + return; + GLCanvas3D* canvas = plater->get_preview_canvas3D(); + if (canvas->get_gcode_viewer().has_data() && canvas->get_wxglcanvas()->IsShownOnScreen()) { + m_timer.Stop(); + plater->get_notification_manager()->set_slicing_progress_hidden(); + begin_scene(canvas, Stage::Preview); + } else if (++m_polls > 30) + finish(_L("Slicing failed, so only Prepare was measured.")); + } +} + +void SceneBenchmarkDialog::on_idle(wxIdleEvent& evt) +{ + evt.Skip(); + if (m_canvas == nullptr || wxGetApp().is_closing()) + return; + if (!m_canvas->get_wxglcanvas()->IsShownOnScreen()) { + finish(_L("The benchmark stopped because the 3D view was hidden.")); + return; + } + + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + if (m_frame > WARMUP_FRAMES && m_frame <= WARMUP_FRAMES + PASS_FRAMES) + m_results.back().frame_ms.push_back(std::chrono::duration(now - m_last_frame).count()); + m_last_frame = now; + + FrameProfiler& profiler = m_canvas->get_frame_profiler(); + if (m_frame == WARMUP_FRAMES + PASS_FRAMES) + profiler.start_averaging(); + if (m_stage == Stage::Layers) + // The warm-up ends where the path starts, so the slider moves in every frame. + set_top_layer(m_frame < WARMUP_FRAMES ? PASS_FRAMES - WARMUP_FRAMES + m_frame : (m_frame - WARMUP_FRAMES) % PASS_FRAMES); + else + set_camera(m_frame < WARMUP_FRAMES ? 0 : (m_frame - WARMUP_FRAMES) % PASS_FRAMES); + m_canvas->render(); + if (m_frame == 0) + on_first_frame(); + + if (++m_frame == SCENE_FRAMES) { + m_results.back().sections = profiler.finish_averaging(true); + end_scene(); + // The next scene starts right away, with no timer to bring the next idle event. + if (m_canvas != nullptr) + evt.RequestMore(); + return; + } + const int scene = m_stage == Stage::Prepare ? 0 : m_stage == Stage::Preview ? 1 : 2; + if (m_frame % 30 == 0) + m_progress->SetValue(int(100 * (scene * SCENE_FRAMES + m_frame) / (3 * SCENE_FRAMES))); + evt.RequestMore(); +} + +void SceneBenchmarkDialog::on_first_frame() +{ + // A benchmark measures the frames the GPU can draw, not the display refresh rate. + wxGLCanvas* glcanvas = m_canvas->get_wxglcanvas(); + m_swap_interval = glcanvas->GetSwapInterval(); + const bool known = m_swap_interval != wxGLCanvas::DefaultSwapInterval; + if (known && m_swap_interval != 0) + m_restore_swap_interval = glcanvas->SetSwapInterval(0) != wxGLCanvas::SwapInterval::NotSet; + if (m_results.size() > 1) + return; + + m_vsync = !known ? "unknown" : m_swap_interval == 0 || m_restore_swap_interval ? "off" : "on"; + GLint samples = 0; + glsafe(::glGetIntegerv(GL_SAMPLES, &samples)); + m_msaa_samples = samples; + const Camera& camera = wxGetApp().plater()->get_camera(); + const std::array& viewport = camera.get_viewport(); + m_viewport_width = viewport[2]; + m_viewport_height = viewport[3]; + m_camera_type = camera.get_type_as_string(); +} + +void SceneBenchmarkDialog::begin_scene(GLCanvas3D* canvas, Stage stage) +{ + m_stage = stage; + m_canvas = canvas; + m_saved_camera = wxGetApp().plater()->get_camera(); + m_frame = 0; + m_restore_swap_interval = false; + m_results.push_back({stage == Stage::Prepare ? "Prepare" : stage == Stage::Preview ? "Preview" : "Layers", {}, {}}); + m_results.back().frame_ms.reserve(PASS_FRAMES); + set_status(stage == Stage::Prepare ? _L("Turning the camera in Prepare") : + stage == Stage::Preview ? _L("Turning the camera in Preview") : + _L("Moving through the layers in Preview")); + if (stage == Stage::Layers) { + m_saved_top_layer = canvas->get_gcode_viewer().get_layers_slider()->GetHigherValue(); + set_camera(0); + } + canvas->set_benchmarking(true); +} + +void SceneBenchmarkDialog::end_scene() +{ + const Stage stage = m_stage; + GLCanvas3D* canvas = m_canvas; + stop_scene(); + if (stage == Stage::Prepare) + start_slicing(); + else if (stage == Stage::Preview) + begin_scene(canvas, Stage::Layers); + else + finish(); +} + +void SceneBenchmarkDialog::stop_scene() +{ + if (m_canvas == nullptr) + return; + if (m_frame < SCENE_FRAMES) + m_results.pop_back(); + FrameProfiler& profiler = m_canvas->get_frame_profiler(); + if (profiler.is_averaging()) + profiler.finish_averaging(false); + if (m_restore_swap_interval && m_canvas->make_current_for_postinit()) + m_canvas->get_wxglcanvas()->SetSwapInterval(m_swap_interval); + if (m_saved_top_layer >= 0) { + m_canvas->get_gcode_viewer().get_layers_slider()->SetHigherValue(m_saved_top_layer); + m_saved_top_layer = -1; + } + m_canvas->set_benchmarking(false); + m_canvas->set_as_dirty(); + wxGetApp().plater()->get_camera() = m_saved_camera; + m_canvas = nullptr; +} + +void SceneBenchmarkDialog::start_slicing() +{ + m_stage = Stage::Slicing; + set_status(_L("Slicing")); + m_progress->SetValue(33); + Plater* plater = wxGetApp().plater(); + plater->reslice(); + plater->select_view_3D("Preview", false); + wxGetApp().mainframe->select_tab(TAB_ID_PREVIEW); + m_polls = 0; + m_timer.Start(100); +} + +void SceneBenchmarkDialog::set_camera(size_t pass_frame) +{ + // Two turns around the model while the view goes three times from below the plate to nearly + // straight above it, zooming in and out twice. + const double t = double(pass_frame) / double(PASS_FRAMES); + const double azimuth = (-0.75 + 4.0 * t) * PI; + const double elevation = (30.0 + 55.0 * std::sin(6.0 * PI * t)) * PI / 180.0; + const Vec3d dir(std::cos(elevation) * std::cos(azimuth), std::cos(elevation) * std::sin(azimuth), std::sin(elevation)); + Camera& camera = wxGetApp().plater()->get_camera(); + camera.look_at(m_target + Camera::DefaultDistance * dir, m_target, Vec3d::UnitZ()); + camera.set_zoom(m_zoom * (1.0 + 0.4 * std::sin(4.0 * PI * t))); +} + +void SceneBenchmarkDialog::set_top_layer(size_t pass_frame) +{ + // Down to the first layer and back up, as dragging the top of the layer slider does. + IMSlider* slider = m_canvas->get_gcode_viewer().get_layers_slider(); + const double t = double(pass_frame) / double(PASS_FRAMES); + const int span = slider->GetMaxValue() - slider->GetMinValue(); + slider->SetHigherValue(slider->GetMinValue() + int(std::lround(span * std::abs(1.0 - 2.0 * t)))); +} + +void SceneBenchmarkDialog::set_status(const wxString& status) +{ + m_status->SetLabel(status + dots); + Fit(); +} + +void SceneBenchmarkDialog::finish(const wxString& error) +{ + m_timer.Stop(); + stop_scene(); + m_disabler.reset(); + m_stage = Stage::Done; + show_report(error); +} + +void SceneBenchmarkDialog::show_report(const wxString& error) +{ + DestroyChildren(); + m_status = nullptr; + m_progress = nullptr; + + auto* sizer = new wxBoxSizer(wxVERTICAL); + if (!error.IsEmpty()) { + auto* message = new Label(this, error); + message->Wrap(FromDIP(500)); + sizer->Add(message, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, FromDIP(15)); + } + + std::string text; + if (!m_results.empty()) { + text = report(); + auto* content = new wxTextCtrl(this, wxID_ANY, from_u8(text), wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP | wxBORDER_SIMPLE); + content->SetFont(wxGetApp().code_font()); + wxClientDC dc(content); + dc.SetFont(content->GetFont()); + const wxSize extent = dc.GetMultiLineTextExtent(content->GetValue()) + FromDIP(wxSize(40, 20)); + content->SetMinSize(wxSize(extent.GetWidth(), std::min(extent.GetHeight(), FromDIP(560)))); + sizer->Add(content, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, FromDIP(15)); + } + + auto* buttons = new DialogButtons(this, text.empty() ? std::vector{"OK"} : std::vector{"Copy", "OK"}); + if (Button* copy = buttons->GetButtonFromID(wxID_COPY)) { + copy->SetToolTip(_L("Copy the results to the clipboard")); + copy->Bind(wxEVT_BUTTON, [text](wxCommandEvent&) { + wxClipboardLocker lock; + if (!lock) + return; + wxTheClipboard->SetData(new wxTextDataObject(from_u8(text))); + }); + } + buttons->GetOK()->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { Close(); }); + sizer->Add(buttons, 0, wxEXPAND); + + SetSizerAndFit(sizer); + CenterOnParent(); + wxGetApp().UpdateDlgDarkUI(this); + Raise(); +} + +std::string SceneBenchmarkDialog::report() const +{ + const AppConfig& config = *wxGetApp().app_config; + const OpenGLManager::GLInfo& gl = OpenGLManager::get_gl_info(); + auto on_off = [](bool on) { return on ? "on" : "off"; }; + + std::ostringstream out; + out << SLIC3R_APP_NAME << " 3D scene benchmark\n" + << "Version: " << SoftFever_VERSION << " (" << build_commit_label << ")\n" + << "GPU: " << gl.get_renderer() << '\n' + << "OpenGL: " << gl.get_version() << '\n' + << "Viewport: " << m_viewport_width << " x " << m_viewport_height << " px, " << m_camera_type << " camera\n" + << "Settings: MSAA " << (m_msaa_samples > 1 ? std::to_string(m_msaa_samples) + "x" : "off") + << ", FXAA " << on_off(config.get_bool(SETTING_OPENGL_FXAA_ENABLED)) + << ", scene cache " << on_off(config.get_bool(SETTING_OPENGL_SCENE_CACHE)) << ", VSync " << m_vsync << '\n' + << "Realistic: "; + if (config.get_bool(SETTING_OPENGL_REALISTIC_MODE)) + out << "on, Phong " << on_off(config.get_bool(SETTING_OPENGL_REALISTIC_PHONG)) << ", SSAO " + << on_off(config.get_bool(SETTING_OPENGL_PHONG_SSAO)) << ", shadows " << config.get(SETTING_OPENGL_REALISTIC_SHADOWS) + << ", in Preview " << on_off(config.get_bool(SETTING_OPENGL_REALISTIC_PREVIEW)) << '\n'; + else + out << "off\n"; + // The Preview scenes depend on the toolpaths, which depend on the presets it was sliced with. + const PresetBundle& presets = *wxGetApp().preset_bundle; + auto preset_name = [](const PresetCollection& collection) { + return collection.get_selected_preset_name() + (collection.get_edited_preset().is_dirty ? " (modified)" : ""); + }; + out << "Presets: " << preset_name(presets.printers) << ", " << preset_name(presets.prints) << '\n' + << "Scene: OrcaSliced Combo, " << PASS_FRAMES << " frames per pass\n"; + const GCodeViewer& gcode_viewer = wxGetApp().plater()->get_preview_canvas3D()->get_gcode_viewer(); + if (gcode_viewer.has_data()) + out << "Toolpaths: " << gcode_viewer.get_vertices_count() << " vertices, " << gcode_viewer.get_layers_count() << " layers\n"; + out << '\n'; + + std::vector stats; + for (const SceneResult& result : m_results) + stats.push_back(frame_time_stats(result.frame_ms)); + auto row = [&out, &stats](const char* label, double FrameTimeStats::*value) { + out << std::left << std::setw(22) << label << std::right; + for (const FrameTimeStats& s : stats) + out << std::setw(10) << s.*value; + out << '\n'; + }; + + out << std::fixed << std::setprecision(1) << std::setw(22) << ""; + for (const SceneResult& result : m_results) + out << std::right << std::setw(10) << result.name; + out << '\n'; + row("Average FPS", &FrameTimeStats::fps); + out << std::setprecision(2) << "Frame time (ms)\n"; + row(" average", &FrameTimeStats::average_ms); + row(" median", &FrameTimeStats::median_ms); + row(" 95th percentile", &FrameTimeStats::p95_ms); + row(" 99th percentile", &FrameTimeStats::p99_ms); + row(" maximum", &FrameTimeStats::max_ms); + + for (const SceneResult& result : m_results) { + out << "\nRender timings, " << result.name << " (ms per frame)\n"; + if (result.sections.empty()) { + out << " not supported by the graphics driver\n"; + continue; + } + out << std::setw(22) << "" << std::setw(10) << "CPU" << std::setw(10) << "GPU" << '\n'; + double cpu_ms = 0.0; + double gpu_ms = 0.0; + for (const FrameProfiler::Section& section : result.sections) { + out << " " << std::left << std::setw(20) << section.name << std::right << std::setw(10) << section.cpu_ms << std::setw(10) + << section.gpu_ms << '\n'; + cpu_ms += section.cpu_ms; + gpu_ms += section.gpu_ms; + } + out << " " << std::left << std::setw(20) << "total" << std::right << std::setw(10) << cpu_ms << std::setw(10) << gpu_ms << '\n'; + } + return out.str(); +} + +} // namespace + +void run_scene_benchmark() +{ + Plater* plater = wxGetApp().plater(); + if (plater == nullptr || !wxGetApp().is_editor()) + return; + if (s_benchmark != nullptr) { + if (s_benchmark->is_running()) { + s_benchmark->Raise(); + return; + } + s_benchmark->Close(); + } + + MessageDialog confirm(wxGetApp().mainframe, + _L("The benchmark replaces the current project with the OrcaSliced Combo and slices it. It turns the camera " + "around the model in Prepare and in Preview, then moves the layer slider through the sliced layers, timing " + "every frame, and shows the results.") + "\n\n" + + _L("It uses the current graphics settings and usually takes less than a minute. The main window stays " + "locked until it finishes."), + _L("Benchmark 3D Scene"), wxICON_INFORMATION | wxOK | wxCANCEL); + confirm.SetButtonLabel(wxID_OK, _L("Start"), true); + if (confirm.ShowModal() != wxID_OK || plater->new_project() == wxID_CANCEL) + return; + + const std::vector& models = MenuFactory::handy_models(); + const auto combo = std::find_if(models.begin(), models.end(), + [](const MenuFactory::HandyModel& model) { return std::strcmp(model.key, "orcasliced_combo") == 0; }); + MenuFactory::load_handy_model(size_t(combo - models.begin())); + (new SceneBenchmarkDialog())->Show(); +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/SceneBenchmark.hpp b/src/slic3r/GUI/SceneBenchmark.hpp new file mode 100644 index 0000000000..96c2df5b60 --- /dev/null +++ b/src/slic3r/GUI/SceneBenchmark.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace Slic3r { +namespace GUI { + +struct FrameTimeStats +{ + double fps{ 0.0 }; + double average_ms{ 0.0 }; + double median_ms{ 0.0 }; + double p95_ms{ 0.0 }; + double p99_ms{ 0.0 }; + double max_ms{ 0.0 }; +}; + +// Nearest-rank percentiles, so every value is a measured frame time. +FrameTimeStats frame_time_stats(std::vector frame_ms); + +// Loads the OrcaSliced Combo into a new project and turns the camera around it in Prepare, then in +// Preview once sliced, then moves the layer slider through the layers, and reports the frame times and +// render timings of the three scenes. +void run_scene_benchmark(); + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index 7a44305e4e..3ab630b404 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -16,6 +16,7 @@ #include "Jobs/BoostThreadWorker.hpp" #include "Jobs/PlaterWorker.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c60566d5c7..3050830d56 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -87,6 +87,7 @@ #include "slic3r/plugin/PluginConfig.hpp" #include "slic3r/plugin/PluginManager.hpp" #include "Plater.hpp" +#include "ParamsDialog.hpp" #include "MainFrame.hpp" #include "format.hpp" #include "UnsavedChangesDialog.hpp" @@ -3302,6 +3303,11 @@ void TabPrint::toggle_options() m_config_manipulation.toggle_print_fff_options(m_config, int(intptr_t(m_extruder_switch->GetClientData())), m_type < Preset::TYPE_COUNT); + if (m_type == Preset::TYPE_PLATE) { + const auto &printer_config = m_preset_bundle->printers.get_edited_preset().config; + toggle_option("curr_bed_type", m_preset_bundle->is_bbl_vendor() || printer_config.opt_bool("support_multi_bed_types")); + } + Field *field = m_active_page->get_field("support_style"); auto support_type = m_config->opt_enum("support_type"); if (auto choice = dynamic_cast(field)) { @@ -7024,6 +7030,15 @@ bool Tab::select_preset( } load_current_preset(); + // Wait for the settings dialog to close; its edits are still provisional. + if (printer_tab && is_selected) { + Plater *plater = wxGetApp().plater(); + ParamsDialog *dialog = wxGetApp().params_dialog(); + if (plater && !plater->is_loading_project() && + (!dialog || !dialog->IsShown())) + plater->normalize_bed_types(false); + } + { Slic3r::LifecycleEventContext ctx; ctx.name = preset_name; diff --git a/src/slic3r/GUI/TabButton.cpp b/src/slic3r/GUI/TabButton.cpp index 3469c9c980..f7c1a55d7c 100644 --- a/src/slic3r/GUI/TabButton.cpp +++ b/src/slic3r/GUI/TabButton.cpp @@ -2,6 +2,7 @@ #include "Widgets/Label.hpp" #include "slic3r/GUI/Widgets/StaticBox.hpp" +#include #include #include #include "slic3r/GUI/wxExtensions.hpp" diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 485ac48b99..ca20f4edb1 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/UpgradePanel.hpp b/src/slic3r/GUI/UpgradePanel.hpp index 2e0245e40e..c67ec0bbc3 100644 --- a/src/slic3r/GUI/UpgradePanel.hpp +++ b/src/slic3r/GUI/UpgradePanel.hpp @@ -2,6 +2,7 @@ #define slic3r_UpgradePanel_hpp_ #include "slic3r/GUI/wxExtensions.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/WebGuideDialog.cpp b/src/slic3r/GUI/WebGuideDialog.cpp index 4f1998ae94..350dd9d4be 100644 --- a/src/slic3r/GUI/WebGuideDialog.cpp +++ b/src/slic3r/GUI/WebGuideDialog.cpp @@ -71,6 +71,7 @@ #include #include "MainFrame.hpp" +#include "Plater.hpp" #include #include #include @@ -1161,6 +1162,8 @@ bool GuideFrame::run() app.app_config->set_legacy_datadir(false); app.update_mode(); + if (Plater *plater = app.plater()) + plater->normalize_bed_types(false); // BBS //app.obj_manipul()->update_ui_from_settings(); BOOST_LOG_TRIVIAL(info) << "GuideFrame applied"; diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 02fc7b0877..0101c83534 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -62,10 +62,10 @@ namespace GUI { WebViewPanel::WebViewPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { - wxString url = file_url_from_path(boost::filesystem::path(resources_dir()) / "web/homepage/index.html"); + m_home_url = file_url_from_path(boost::filesystem::path(resources_dir()) / "web/homepage/index.html"); wxString strlang = wxGetApp().current_language_code_safe(); if (strlang != "") - url += "?lang=" + strlang; + m_home_url += "?lang=" + strlang; wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); @@ -109,12 +109,8 @@ WebViewPanel::WebViewPanel(wxWindow *parent) m_info = new wxInfoBar(this); topsizer->Add(m_info, wxSizerFlags().Expand()); // Create the webview - m_browser = WebView::CreateWebView(this, url); - if (m_browser == nullptr) { - wxLogError("Could not init m_browser"); - return; - } - m_browser->Hide(); + create_browser(); + m_reset_on_show = WebView::NeedsRecreateOnShow(); SetSizer(topsizer); topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); @@ -264,6 +260,27 @@ WebViewPanel::~WebViewPanel() } +void WebViewPanel::create_browser() +{ + m_browser = WebView::CreateWebView(this, m_home_url); + m_browser->Hide(); +} + +void WebViewPanel::reset_browser() +{ + m_browser->Destroy(); // also removes it from the sizer + create_browser(); + GetSizer()->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); + Layout(); +} + +bool WebViewPanel::Show(bool show) +{ + if (show && std::exchange(m_reset_on_show, false)) + reset_browser(); + return wxPanel::Show(show); +} + void WebViewPanel::load_url(wxString& url) { this->Show(); diff --git a/src/slic3r/GUI/WebViewDialog.hpp b/src/slic3r/GUI/WebViewDialog.hpp index 96d18f23c0..8a4ecbf35d 100644 --- a/src/slic3r/GUI/WebViewDialog.hpp +++ b/src/slic3r/GUI/WebViewDialog.hpp @@ -113,9 +113,15 @@ public: int get_model_mall_detail_url(std::string *url, std::string id); void update_mode(); + + bool Show(bool show = true) override; private: + void create_browser(); + void reset_browser(); wxWebView* m_browser; + wxString m_home_url; + bool m_reset_on_show{false}; wxButton * m_button_stop; wxTextCtrl *m_url; #if !BBL_RELEASE_TO_PUBLIC diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 8a5f03b7ad..1abe045942 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -11,6 +11,7 @@ #include "slic3r/GUI/DeviceCore/DevFilaSystem.h" #include "slic3r/GUI/DeviceCore/DevFilaSwitch.h" +#include #include #include #include "slic3r/GUI/AmsMappingPopup.hpp" diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 4f44d7a1e7..f4c83667c2 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -9,6 +9,7 @@ #include "../DeviceManager.hpp" #include "slic3r/GUI/Event.hpp" #include "slic3r/GUI/AmsMappingPopup.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 96ca92494d..303b4221bb 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -12,6 +12,7 @@ #include "slic3r/GUI/DeviceCore/DevConfig.h" #include "slic3r/GUI/DeviceCore/DevManager.h" +#include #include #include #include "slic3r/GUI/Event.hpp" diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index e84ba64d98..55c0a3ca8d 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -9,6 +9,7 @@ #include "slic3r/GUI/Event.hpp" #include "slic3r/GUI/AmsMappingPopup.hpp" #include +#include #include #include #include "slic3r/GUI/DeviceCore/DevDefs.h" diff --git a/src/slic3r/GUI/Widgets/AnimaController.cpp b/src/slic3r/GUI/Widgets/AnimaController.cpp index a73c6d8e50..0267650e1d 100644 --- a/src/slic3r/GUI/Widgets/AnimaController.cpp +++ b/src/slic3r/GUI/Widgets/AnimaController.cpp @@ -1,5 +1,6 @@ #include "AnimaController.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/AnimaController.hpp b/src/slic3r/GUI/Widgets/AnimaController.hpp index e32eae6fb7..a1ddb7bc74 100644 --- a/src/slic3r/GUI/Widgets/AnimaController.hpp +++ b/src/slic3r/GUI/Widgets/AnimaController.hpp @@ -3,6 +3,7 @@ #include "../wxExtensions.hpp" #include "Label.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/Button.cpp b/src/slic3r/GUI/Widgets/Button.cpp index 7010dbd91c..54e720feb4 100644 --- a/src/slic3r/GUI/Widgets/Button.cpp +++ b/src/slic3r/GUI/Widgets/Button.cpp @@ -3,6 +3,7 @@ #include "slic3r/GUI/Widgets/StaticBox.hpp" #include +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/Button.hpp b/src/slic3r/GUI/Widgets/Button.hpp index cee2eb15b6..b4b1e24bb2 100644 --- a/src/slic3r/GUI/Widgets/Button.hpp +++ b/src/slic3r/GUI/Widgets/Button.hpp @@ -3,6 +3,7 @@ #include "../wxExtensions.hpp" #include "StaticBox.hpp" +#include #include #include "slic3r/GUI/Widgets/StateColor.hpp" #include diff --git a/src/slic3r/GUI/Widgets/CheckBox.cpp b/src/slic3r/GUI/Widgets/CheckBox.cpp index f019f18784..c36a53d8af 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.cpp +++ b/src/slic3r/GUI/Widgets/CheckBox.cpp @@ -1,6 +1,7 @@ #include "CheckBox.hpp" #include "../wxExtensions.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/CheckBox.hpp b/src/slic3r/GUI/Widgets/CheckBox.hpp index 3ad3dac2c4..bab691eb53 100644 --- a/src/slic3r/GUI/Widgets/CheckBox.hpp +++ b/src/slic3r/GUI/Widgets/CheckBox.hpp @@ -3,6 +3,7 @@ #include "../wxExtensions.hpp" +#include #include #include diff --git a/src/slic3r/GUI/Widgets/CheckList.cpp b/src/slic3r/GUI/Widgets/CheckList.cpp index 2b8dcac75e..a9c5c15be4 100644 --- a/src/slic3r/GUI/Widgets/CheckList.cpp +++ b/src/slic3r/GUI/Widgets/CheckList.cpp @@ -2,6 +2,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/I18N.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/CheckList.hpp b/src/slic3r/GUI/Widgets/CheckList.hpp index 9e5ae4c9e1..5518b10fd0 100644 --- a/src/slic3r/GUI/Widgets/CheckList.hpp +++ b/src/slic3r/GUI/Widgets/CheckList.hpp @@ -6,6 +6,7 @@ #include "Label.hpp" #include "TextInput.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 7d507789f5..20998eda0a 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/ComboBox.hpp b/src/slic3r/GUI/Widgets/ComboBox.hpp index f13bc876c4..1dae23b85d 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.hpp +++ b/src/slic3r/GUI/Widgets/ComboBox.hpp @@ -3,6 +3,7 @@ #include "TextInput.hpp" #include "DropDown.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/FanControl.cpp b/src/slic3r/GUI/Widgets/FanControl.cpp index 3ffaf59141..e4f039307b 100644 --- a/src/slic3r/GUI/Widgets/FanControl.cpp +++ b/src/slic3r/GUI/Widgets/FanControl.cpp @@ -6,6 +6,7 @@ #include "../MsgDialog.hpp" #include "json_diff.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/FanControl.hpp b/src/slic3r/GUI/Widgets/FanControl.hpp index b97c9a4d27..e5eb49ed45 100644 --- a/src/slic3r/GUI/Widgets/FanControl.hpp +++ b/src/slic3r/GUI/Widgets/FanControl.hpp @@ -9,6 +9,7 @@ #include "../SelectMachine.hpp" #include "../DeviceManager.hpp" #include "slic3r/GUI/Event.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/FilamentLoad.cpp b/src/slic3r/GUI/Widgets/FilamentLoad.cpp index 712c103826..11541a95a3 100644 --- a/src/slic3r/GUI/Widgets/FilamentLoad.cpp +++ b/src/slic3r/GUI/Widgets/FilamentLoad.cpp @@ -5,6 +5,7 @@ #include "../GUI_App.hpp" #include "../DeviceCore/DevFilaSystem.h" +#include #include #include #include "slic3r/GUI/Widgets/StepCtrl.hpp" diff --git a/src/slic3r/GUI/Widgets/FilamentLoad.hpp b/src/slic3r/GUI/Widgets/FilamentLoad.hpp index 257e92d21c..2c516987fc 100644 --- a/src/slic3r/GUI/Widgets/FilamentLoad.hpp +++ b/src/slic3r/GUI/Widgets/FilamentLoad.hpp @@ -8,6 +8,7 @@ #include "../DeviceManager.hpp" #include "slic3r/GUI/Event.hpp" #include "slic3r/GUI/AmsMappingPopup.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/ImageSwitchButton.cpp b/src/slic3r/GUI/Widgets/ImageSwitchButton.cpp index 9915795af5..80e7e85c66 100644 --- a/src/slic3r/GUI/Widgets/ImageSwitchButton.cpp +++ b/src/slic3r/GUI/Widgets/ImageSwitchButton.cpp @@ -4,6 +4,7 @@ #include "../wxExtensions.hpp" #include "slic3r/GUI/I18N.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/RadioBox.cpp b/src/slic3r/GUI/Widgets/RadioBox.cpp index 93e8f63b91..5b4af4e7b5 100644 --- a/src/slic3r/GUI/Widgets/RadioBox.cpp +++ b/src/slic3r/GUI/Widgets/RadioBox.cpp @@ -1,6 +1,7 @@ #include "RadioBox.hpp" #include "../wxExtensions.hpp" +#include #include #include diff --git a/src/slic3r/GUI/Widgets/RadioGroup.hpp b/src/slic3r/GUI/Widgets/RadioGroup.hpp index 6f25190431..ce6499c727 100644 --- a/src/slic3r/GUI/Widgets/RadioGroup.hpp +++ b/src/slic3r/GUI/Widgets/RadioGroup.hpp @@ -3,6 +3,7 @@ #include "../wxExtensions.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/RoundedRectangle.cpp b/src/slic3r/GUI/Widgets/RoundedRectangle.cpp index 5b5cd98076..d53f176ac3 100644 --- a/src/slic3r/GUI/Widgets/RoundedRectangle.cpp +++ b/src/slic3r/GUI/Widgets/RoundedRectangle.cpp @@ -1,5 +1,6 @@ #include "RoundedRectangle.hpp" #include "../wxExtensions.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/ScrolledWindow.hpp b/src/slic3r/GUI/Widgets/ScrolledWindow.hpp index a430dec423..cb497d1015 100644 --- a/src/slic3r/GUI/Widgets/ScrolledWindow.hpp +++ b/src/slic3r/GUI/Widgets/ScrolledWindow.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/SideButton.cpp b/src/slic3r/GUI/Widgets/SideButton.cpp index e9fe493621..54b75f1e14 100644 --- a/src/slic3r/GUI/Widgets/SideButton.cpp +++ b/src/slic3r/GUI/Widgets/SideButton.cpp @@ -3,6 +3,7 @@ #include #include "slic3r/GUI/Widgets/StateHandler.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/SideTools.hpp b/src/slic3r/GUI/Widgets/SideTools.hpp index 81c42ecef0..94af1e64c9 100644 --- a/src/slic3r/GUI/Widgets/SideTools.hpp +++ b/src/slic3r/GUI/Widgets/SideTools.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "Button.hpp" #include "Label.hpp" diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index 3077304947..80c000fe46 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/Widgets/StaticBox.hpp" #include #include "slic3r/GUI/Widgets/StateHandler.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/StaticBox.cpp b/src/slic3r/GUI/Widgets/StaticBox.cpp index 87a1d26827..5b18f733c9 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.cpp +++ b/src/slic3r/GUI/Widgets/StaticBox.cpp @@ -1,6 +1,7 @@ #include "StaticBox.hpp" #include "../GUI.hpp" #include +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/StaticBox.hpp b/src/slic3r/GUI/Widgets/StaticBox.hpp index b7662ff670..7c8d7c50ee 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.hpp +++ b/src/slic3r/GUI/Widgets/StaticBox.hpp @@ -4,6 +4,7 @@ #include "../wxExtensions.hpp" #include "StateHandler.hpp" +#include #include #include #include "slic3r/GUI/Widgets/StateColor.hpp" diff --git a/src/slic3r/GUI/Widgets/StaticLine.cpp b/src/slic3r/GUI/Widgets/StaticLine.cpp index f574a5b739..61602d520d 100644 --- a/src/slic3r/GUI/Widgets/StaticLine.cpp +++ b/src/slic3r/GUI/Widgets/StaticLine.cpp @@ -2,6 +2,7 @@ #include "Label.hpp" #include "StateColor.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/StepCtrl.cpp b/src/slic3r/GUI/Widgets/StepCtrl.cpp index 34ce8506de..e50db7c821 100644 --- a/src/slic3r/GUI/Widgets/StepCtrl.cpp +++ b/src/slic3r/GUI/Widgets/StepCtrl.cpp @@ -1,6 +1,7 @@ #include "StepCtrl.hpp" #include "Label.hpp" +#include #include #include "slic3r/GUI/Widgets/StaticBox.hpp" #include diff --git a/src/slic3r/GUI/Widgets/StepCtrl.hpp b/src/slic3r/GUI/Widgets/StepCtrl.hpp index d568443eaa..3b5abdab57 100644 --- a/src/slic3r/GUI/Widgets/StepCtrl.hpp +++ b/src/slic3r/GUI/Widgets/StepCtrl.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_StepCtrlBase_hpp_ #include "StaticBox.hpp" +#include #include #include "slic3r/GUI/Widgets/StateColor.hpp" #include diff --git a/src/slic3r/GUI/Widgets/SwitchButton.hpp b/src/slic3r/GUI/Widgets/SwitchButton.hpp index e4ef0005ad..24fcf59981 100644 --- a/src/slic3r/GUI/Widgets/SwitchButton.hpp +++ b/src/slic3r/GUI/Widgets/SwitchButton.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/TabCtrl.cpp b/src/slic3r/GUI/Widgets/TabCtrl.cpp index 66ff926d25..7c39cdd3f4 100644 --- a/src/slic3r/GUI/Widgets/TabCtrl.cpp +++ b/src/slic3r/GUI/Widgets/TabCtrl.cpp @@ -1,6 +1,7 @@ #include "TabCtrl.hpp" #include "slic3r/GUI/Widgets/StaticBox.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/TabCtrl.hpp b/src/slic3r/GUI/Widgets/TabCtrl.hpp index 80ac49da0a..f80a1aa08c 100644 --- a/src/slic3r/GUI/Widgets/TabCtrl.hpp +++ b/src/slic3r/GUI/Widgets/TabCtrl.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_TabCtrl_hpp_ #include "Button.hpp" +#include #include #include "slic3r/GUI/Widgets/StaticBox.hpp" #include diff --git a/src/slic3r/GUI/Widgets/TempInput.cpp b/src/slic3r/GUI/Widgets/TempInput.cpp index 99f50269ed..5890c702ac 100644 --- a/src/slic3r/GUI/Widgets/TempInput.cpp +++ b/src/slic3r/GUI/Widgets/TempInput.cpp @@ -5,6 +5,7 @@ #include "slic3r/GUI/Widgets/StaticBox.hpp" #include #include +#include #include #include "slic3r/GUI/Widgets/StateHandler.hpp" #include diff --git a/src/slic3r/GUI/Widgets/TempInput.hpp b/src/slic3r/GUI/Widgets/TempInput.hpp index 8560576b96..3ca55e558c 100644 --- a/src/slic3r/GUI/Widgets/TempInput.hpp +++ b/src/slic3r/GUI/Widgets/TempInput.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_TempInput_hpp_ #include "../wxExtensions.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/TextCtrl.h b/src/slic3r/GUI/Widgets/TextCtrl.h index 3f3ab2b4de..2d57c38146 100644 --- a/src/slic3r/GUI/Widgets/TextCtrl.h +++ b/src/slic3r/GUI/Widgets/TextCtrl.h @@ -1,3 +1,5 @@ +#include + #ifdef __WXMSW__ class TextCtrl : public wxTextCtrl { diff --git a/src/slic3r/GUI/Widgets/TextInput.cpp b/src/slic3r/GUI/Widgets/TextInput.cpp index 0ed38ff8de..e3670cbaed 100644 --- a/src/slic3r/GUI/Widgets/TextInput.cpp +++ b/src/slic3r/GUI/Widgets/TextInput.cpp @@ -7,6 +7,7 @@ #include #include #include "slic3r/GUI/Widgets/StateHandler.hpp" +#include #include #include #include diff --git a/src/slic3r/GUI/Widgets/WebView.cpp b/src/slic3r/GUI/Widgets/WebView.cpp index 9a4d5f90b0..c446875d1f 100644 --- a/src/slic3r/GUI/Widgets/WebView.cpp +++ b/src/slic3r/GUI/Widgets/WebView.cpp @@ -381,6 +381,17 @@ void WebView::MarkScriptMessageHandlerAdded(wxWebView * webView) if (WebViewRef *ref = webview_ref(webView)) ref->m_script_handler_added = true; } + +bool WebView::NeedsRecreateOnShow() +{ + const bool recreating = Slic3r::GUI::wxGetApp().is_recreating_gui(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": is_recreating_gui = " << recreating; +#ifdef __WIN32__ + return recreating; +#else + return false; +#endif +} #if wxUSE_WEBVIEW_EDGE bool WebView::CheckWebViewRuntime() { diff --git a/src/slic3r/GUI/Widgets/WebView.hpp b/src/slic3r/GUI/Widgets/WebView.hpp index 2dc126643d..0172f3f8ac 100644 --- a/src/slic3r/GUI/Widgets/WebView.hpp +++ b/src/slic3r/GUI/Widgets/WebView.hpp @@ -23,6 +23,10 @@ public: // Marks "wx" as registered so CreateWebView's deferred add skips the duplicate. static void MarkScriptMessageHandlerAdded(wxWebView * webView); + // On Windows, a WebView2 backend created during a GUI rebuild (language switch) can come up + // ignoring every navigation. A panel that gets true here recreates its view on first Show(). + static bool NeedsRecreateOnShow(); + static void RecreateAll(); }; diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 91944cfc78..6f6af5f59d 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -1,8 +1,16 @@ #ifndef _WIPE_TOWER_DIALOG_H_ #define _WIPE_TOWER_DIALOG_H_ +#include +#include +#include +#include #include +#include +#include +#include #include +#include "libslic3r/FlushVolCalc.hpp" #include "libslic3r/PrintConfig.hpp" #include "Widgets/SpinInput.hpp" diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp index 48ea425cf0..24abe219bc 100644 --- a/src/slic3r/GUI/calib_dlg.cpp +++ b/src/slic3r/GUI/calib_dlg.cpp @@ -6,6 +6,7 @@ #include #include #include "slic3r/GUI/Widgets/CheckBox.hpp" +#include #include #include "libslic3r/Config.hpp" #include diff --git a/src/slic3r/GUI/calib_dlg.hpp b/src/slic3r/GUI/calib_dlg.hpp index da6e9ee7c5..81d6b15200 100644 --- a/src/slic3r/GUI/calib_dlg.hpp +++ b/src/slic3r/GUI/calib_dlg.hpp @@ -13,6 +13,7 @@ #include "Widgets/RadioGroup.hpp" #include "GUI_App.hpp" #include "wx/hyperlink.h" +#include #include #include #include diff --git a/src/slic3r/Utils/3DPrinterOS.cpp b/src/slic3r/Utils/3DPrinterOS.cpp old mode 100755 new mode 100644 index 081afb667c..29b6bd63f8 --- a/src/slic3r/Utils/3DPrinterOS.cpp +++ b/src/slic3r/Utils/3DPrinterOS.cpp @@ -1,7 +1,12 @@ #include "3DPrinterOS.hpp" #include +#include "slic3r/GUI/Widgets/DropDown.hpp" +#include +#include +#include #include +#include #include #include #include @@ -11,12 +16,16 @@ #include #include +#include +#include +#include #include #include #include #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/I18N.hpp" @@ -30,6 +39,8 @@ #include "Http.hpp" #include +#include +#include using json = nlohmann::json; diff --git a/src/slic3r/Utils/3DPrinterOS.hpp b/src/slic3r/Utils/3DPrinterOS.hpp old mode 100755 new mode 100644 index 8c8e4ca6dc..02cc81ee6f --- a/src/slic3r/Utils/3DPrinterOS.hpp +++ b/src/slic3r/Utils/3DPrinterOS.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_3DPrinterOS_hpp_ #define slic3r_3DPrinterOS_hpp_ +#include #include #include #include diff --git a/src/slic3r/Utils/ASCIIFolding.cpp b/src/slic3r/Utils/ASCIIFolding.cpp index 016c30fcde..acf6f96fc9 100644 --- a/src/slic3r/Utils/ASCIIFolding.cpp +++ b/src/slic3r/Utils/ASCIIFolding.cpp @@ -1,10 +1,13 @@ #include "ASCIIFolding.hpp" +#include +#include #include #include #include #include #include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/AstroBox.cpp b/src/slic3r/Utils/AstroBox.cpp index 61f9f96c33..6904b56920 100644 --- a/src/slic3r/Utils/AstroBox.cpp +++ b/src/slic3r/Utils/AstroBox.cpp @@ -1,6 +1,7 @@ #include "AstroBox.hpp" #include +#include #include #include #include @@ -9,8 +10,11 @@ #include #include +#include #include +#include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI.hpp" diff --git a/src/slic3r/Utils/AstroBox.hpp b/src/slic3r/Utils/AstroBox.hpp index 72ab273228..04bbb00b67 100644 --- a/src/slic3r/Utils/AstroBox.hpp +++ b/src/slic3r/Utils/AstroBox.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_AstroBox_hpp_ #define slic3r_AstroBox_hpp_ +#include #include #include #include diff --git a/src/slic3r/Utils/BBLCloudServiceAgent.cpp b/src/slic3r/Utils/BBLCloudServiceAgent.cpp index 801ad1cf57..8943a01914 100644 --- a/src/slic3r/Utils/BBLCloudServiceAgent.cpp +++ b/src/slic3r/Utils/BBLCloudServiceAgent.cpp @@ -2,12 +2,21 @@ #include "BBLNetworkPlugin.hpp" #include +#include "CloudProvider.hpp" #include "Http.hpp" +#include "bambu_networking.hpp" +#include "ICloudServiceAgent.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include +#include +#include "libslic3r/ProjectTask.hpp" #include #include #include +#include +#include +#include using json = nlohmann::json; diff --git a/src/slic3r/Utils/BBLCloudServiceAgent.hpp b/src/slic3r/Utils/BBLCloudServiceAgent.hpp index 9f03f0b839..8ca07377ee 100644 --- a/src/slic3r/Utils/BBLCloudServiceAgent.hpp +++ b/src/slic3r/Utils/BBLCloudServiceAgent.hpp @@ -1,9 +1,14 @@ #ifndef __BBL_CLOUD_SERVICE_AGENT_HPP__ #define __BBL_CLOUD_SERVICE_AGENT_HPP__ +#include "CloudProvider.hpp" #include "ICloudServiceAgent.hpp" +#include "bambu_networking.hpp" +#include +#include "libslic3r/ProjectTask.hpp" #include #include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/BBLNetworkPlugin.cpp b/src/slic3r/Utils/BBLNetworkPlugin.cpp index d795abf354..94ac57aaf0 100644 --- a/src/slic3r/Utils/BBLNetworkPlugin.cpp +++ b/src/slic3r/Utils/BBLNetworkPlugin.cpp @@ -1,11 +1,22 @@ #include "BBLNetworkPlugin.hpp" #include "NetworkAgent.hpp" +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include "bambu_networking.hpp" +#include +#include +#include #include "libslic3r/Utils.hpp" #include "slic3r/Utils/FileTransferUtils.hpp" diff --git a/src/slic3r/Utils/BBLNetworkPlugin.hpp b/src/slic3r/Utils/BBLNetworkPlugin.hpp index 3788568e37..8541f90bce 100644 --- a/src/slic3r/Utils/BBLNetworkPlugin.hpp +++ b/src/slic3r/Utils/BBLNetworkPlugin.hpp @@ -3,6 +3,7 @@ #include "bambu_networking.hpp" #include "libslic3r/ProjectTask.hpp" +#include "libslic3r/AppConfig.hpp" #include #include #include diff --git a/src/slic3r/Utils/BBLPrinterAgent.cpp b/src/slic3r/Utils/BBLPrinterAgent.cpp index 4e2015d5d7..0e468b642b 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.cpp +++ b/src/slic3r/Utils/BBLPrinterAgent.cpp @@ -3,6 +3,7 @@ #include "IPrinterAgent.hpp" #include "NetworkAgentFactory.hpp" #include "NetworkAgent.hpp" +#include "bambu_networking.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/DeviceCore/DevManager.h" @@ -10,9 +11,14 @@ #include #include #include +#include +#include #include #include #include +#include +#include +#include using json = nlohmann::json; #include diff --git a/src/slic3r/Utils/BBLPrinterAgent.hpp b/src/slic3r/Utils/BBLPrinterAgent.hpp index 4398602976..89315219c0 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.hpp +++ b/src/slic3r/Utils/BBLPrinterAgent.hpp @@ -3,9 +3,12 @@ #include "IPrinterAgent.hpp" #include "ICloudServiceAgent.hpp" +#include "bambu_networking.hpp" +#include #include #include #include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/Bonjour.cpp b/src/slic3r/Utils/Bonjour.cpp index 0bff5b526c..e67d3f0240 100644 --- a/src/slic3r/Utils/Bonjour.cpp +++ b/src/slic3r/Utils/Bonjour.cpp @@ -1,8 +1,29 @@ #include "Bonjour.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/slic3r/Utils/Bonjour.hpp b/src/slic3r/Utils/Bonjour.hpp index 3ef8f0e1a2..e267575f74 100644 --- a/src/slic3r/Utils/Bonjour.hpp +++ b/src/slic3r/Utils/Bonjour.hpp @@ -1,8 +1,16 @@ #ifndef slic3r_Bonjour_hpp_ #define slic3r_Bonjour_hpp_ +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -13,6 +21,8 @@ #include #include #include +#include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 462f8c2712..82686cb7c7 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -6,6 +6,7 @@ #include "NetworkAgent.hpp" #include "../GUI/Jobs/ProgressIndicator.hpp" #include "../GUI/PartPlate.hpp" +#include "json_diff.hpp" #include "libslic3r/CutUtils.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Utils.hpp" @@ -22,6 +23,41 @@ #include "../GUI/DeviceCore/DevStorage.h" #include "libslic3r/FlushVolCalc.hpp" #include "../GUI/Plater.hpp" +#include +#include "slic3r/GUI/Jobs/Worker.hpp" +#include +#include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Flow.hpp" +#include +#include "libslic3r/ParameterUtils.hpp" +#include +#include +#include +#include "libslic3r/calib.hpp" +#include +#include "libslic3r/CommonDefs.hpp" +#include +#include +#include "libslic3r/Point.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/Format/bbs_3mf.hpp" +#include "libslic3r/Semver.hpp" +#include +#include "libslic3r/BoundingBox.hpp" +#include +#include "libslic3r/libslic3r.h" +#include "slic3r/GUI/DeviceCore/DevDefs.h" +#include "libslic3r/PrintBase.hpp" +#include "libslic3r/GCode/ThumbnailData.hpp" +#include "libslic3r/ProjectTask.hpp" +#include "slic3r/GUI/3DScene.hpp" +#include "libslic3r/Color.hpp" +#include "slic3r/GUI/GLShader.hpp" +#include "slic3r/GUI/OpenGLManager.hpp" +#include +#include "slic3r/GUI/Jobs/PrintJob.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/Utils/CalibUtils.hpp b/src/slic3r/Utils/CalibUtils.hpp index 1060a7d3d9..00b9e0020c 100644 --- a/src/slic3r/Utils/CalibUtils.hpp +++ b/src/slic3r/Utils/CalibUtils.hpp @@ -3,6 +3,11 @@ #include "../GUI/DeviceManager.hpp" #include "../GUI/Jobs/PrintJob.hpp" #include "slic3r/GUI/Jobs/Worker.hpp" +#include "libslic3r/PrintConfig.hpp" +#include +#include +#include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/ColorSpaceConvert.cpp b/src/slic3r/Utils/ColorSpaceConvert.cpp index 176bd29304..63ebc6b7b8 100644 --- a/src/slic3r/Utils/ColorSpaceConvert.cpp +++ b/src/slic3r/Utils/ColorSpaceConvert.cpp @@ -2,6 +2,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/slic3r/Utils/CrealityHostDiscovery.cpp b/src/slic3r/Utils/CrealityHostDiscovery.cpp index a3256794e2..556309ef30 100644 --- a/src/slic3r/Utils/CrealityHostDiscovery.cpp +++ b/src/slic3r/Utils/CrealityHostDiscovery.cpp @@ -4,9 +4,13 @@ #include "Http.hpp" #include +#include #include #include +#include +#include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/CrealityPrint.cpp b/src/slic3r/Utils/CrealityPrint.cpp index 323db56ff6..20e702ba54 100644 --- a/src/slic3r/Utils/CrealityPrint.cpp +++ b/src/slic3r/Utils/CrealityPrint.cpp @@ -1,6 +1,20 @@ #include "CrealityPrint.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -16,8 +30,11 @@ #include #include +#include +#include #include +#include "PrintHost.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -37,6 +54,7 @@ #include #include +#include using json = nlohmann::json; using std::to_string; diff --git a/src/slic3r/Utils/CrealityPrintAgent.cpp b/src/slic3r/Utils/CrealityPrintAgent.cpp index 4730903c59..10f6a51c5d 100644 --- a/src/slic3r/Utils/CrealityPrintAgent.cpp +++ b/src/slic3r/Utils/CrealityPrintAgent.cpp @@ -1,16 +1,23 @@ #include "CrealityPrintAgent.hpp" #include "CrealityPrint.hpp" +#include "MoonrakerPrinterAgent.hpp" +#include "IPrinterAgent.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI_App.hpp" #include +#include "libslic3r/Config.hpp" +#include #include #include #include #include #include +#include +#include +#include using json = nlohmann::json; diff --git a/src/slic3r/Utils/CrealityPrintAgent.hpp b/src/slic3r/Utils/CrealityPrintAgent.hpp index cf22d104ec..3b925c5d21 100644 --- a/src/slic3r/Utils/CrealityPrintAgent.hpp +++ b/src/slic3r/Utils/CrealityPrintAgent.hpp @@ -1,6 +1,7 @@ #ifndef __CREALITY_PRINT_AGENT_HPP__ #define __CREALITY_PRINT_AGENT_HPP__ +#include "IPrinterAgent.hpp" #include "MoonrakerPrinterAgent.hpp" #include diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index e26a493131..592e198808 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -1,6 +1,7 @@ #include "Duet.hpp" #include +#include #include #include #include @@ -8,14 +9,17 @@ #include #include +#include #include #include #include #include #include +#include #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/ESP3D.cpp b/src/slic3r/Utils/ESP3D.cpp index 5c10862118..0fc28cfcaf 100644 --- a/src/slic3r/Utils/ESP3D.cpp +++ b/src/slic3r/Utils/ESP3D.cpp @@ -12,14 +12,17 @@ #include #include +#include #include #include #include #include #include +#include #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/ElegooLink.cpp b/src/slic3r/Utils/ElegooLink.cpp index 64ff4a9455..fb74a384d1 100644 --- a/src/slic3r/Utils/ElegooLink.cpp +++ b/src/slic3r/Utils/ElegooLink.cpp @@ -1,8 +1,19 @@ #include "ElegooLink.hpp" #include +#include "libslic3r/Utils.hpp" +#include +#include +#include +#include +#include +#include +#include "libslic3r/PrintConfig.hpp" +#include #include #include +#include +#include #include #include #include @@ -20,8 +31,15 @@ #include +#include +#include +#include +#include #include +#include "OctoPrint.hpp" +#include "PrintHost.hpp" +#include "WebSocketClient.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/Utils/ElegooLink.hpp b/src/slic3r/Utils/ElegooLink.hpp index a60d2de1b3..9072fd5c78 100644 --- a/src/slic3r/Utils/ElegooLink.hpp +++ b/src/slic3r/Utils/ElegooLink.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_ElegooLink_hpp_ #define slic3r_ElegooLink_hpp_ +#include +#include +#include #include #include #include diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 5e777e2f29..5f03bd5df3 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -1,4 +1,19 @@ #include "EmbossStyleManager.hpp" +#include +#include +#include "libslic3r/TextConfiguration.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/Emboss.hpp" +#include "libslic3r/Point.hpp" +#include +#include +#include +#include +#include "libslic3r/EmbossShape.hpp" #include #include // Imgui texture #include // ImTextCharFromUtf8 @@ -12,6 +27,13 @@ #include #include +#include +#include +#include +#include "slic3r/GUI/GUI_Utils.hpp" +#include "slic3r/GUI/Jobs/Worker.hpp" +#include +#include "slic3r/GUI/OpenGLManager.hpp" using namespace Slic3r; using namespace Slic3r::Emboss; diff --git a/src/slic3r/Utils/EmbossStyleManager.hpp b/src/slic3r/Utils/EmbossStyleManager.hpp index 171f6fb1aa..76be39ac04 100644 --- a/src/slic3r/Utils/EmbossStyleManager.hpp +++ b/src/slic3r/Utils/EmbossStyleManager.hpp @@ -1,11 +1,15 @@ #ifndef slic3r_EmbossStyleManager_hpp_ #define slic3r_EmbossStyleManager_hpp_ +#include +#include +#include "libslic3r/Point.hpp" #include #include #include #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/FileHelp.cpp b/src/slic3r/Utils/FileHelp.cpp index bd67dab46f..12c1d5728f 100644 --- a/src/slic3r/Utils/FileHelp.cpp +++ b/src/slic3r/Utils/FileHelp.cpp @@ -1,6 +1,11 @@ #include "FileHelp.hpp" +#include #include +#include +#include #include +#include +#include namespace Slic3r { namespace Utils { diff --git a/src/slic3r/Utils/FileTransferUtils.cpp b/src/slic3r/Utils/FileTransferUtils.cpp index 822ccdf09d..e56cdc1551 100644 --- a/src/slic3r/Utils/FileTransferUtils.cpp +++ b/src/slic3r/Utils/FileTransferUtils.cpp @@ -1,3 +1,9 @@ +#include +#include +#include +#include +#include +#include #include #include #include "FileTransferUtils.hpp" diff --git a/src/slic3r/Utils/FixModelByCgal.cpp b/src/slic3r/Utils/FixModelByCgal.cpp index 9d973844bb..237a4b9dc6 100644 --- a/src/slic3r/Utils/FixModelByCgal.cpp +++ b/src/slic3r/Utils/FixModelByCgal.cpp @@ -1,14 +1,26 @@ #include "FixModelByCgal.hpp" +#include #include #include #include #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include "libslic3r/Exception.hpp" #include #include +#include "slic3r/GUI/Widgets/ProgressDialog.hpp" +#include #include #include +#include #include +#include #include "libslic3r/MeshBoolean.hpp" #include "libslic3r/Model.hpp" diff --git a/src/slic3r/Utils/FixModelByCgal.hpp b/src/slic3r/Utils/FixModelByCgal.hpp index 61c8c91087..03bec43f47 100644 --- a/src/slic3r/Utils/FixModelByCgal.hpp +++ b/src/slic3r/Utils/FixModelByCgal.hpp @@ -2,6 +2,7 @@ #define slic3r_GUI_Utils_FixModelByCgal_hpp_ #include +#include #include "../GUI/Widgets/ProgressDialog.hpp" namespace Slic3r { diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index f2d66fd012..557604cffc 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -7,14 +7,17 @@ #include #include +#include #include #include #include #include #include +#include #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/Flashforge.cpp b/src/slic3r/Utils/Flashforge.cpp index a042a889ae..5f639c3e5f 100644 --- a/src/slic3r/Utils/Flashforge.cpp +++ b/src/slic3r/Utils/Flashforge.cpp @@ -1,8 +1,22 @@ #include "Flashforge.hpp" #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include "libslic3r/Config.hpp" +#include +#include #include #include #include @@ -16,11 +30,14 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -28,6 +45,7 @@ #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/FontConfigHelp.cpp b/src/slic3r/Utils/FontConfigHelp.cpp index 15beca07ba..f3280ad83d 100644 --- a/src/slic3r/Utils/FontConfigHelp.cpp +++ b/src/slic3r/Utils/FontConfigHelp.cpp @@ -1,4 +1,11 @@ #include "FontConfigHelp.hpp" +#include +#include +#include +#include +#include +#include +#include #ifdef EXIST_FONT_CONFIG_INCLUDE diff --git a/src/slic3r/Utils/FontConfigHelp.hpp b/src/slic3r/Utils/FontConfigHelp.hpp index d2d7738767..ca69b7719e 100644 --- a/src/slic3r/Utils/FontConfigHelp.hpp +++ b/src/slic3r/Utils/FontConfigHelp.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_FontConfigHelp_hpp_ #define slic3r_FontConfigHelp_hpp_ +#include #ifdef __linux__ #define EXIST_FONT_CONFIG_INCLUDE #endif diff --git a/src/slic3r/Utils/HexFile.cpp b/src/slic3r/Utils/HexFile.cpp index a13fcab02b..76e1f998bf 100644 --- a/src/slic3r/Utils/HexFile.cpp +++ b/src/slic3r/Utils/HexFile.cpp @@ -1,9 +1,15 @@ #include "HexFile.hpp" +#include +#include +#include +#include #include #include #include #include +#include +#include namespace fs = boost::filesystem; namespace pt = boost::property_tree; diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 363ca0ecf6..552c0b6a39 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -1,8 +1,23 @@ #include "Http.hpp" +#include "libslic3r_version.h" +#include #include +#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include "libslic3r/Exception.hpp" +#include +#include #include #include #include @@ -14,6 +29,7 @@ #include #include +#include #ifdef OPENSSL_CERT_OVERRIDE #include diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index a44a95e605..d8fa012124 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -1,8 +1,10 @@ #ifndef __Http_hpp__ #define __Http_hpp__ +#include #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/InstanceID.cpp b/src/slic3r/Utils/InstanceID.cpp index d4a903e276..d683138e2e 100644 --- a/src/slic3r/Utils/InstanceID.cpp +++ b/src/slic3r/Utils/InstanceID.cpp @@ -1,7 +1,10 @@ #include "InstanceID.hpp" #include +#include +#include #include +#include #include #include #include diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index ced7af9c9f..6a27c7c7ce 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -12,14 +12,18 @@ #include #include +#include #include #include #include #include #include +#include #include #include +#include "TCPConsole.hpp" +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/MeshInspect.cpp b/src/slic3r/Utils/MeshInspect.cpp index 0a60358278..dd8e5c88a0 100644 --- a/src/slic3r/Utils/MeshInspect.cpp +++ b/src/slic3r/Utils/MeshInspect.cpp @@ -3,11 +3,17 @@ #include "libslic3r/LayOnFace.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" +#include #include #include #include #include +#include +#include +#include namespace Slic3r { namespace MeshInspect { diff --git a/src/slic3r/Utils/MeshInspect.hpp b/src/slic3r/Utils/MeshInspect.hpp index 0f53b41c4a..b908d568ba 100644 --- a/src/slic3r/Utils/MeshInspect.hpp +++ b/src/slic3r/Utils/MeshInspect.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/slic3r/Utils/Moonraker.cpp b/src/slic3r/Utils/Moonraker.cpp index 73fdb8486a..f8692a8bb8 100644 --- a/src/slic3r/Utils/Moonraker.cpp +++ b/src/slic3r/Utils/Moonraker.cpp @@ -1,12 +1,17 @@ #include "Moonraker.hpp" +#include #include #include #include #include #include +#include +#include +#include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI.hpp" diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp index 5d75955a1e..96570b656b 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp @@ -1,6 +1,7 @@ #include "MoonrakerPrinterAgent.hpp" #include "Http.hpp" #include "IPrinterAgent.hpp" +#include "bambu_networking.hpp" #include "libslic3r/Preset.hpp" #include "libslic3r/PresetBundle.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -11,18 +12,44 @@ #include "../GUI/DeviceCore/DevFirmware.h" #include "nlohmann/json.hpp" #include +#include +#include +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include #include #include #include #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include +#include namespace { diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.hpp b/src/slic3r/Utils/MoonrakerPrinterAgent.hpp index a25a088ada..a733d4dfb2 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.hpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.hpp @@ -3,7 +3,11 @@ #include "IPrinterAgent.hpp" #include "ICloudServiceAgent.hpp" +#include "bambu_networking.hpp" +#include +#include +#include #include #include #include @@ -11,6 +15,7 @@ #include #include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 1f7705658e..4e5154fd42 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -1,11 +1,24 @@ #include "NetworkAgent.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/ProjectTask.hpp" #include #include #include +#include +#include +#include +#include "CloudProvider.hpp" +#include "ICloudServiceAgent.hpp" +#include "ICameraSignalingChannel.hpp" #include "IPrinterAgent.hpp" #include "BBLNetworkPlugin.hpp" +#include "bambu_networking.hpp" namespace Slic3r { diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index f93178db8b..c7813f2bb7 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -1,12 +1,15 @@ #ifndef __NETWORK_Agent_HPP__ #define __NETWORK_Agent_HPP__ +#include "CloudProvider.hpp" +#include "ICameraSignalingChannel.hpp" #include "bambu_networking.hpp" #include "libslic3r/ProjectTask.hpp" #include "ICloudServiceAgent.hpp" #include "IPrinterAgent.hpp" +#include #include #include #include diff --git a/src/slic3r/Utils/NetworkAgentFactory.cpp b/src/slic3r/Utils/NetworkAgentFactory.cpp index e2e58b7510..3d87a3eec9 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.cpp +++ b/src/slic3r/Utils/NetworkAgentFactory.cpp @@ -1,4 +1,5 @@ #include "NetworkAgentFactory.hpp" +#include "CloudProvider.hpp" #include "IPrinterAgent.hpp" #include "ICloudServiceAgent.hpp" #include "BBLPrinterAgent.hpp" @@ -13,13 +14,18 @@ #include #include #include +#include #include +#include #include #include #include #include #include +#include +#include #include +#include namespace Slic3r { namespace { diff --git a/src/slic3r/Utils/NetworkAgentFactory.hpp b/src/slic3r/Utils/NetworkAgentFactory.hpp index a055b19493..0053a42466 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.hpp +++ b/src/slic3r/Utils/NetworkAgentFactory.hpp @@ -1,6 +1,7 @@ #ifndef __NETWORK_AGENT_FACTORY_HPP__ #define __NETWORK_AGENT_FACTORY_HPP__ +#include "CloudProvider.hpp" #include "ICloudServiceAgent.hpp" #include "IPrinterAgent.hpp" #include "NetworkAgent.hpp" @@ -11,6 +12,7 @@ #include #include #include +#include #include namespace Slic3r { diff --git a/src/slic3r/Utils/Obico.cpp b/src/slic3r/Utils/Obico.cpp index 92d748b496..9dabd91467 100644 --- a/src/slic3r/Utils/Obico.cpp +++ b/src/slic3r/Utils/Obico.cpp @@ -1,6 +1,8 @@ #include "Obico.hpp" #include +#include "libslic3r/Exception.hpp" +#include #include #include #include @@ -14,8 +16,12 @@ #include #include +#include +#include #include +#include +#include "PrintHost.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index fa57b7b527..a39b300d79 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -1,6 +1,10 @@ #include "OctoPrint.hpp" #include +#include +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Exception.hpp" #include #include #include @@ -14,8 +18,14 @@ #include +#include +#include +#include +#include #include +#include +#include "PrintHost.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index ad7e8c411e..b2dbe11cff 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_OctoPrint_hpp_ #define slic3r_OctoPrint_hpp_ +#include #include #include #include diff --git a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp index 1618bff548..2cebdb8ab9 100644 --- a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp +++ b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp @@ -1,21 +1,37 @@ #include "OrcaCloudServiceAgent.hpp" +#include "CloudProvider.hpp" #include "Http.hpp" +#include "bambu_networking.hpp" +#include "ICloudServiceAgent.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "libslic3r/AppConfig.hpp" +#include #include +#include +#include #include #include +#include #include +#include #include #include #include +#include +#include #include +#include #include +#include #include +#include +#include "libslic3r/Preset.hpp" +#include "libslic3r/ProjectTask.hpp" #include +#include #include #include #include @@ -32,7 +48,11 @@ #include #include +#include +#include +#include #include +#include #include #include #include diff --git a/src/slic3r/Utils/OrcaCloudServiceAgent.hpp b/src/slic3r/Utils/OrcaCloudServiceAgent.hpp index 7e060da84a..458aa55fcd 100644 --- a/src/slic3r/Utils/OrcaCloudServiceAgent.hpp +++ b/src/slic3r/Utils/OrcaCloudServiceAgent.hpp @@ -1,9 +1,12 @@ #ifndef __ORCA_CLOUD_SERVICE_AGENT_HPP__ #define __ORCA_CLOUD_SERVICE_AGENT_HPP__ +#include "CloudProvider.hpp" #include "ICameraSignalingChannel.hpp" #include "ICloudServiceAgent.hpp" +#include "bambu_networking.hpp" #include +#include "libslic3r/ProjectTask.hpp" #include #include #include @@ -13,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/src/slic3r/Utils/OrcaPrinterAgent.cpp b/src/slic3r/Utils/OrcaPrinterAgent.cpp index 987cc0efdb..cb8b38acc8 100644 --- a/src/slic3r/Utils/OrcaPrinterAgent.cpp +++ b/src/slic3r/Utils/OrcaPrinterAgent.cpp @@ -1,6 +1,11 @@ #include "OrcaPrinterAgent.hpp" #include "IPrinterAgent.hpp" #include "NetworkAgentFactory.hpp" +#include +#include +#include +#include +#include "bambu_networking.hpp" namespace Slic3r { diff --git a/src/slic3r/Utils/OrcaPrinterAgent.hpp b/src/slic3r/Utils/OrcaPrinterAgent.hpp index 7d2a75fe0f..a56b2c8dda 100644 --- a/src/slic3r/Utils/OrcaPrinterAgent.hpp +++ b/src/slic3r/Utils/OrcaPrinterAgent.hpp @@ -3,6 +3,7 @@ #include "IPrinterAgent.hpp" #include "ICloudServiceAgent.hpp" +#include "bambu_networking.hpp" #include #include #include diff --git a/src/slic3r/Utils/PaintCLI.cpp b/src/slic3r/Utils/PaintCLI.cpp index d99dc0b450..2bf2b9728a 100644 --- a/src/slic3r/Utils/PaintCLI.cpp +++ b/src/slic3r/Utils/PaintCLI.cpp @@ -5,9 +5,13 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleSelector.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" +#include #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 5bbe779970..1df0edf8fa 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -1,12 +1,23 @@ #include "PresetUpdater.hpp" #include +#include +#include +#include #include +#include #include #include #include +#include #include #include +#include "libslic3r/Exception.hpp" +#include +#include +#include "libslic3r/AppConfig.hpp" +#include "libslic3r/Preset.hpp" +#include "libslic3r/Config.hpp" #include #include #include @@ -24,8 +35,10 @@ #include #include +#include #include +#include "json_diff.hpp" #include "libslic3r/libslic3r.h" #include "libslic3r/format.hpp" #include "libslic3r/Utils.hpp" diff --git a/src/slic3r/Utils/PresetUpdater.hpp b/src/slic3r/Utils/PresetUpdater.hpp index ccb0902fd5..22571e52d9 100644 --- a/src/slic3r/Utils/PresetUpdater.hpp +++ b/src/slic3r/Utils/PresetUpdater.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 2eeb78a975..2b3c4d181d 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -1,5 +1,17 @@ #include "PrintHost.hpp" +#include +#include "libslic3r/Config.hpp" +#include +#include +#include "slic3r/GUI/Gizmos/GLGizmoBase.hpp" +#include +#include +#include +#include +#include +#include "libslic3r/LifecycleEvents.hpp" +#include "slic3r/GUI/GUI_App.hpp" #include #include #include @@ -11,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index cf197ede07..771eb7732a 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -1,12 +1,14 @@ #ifndef slic3r_PrintHost_hpp_ #define slic3r_PrintHost_hpp_ +#include #include #include #include #include #include +#include #include #include diff --git a/src/slic3r/Utils/Process.cpp b/src/slic3r/Utils/Process.cpp index 96da521114..150e838489 100644 --- a/src/slic3r/Utils/Process.cpp +++ b/src/slic3r/Utils/Process.cpp @@ -1,5 +1,6 @@ #include "Process.hpp" +#include #include #include "../GUI/GUI.hpp" @@ -13,6 +14,11 @@ #include #include +#include +#include +#include +#include +#include // For starting another OrcaSlicer instance on OSX. // Fails to compile on Windows on the build server. diff --git a/src/slic3r/Utils/QidiPrinterAgent.cpp b/src/slic3r/Utils/QidiPrinterAgent.cpp index 4a90ec3771..06499e1092 100644 --- a/src/slic3r/Utils/QidiPrinterAgent.cpp +++ b/src/slic3r/Utils/QidiPrinterAgent.cpp @@ -1,13 +1,22 @@ #include "QidiPrinterAgent.hpp" #include "Http.hpp" +#include "MoonrakerPrinterAgent.hpp" +#include "IPrinterAgent.hpp" #include "libslic3r/PresetBundle.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "nlohmann/json.hpp" #include +#include +#include #include #include +#include "libslic3r/Preset.hpp" +#include #include +#include +#include +#include using json = nlohmann::json; diff --git a/src/slic3r/Utils/QidiPrinterAgent.hpp b/src/slic3r/Utils/QidiPrinterAgent.hpp index ce7b4cda0d..5f4cfc3a7e 100644 --- a/src/slic3r/Utils/QidiPrinterAgent.hpp +++ b/src/slic3r/Utils/QidiPrinterAgent.hpp @@ -1,6 +1,7 @@ #ifndef __QIDI_PRINTER_AGENT_HPP__ #define __QIDI_PRINTER_AGENT_HPP__ +#include "IPrinterAgent.hpp" #include "MoonrakerPrinterAgent.hpp" #include diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp index 62c7a922d7..dba5ae1a54 100644 --- a/src/slic3r/Utils/RaycastManager.cpp +++ b/src/slic3r/Utils/RaycastManager.cpp @@ -1,5 +1,17 @@ #include "RaycastManager.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/AABBMesh.hpp" +#include +#include "libslic3r/Point.hpp" +#include +#include +#include +#include +#include +#include "slic3r/GUI/SceneRaycaster.hpp" +#include "slic3r/GUI/3DScene.hpp" #include +#include #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Camera.hpp" diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp index 4e143ba5dd..0c62ecaacc 100644 --- a/src/slic3r/Utils/RaycastManager.hpp +++ b/src/slic3r/Utils/RaycastManager.hpp @@ -1,8 +1,13 @@ #ifndef slic3r_RaycastManager_hpp_ #define slic3r_RaycastManager_hpp_ +#include +#include +#include #include // unique_ptr #include +#include +#include #include "libslic3r/AABBMesh.hpp" // Structure to cast rays #include "libslic3r/Point.hpp" // Transform3d #include "libslic3r/ObjectID.hpp" diff --git a/src/slic3r/Utils/Repetier.cpp b/src/slic3r/Utils/Repetier.cpp index a524f29b71..ae269cac4f 100644 --- a/src/slic3r/Utils/Repetier.cpp +++ b/src/slic3r/Utils/Repetier.cpp @@ -1,6 +1,9 @@ #include "Repetier.hpp" #include +#include +#include "libslic3r/Exception.hpp" +#include #include #include #include @@ -10,9 +13,13 @@ #include #include +#include +#include #include +#include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI.hpp" diff --git a/src/slic3r/Utils/Serial.cpp b/src/slic3r/Utils/Serial.cpp index f8c03ceb26..2b64330826 100644 --- a/src/slic3r/Utils/Serial.cpp +++ b/src/slic3r/Utils/Serial.cpp @@ -3,7 +3,19 @@ #include "libslic3r/Exception.hpp" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include diff --git a/src/slic3r/Utils/Serial.hpp b/src/slic3r/Utils/Serial.hpp index 8bad75b315..c5c4d19fc5 100644 --- a/src/slic3r/Utils/Serial.hpp +++ b/src/slic3r/Utils/Serial.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_GUI_Utils_Serial_hpp_ #define slic3r_GUI_Utils_Serial_hpp_ +#include +#include +#include #include #include #include diff --git a/src/slic3r/Utils/SimplyPrint.cpp b/src/slic3r/Utils/SimplyPrint.cpp index a3edfd98ee..5c68878986 100644 --- a/src/slic3r/Utils/SimplyPrint.cpp +++ b/src/slic3r/Utils/SimplyPrint.cpp @@ -1,10 +1,36 @@ #include "SimplyPrint.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include "slic3r/GUI/Jobs/OAuthJob.hpp" +#include +#include +#include +#include "PrintHost.hpp" #include "nlohmann/json.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/SimplyPrint.hpp b/src/slic3r/Utils/SimplyPrint.hpp index 3804324724..83ff64378e 100644 --- a/src/slic3r/Utils/SimplyPrint.hpp +++ b/src/slic3r/Utils/SimplyPrint.hpp @@ -3,6 +3,11 @@ #include "PrintHost.hpp" #include "slic3r/GUI/Jobs/OAuthJob.hpp" +#include +#include +#include +#include +#include namespace Slic3r { diff --git a/src/slic3r/Utils/SnapmakerPrinterAgent.cpp b/src/slic3r/Utils/SnapmakerPrinterAgent.cpp index 6039eb260f..a237d1b2b1 100644 --- a/src/slic3r/Utils/SnapmakerPrinterAgent.cpp +++ b/src/slic3r/Utils/SnapmakerPrinterAgent.cpp @@ -1,10 +1,17 @@ #include "SnapmakerPrinterAgent.hpp" #include "Http.hpp" +#include "MoonrakerPrinterAgent.hpp" +#include "IPrinterAgent.hpp" #include "libslic3r/PresetBundle.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "nlohmann/json.hpp" #include +#include +#include +#include "libslic3r/Preset.hpp" +#include +#include using json = nlohmann::json; diff --git a/src/slic3r/Utils/SnapmakerPrinterAgent.hpp b/src/slic3r/Utils/SnapmakerPrinterAgent.hpp index d49fe21239..39b642081b 100644 --- a/src/slic3r/Utils/SnapmakerPrinterAgent.hpp +++ b/src/slic3r/Utils/SnapmakerPrinterAgent.hpp @@ -1,5 +1,6 @@ #pragma once +#include "IPrinterAgent.hpp" #include "MoonrakerPrinterAgent.hpp" #include diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index 25802e3908..78d4624abc 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -1,14 +1,21 @@ +#include +#include #include +#include #include #include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index e94e130a9e..4ec766faa4 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -1,6 +1,9 @@ #ifndef slic3r_Utils_TCPConsole_hpp_ #define slic3r_Utils_TCPConsole_hpp_ +#include +#include +#include #include #include #include @@ -8,6 +11,7 @@ #include #include #include "SerialMessage.hpp" +#include "SerialMessageType.hpp" namespace Slic3r { namespace Utils { diff --git a/src/slic3r/Utils/UltiMaker.cpp b/src/slic3r/Utils/UltiMaker.cpp index badb69d209..fefd8ec786 100644 --- a/src/slic3r/Utils/UltiMaker.cpp +++ b/src/slic3r/Utils/UltiMaker.cpp @@ -1,6 +1,10 @@ #include "UltiMaker.hpp" #include +#include +#include +#include +#include #include #include #include @@ -8,14 +12,20 @@ #include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include +#include "PrintHost.hpp" #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index 8e7bd703c3..2cdefefbb4 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -1,9 +1,18 @@ #include "UndoRedo.hpp" #include +#include +#include +#include +#include #include #include +#include +#include "libslic3r/Exception.hpp" #include +#include +#include +#include #include #include #include @@ -14,6 +23,8 @@ #include #include #include +#include +#include #define CEREAL_FUTURE_EXPERIMENTAL #include diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp index 9042d60a4b..4a5aaca9c1 100644 --- a/src/slic3r/Utils/UndoRedo.hpp +++ b/src/slic3r/Utils/UndoRedo.hpp @@ -2,8 +2,11 @@ #define slic3r_Utils_UndoRedo_hpp_ #include +#include +#include #include #include +#include #include #include diff --git a/src/slic3r/Utils/WebSocketClient.hpp b/src/slic3r/Utils/WebSocketClient.hpp index 2660231794..f85c3e15fa 100644 --- a/src/slic3r/Utils/WebSocketClient.hpp +++ b/src/slic3r/Utils/WebSocketClient.hpp @@ -1,9 +1,18 @@ #ifndef _WEB_SOCKET_CLIENT_HPP_ #define _WEB_SOCKET_CLIENT_HPP_ +#include +#include #include +#include +#include +#include #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/src/slic3r/Utils/WxFontUtils.cpp b/src/slic3r/Utils/WxFontUtils.cpp index a536e65912..4d28fa54c0 100644 --- a/src/slic3r/Utils/WxFontUtils.cpp +++ b/src/slic3r/Utils/WxFontUtils.cpp @@ -1,6 +1,15 @@ #include "WxFontUtils.hpp" #include +#include #include +#include +#include "libslic3r/Emboss.hpp" +#include +#include "libslic3r/TextConfiguration.hpp" +#include +#include +#include +#include #include "libslic3r/Utils.hpp" #if defined(__APPLE__) diff --git a/src/slic3r/Utils/WxFontUtils.hpp b/src/slic3r/Utils/WxFontUtils.hpp index 51c8605ff0..7a9448fbe9 100644 --- a/src/slic3r/Utils/WxFontUtils.hpp +++ b/src/slic3r/Utils/WxFontUtils.hpp @@ -1,8 +1,10 @@ #ifndef slic3r_WxFontUtils_hpp_ #define slic3r_WxFontUtils_hpp_ +#include "libslic3r/TextConfiguration.hpp" #include #include +#include #include #include #include diff --git a/src/slic3r/Utils/bambu_networking.hpp b/src/slic3r/Utils/bambu_networking.hpp index c514daffff..30c33c6c73 100644 --- a/src/slic3r/Utils/bambu_networking.hpp +++ b/src/slic3r/Utils/bambu_networking.hpp @@ -1,6 +1,7 @@ #ifndef __BAMBU_NETWORKING_HPP__ #define __BAMBU_NETWORKING_HPP__ +#include #include #include #include diff --git a/src/slic3r/Utils/minilzo_extension.cpp b/src/slic3r/Utils/minilzo_extension.cpp index 07031cd1af..eca2ee0a7f 100644 --- a/src/slic3r/Utils/minilzo_extension.cpp +++ b/src/slic3r/Utils/minilzo_extension.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp b/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp index df1b495bff..a35aceafeb 100644 --- a/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp +++ b/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp @@ -8,8 +8,16 @@ #include "slic3r/GUI/Widgets/Label.hpp" #include "slic3r/GUI/Widgets/LabeledStaticBox.hpp" +#include +#include +#include +#include +#include +#include +#include #include #include +#include wxString CustomWidgetsPlugin::GetName() const { diff --git a/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp b/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp index 083ed8a74c..1430677a7d 100644 --- a/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp +++ b/src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp @@ -1,6 +1,10 @@ #pragma once +#include #include +#include +#include +#include class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin { diff --git a/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp b/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp index f52a5d4313..ee81e3e7fa 100644 --- a/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp +++ b/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp @@ -2,8 +2,15 @@ #include "slic3r/GUI/GUI_Utils.hpp" // DPIFrame, DPIDialog, DPIAware

+#include +#include +#include +#include +#include +#include #include #include +#include namespace { diff --git a/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp b/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp index 5d78342967..d1df7fe4aa 100644 --- a/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp +++ b/src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp @@ -1,6 +1,10 @@ #pragma once +#include #include +#include +#include +#include class DPIAwarePlugin : public wxInspector::wxInspectorPlugin { diff --git a/src/slic3r/plugin/CloudPluginService.cpp b/src/slic3r/plugin/CloudPluginService.cpp index 6b72da3293..b6af332dbc 100644 --- a/src/slic3r/plugin/CloudPluginService.cpp +++ b/src/slic3r/plugin/CloudPluginService.cpp @@ -4,9 +4,13 @@ #include "slic3r/Utils/Http.hpp" #include +#include +#include #include #include #include +#include +#include #include #include #include diff --git a/src/slic3r/plugin/PluginAuditManager.cpp b/src/slic3r/plugin/PluginAuditManager.cpp index 4d69a4f761..bd75ad2459 100644 --- a/src/slic3r/plugin/PluginAuditManager.cpp +++ b/src/slic3r/plugin/PluginAuditManager.cpp @@ -3,24 +3,33 @@ #include "../Utils/OrcaCloudServiceAgent.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/libslic3r.h" // GCODEVIEWER_APP_KEY, and SLIC3R_APP_KEY via libslic3r_version.h +#include "libslic3r_version.h" #include +#include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include namespace Slic3r { diff --git a/src/slic3r/plugin/PluginAuditManager.hpp b/src/slic3r/plugin/PluginAuditManager.hpp index 153f9d6107..76ac5cdd18 100644 --- a/src/slic3r/plugin/PluginAuditManager.hpp +++ b/src/slic3r/plugin/PluginAuditManager.hpp @@ -2,6 +2,7 @@ #define slic3r_PluginAuditManager_hpp_ // Via pybind11 so this file requests the same python3xx.lib as everything else. +#include #include #include #include diff --git a/src/slic3r/plugin/PluginBindingUtils.hpp b/src/slic3r/plugin/PluginBindingUtils.hpp index 52050ed561..7572777c43 100644 --- a/src/slic3r/plugin/PluginBindingUtils.hpp +++ b/src/slic3r/plugin/PluginBindingUtils.hpp @@ -1,8 +1,11 @@ #pragma once +#include "libslic3r/libslic3r.h" #include #include #include "libslic3r/Config.hpp" // ConfigBase #include "libslic3r/Point.hpp" // Point/Point3 packing asserts, Vec3d, Transform3d +#include +#include #include #include #include diff --git a/src/slic3r/plugin/PluginConfig.cpp b/src/slic3r/plugin/PluginConfig.cpp index 14d24fabe1..685d295206 100644 --- a/src/slic3r/plugin/PluginConfig.cpp +++ b/src/slic3r/plugin/PluginConfig.cpp @@ -1,24 +1,38 @@ #include "PluginConfig.hpp" #include +#include #include #include #include +#include #include +#include "libslic3r/Preset.hpp" #include #include +#include +#include +#include +#include "libslic3r/Utils.hpp" +#include "libslic3r/libslic3r.h" #include #include #include #include +#include "slic3r/plugin/PluginDescriptor.hpp" #include #include #include #include #include +#include +#include +#include +#include #include +#include #include namespace Slic3r { diff --git a/src/slic3r/plugin/PluginConfig.hpp b/src/slic3r/plugin/PluginConfig.hpp index 523173af68..8f39b4a40e 100644 --- a/src/slic3r/plugin/PluginConfig.hpp +++ b/src/slic3r/plugin/PluginConfig.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/src/slic3r/plugin/PluginDescriptor.hpp b/src/slic3r/plugin/PluginDescriptor.hpp index b0d2d214c3..9e55a89e59 100644 --- a/src/slic3r/plugin/PluginDescriptor.hpp +++ b/src/slic3r/plugin/PluginDescriptor.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/src/slic3r/plugin/PluginFsUtils.cpp b/src/slic3r/plugin/PluginFsUtils.cpp index 4d6aabe3d3..e3b1bc3bee 100644 --- a/src/slic3r/plugin/PluginFsUtils.cpp +++ b/src/slic3r/plugin/PluginFsUtils.cpp @@ -4,16 +4,24 @@ #include "libslic3r/miniz_extension.hpp" #include +#include +#include +#include +#include #include #include #include "PluginAuditManager.hpp" #include "PythonInterpreter.hpp" +#include +#include #include #include #include +#include +#include "slic3r/plugin/PluginDescriptor.hpp" #include #include #include diff --git a/src/slic3r/plugin/PluginFsUtils.hpp b/src/slic3r/plugin/PluginFsUtils.hpp index 5b62e9f7f1..80174a68bd 100644 --- a/src/slic3r/plugin/PluginFsUtils.hpp +++ b/src/slic3r/plugin/PluginFsUtils.hpp @@ -1,6 +1,7 @@ #pragma once #include "PluginDescriptor.hpp" +#include #include #include @@ -9,6 +10,7 @@ #include #include +#include #include #define PLUGIN_SUBSCRIBED_DIR "_subscribed" diff --git a/src/slic3r/plugin/PluginHooks.cpp b/src/slic3r/plugin/PluginHooks.cpp index 2d84df5fdb..36c7f9292d 100644 --- a/src/slic3r/plugin/PluginHooks.cpp +++ b/src/slic3r/plugin/PluginHooks.cpp @@ -13,7 +13,10 @@ #include +#include +#include #include +#include "slic3r/plugin/PluginDescriptor.hpp" #include #include diff --git a/src/slic3r/plugin/PluginLoader.cpp b/src/slic3r/plugin/PluginLoader.cpp index 0c45564f1b..9da76b9109 100644 --- a/src/slic3r/plugin/PluginLoader.cpp +++ b/src/slic3r/plugin/PluginLoader.cpp @@ -11,9 +11,26 @@ #include "libslic3r/Utils.hpp" #include +#include +#include #include +#include +#include +#include +#include #include #include +#include "slic3r/plugin/PluginDescriptor.hpp" +#include +#include +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include +#include +#include +#include +#include +#include #ifdef _WIN32 #include #endif diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index 022f85eb1f..c064622b17 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -1,8 +1,14 @@ #include "PluginManager.hpp" +#include +#include +#include #include +#include +#include "libslic3r/LifecycleEvents.hpp" #include #include +#include #include #include "PluginFsUtils.hpp" @@ -21,14 +27,19 @@ #include #include #include +#include "slic3r/plugin/CloudPluginService.hpp" #include #include #include #include #include +#include #include +#include #include #include +#include +#include namespace Slic3r { namespace { diff --git a/src/slic3r/plugin/PluginManager.hpp b/src/slic3r/plugin/PluginManager.hpp index 891f787bf2..bd7a495a67 100644 --- a/src/slic3r/plugin/PluginManager.hpp +++ b/src/slic3r/plugin/PluginManager.hpp @@ -1,9 +1,11 @@ #ifndef slic3r_PluginManager_hpp_ #define slic3r_PluginManager_hpp_ +#include #include #include +#include #include #include #include @@ -13,9 +15,11 @@ #include #include #include +#include "slic3r/plugin/PluginFsUtils.hpp" #include #include #include +#include #include #include diff --git a/src/slic3r/plugin/PluginResolver.cpp b/src/slic3r/plugin/PluginResolver.cpp index 6e72929c63..6b8ca9a417 100644 --- a/src/slic3r/plugin/PluginResolver.cpp +++ b/src/slic3r/plugin/PluginResolver.cpp @@ -11,9 +11,15 @@ #include "../GUI/NotificationManager.hpp" #include +#include #include +#include "libslic3r/Preset.hpp" #include +#include #include +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include #include #include diff --git a/src/slic3r/plugin/PyPluginTrampoline.hpp b/src/slic3r/plugin/PyPluginTrampoline.hpp index 4c77f1ba9c..915c578353 100644 --- a/src/slic3r/plugin/PyPluginTrampoline.hpp +++ b/src/slic3r/plugin/PyPluginTrampoline.hpp @@ -1,17 +1,22 @@ #ifndef slic3r_PyPluginTrampoline_hpp_ #define slic3r_PyPluginTrampoline_hpp_ +#include "libslic3r/LifecycleEvents.hpp" #include #include #include #include +#include #include "PythonPluginInterface.hpp" #include "PythonInterpreter.hpp" #include "PluginFsUtils.hpp" #include "PluginAuditManager.hpp" +#include +#include +#include // Trampoline variants of pybind11's override macros. Every C++->Python plugin call crosses a // trampoline method, so this single boundary is where we (1) log the full Python traceback and diff --git a/src/slic3r/plugin/PythonInterpreter.cpp b/src/slic3r/plugin/PythonInterpreter.cpp index d82bf52a13..6d1afc1ba1 100644 --- a/src/slic3r/plugin/PythonInterpreter.cpp +++ b/src/slic3r/plugin/PythonInterpreter.cpp @@ -2,9 +2,15 @@ #include "GeneratedConfig.hpp" #include "libslic3r/Utils.hpp" #include "PluginAuditManager.hpp" +#include +#include #include +#include +#include +#include #include #include "PluginFsUtils.hpp" +#include #include @@ -16,7 +22,10 @@ #include #include #include +#include #include +#include +#include #include namespace Slic3r { diff --git a/src/slic3r/plugin/PythonInterpreter.hpp b/src/slic3r/plugin/PythonInterpreter.hpp index e15aa91598..2c499283cc 100644 --- a/src/slic3r/plugin/PythonInterpreter.hpp +++ b/src/slic3r/plugin/PythonInterpreter.hpp @@ -2,6 +2,7 @@ #define slic3r_PythonInterpreter_hpp_ // Via pybind11 so this file requests the same python3xx.lib as everything else. +#include #include #include #include diff --git a/src/slic3r/plugin/PythonPluginBridge.cpp b/src/slic3r/plugin/PythonPluginBridge.cpp index a88695005c..6cf747810f 100644 --- a/src/slic3r/plugin/PythonPluginBridge.cpp +++ b/src/slic3r/plugin/PythonPluginBridge.cpp @@ -3,15 +3,19 @@ #include #include #include +#include "libslic3r/LifecycleEvents.hpp" #include #include #include +#include "slic3r/plugin/PythonPluginInterface.hpp" #include #include #include #include #include +#include +#include #include "PythonInterpreter.hpp" #include "PluginFsUtils.hpp" @@ -23,6 +27,8 @@ #include "pluginTypes/pages/PagesPluginCapability.hpp" #include "pluginTypes/script/ScriptPluginCapability.hpp" #include "pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp" +#include +#include namespace py = pybind11; diff --git a/src/slic3r/plugin/host/PluginHost.cpp b/src/slic3r/plugin/host/PluginHost.cpp index 2830d6f276..ae56bc575c 100644 --- a/src/slic3r/plugin/host/PluginHost.cpp +++ b/src/slic3r/plugin/host/PluginHost.cpp @@ -1,10 +1,12 @@ #include "PluginHost.hpp" #include "PluginHostBindings.hpp" #include "PluginHostUi.hpp" +#include #include #include #include +#include namespace Slic3r { diff --git a/src/slic3r/plugin/host/PluginHostApp.cpp b/src/slic3r/plugin/host/PluginHostApp.cpp index 75acd4cc7b..668e99c7ff 100644 --- a/src/slic3r/plugin/host/PluginHostApp.cpp +++ b/src/slic3r/plugin/host/PluginHostApp.cpp @@ -1,4 +1,5 @@ #include "PluginHostBindings.hpp" +#include #include #include @@ -8,6 +9,8 @@ #include #include +#include +#include namespace py = pybind11; diff --git a/src/slic3r/plugin/host/PluginHostGeometry.cpp b/src/slic3r/plugin/host/PluginHostGeometry.cpp index 646dffb5d4..14db01cc4c 100644 --- a/src/slic3r/plugin/host/PluginHostGeometry.cpp +++ b/src/slic3r/plugin/host/PluginHostGeometry.cpp @@ -1,10 +1,18 @@ #include "PluginHostBindings.hpp" +#include +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" +#include #include #include // offset/offset_ex/union_ex/diff_ex/intersection_ex #include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" #include #include diff --git a/src/slic3r/plugin/host/PluginHostMesh.cpp b/src/slic3r/plugin/host/PluginHostMesh.cpp index 28da5c3afc..8799278bd5 100644 --- a/src/slic3r/plugin/host/PluginHostMesh.cpp +++ b/src/slic3r/plugin/host/PluginHostMesh.cpp @@ -1,11 +1,18 @@ #include "PluginHostBindings.hpp" #include "PluginHostMesh.hpp" +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Point.hpp" +#include #include #include #include +#include #include namespace py = pybind11; diff --git a/src/slic3r/plugin/host/PluginHostModel.cpp b/src/slic3r/plugin/host/PluginHostModel.cpp index 3da1c2ae6f..357e37808d 100644 --- a/src/slic3r/plugin/host/PluginHostModel.cpp +++ b/src/slic3r/plugin/host/PluginHostModel.cpp @@ -1,7 +1,11 @@ #include "PluginHostBindings.hpp" #include "PluginHostMesh.hpp" +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" +#include #include #include diff --git a/src/slic3r/plugin/host/PluginHostPresets.cpp b/src/slic3r/plugin/host/PluginHostPresets.cpp index fffe9e64cf..6e10e3f282 100644 --- a/src/slic3r/plugin/host/PluginHostPresets.cpp +++ b/src/slic3r/plugin/host/PluginHostPresets.cpp @@ -1,9 +1,14 @@ #include "PluginHostBindings.hpp" +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" +#include #include #include +#include #include #include diff --git a/src/slic3r/plugin/host/PluginHostSlicing.cpp b/src/slic3r/plugin/host/PluginHostSlicing.cpp index 30e7b45138..fb2c02eaac 100644 --- a/src/slic3r/plugin/host/PluginHostSlicing.cpp +++ b/src/slic3r/plugin/host/PluginHostSlicing.cpp @@ -1,4 +1,7 @@ #include "PluginHostBindings.hpp" +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" #include "libslic3r/BoundingBox.hpp" @@ -10,8 +13,12 @@ #include "libslic3r/Layer.hpp" // LayerRegion, Layer, SupportLayer #include "libslic3r/Print.hpp" // PrintRegion, PrintObject, Print +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Model.hpp" #include #include +#include #include namespace py = pybind11; diff --git a/src/slic3r/plugin/host/PluginHostUi.cpp b/src/slic3r/plugin/host/PluginHostUi.cpp index ed501f0249..54de1df0d6 100644 --- a/src/slic3r/plugin/host/PluginHostUi.cpp +++ b/src/slic3r/plugin/host/PluginHostUi.cpp @@ -1,9 +1,14 @@ #include "PluginHostUi.hpp" +#include +#include +#include #include "slic3r/plugin/PluginAuditManager.hpp" #include "slic3r/plugin/PythonInterpreter.hpp" // PythonGILState #include "slic3r/plugin/PluginFsUtils.hpp" // json_to_py / py_to_json +#include +#include #include #include #include @@ -18,8 +23,14 @@ #include +#include +#include #include #include +#include +#include +#include +#include #include #include diff --git a/src/slic3r/plugin/host/PluginPages.cpp b/src/slic3r/plugin/host/PluginPages.cpp index eb8b3332b9..36b4cd10b4 100644 --- a/src/slic3r/plugin/host/PluginPages.cpp +++ b/src/slic3r/plugin/host/PluginPages.cpp @@ -1,6 +1,7 @@ #include "PluginPages.hpp" #include "libslic3r/AppConfig.hpp" +#include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/Notebook.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Widgets/Button.hpp" @@ -9,16 +10,30 @@ #include +#include #include #include +#include +#include +#include #include +#include "slic3r/plugin/pluginTypes/pages/PagesPluginCapability.hpp" +#include "slic3r/GUI/WebPanel.hpp" +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" #include +#include +#include +#include #include +#include #include #include #include +#include +#include namespace Slic3r { namespace { @@ -169,8 +184,10 @@ void PluginPages::initialize(Notebook* parent) void PluginPages::shutdown() { - while (!m_pages.empty()) - remove_page(m_pages.begin()->first); + // Removing the selected tab selects the tab to its left. In tab order that is a built-in tab, + // never an unbuilt plugin page that is removed next and would be built only to be destroyed. + for (const PluginCapabilityId& id : std::vector(m_order)) + remove_page(id); m_parent = nullptr; } @@ -211,8 +228,7 @@ bool PluginPages::create_page(const PluginCapabilityId& id) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to get icon for plugin " << id.plugin_key; } - auto* page = new PluginPage(m_parent, std::move(capability)); - + wxBitmap bitmap; if (!icon.empty()) { try { boost::filesystem::path icon_path(icon); @@ -220,7 +236,7 @@ bool PluginPages::create_page(const PluginCapabilityId& id) if (extension == ".svg" || extension == ".png") icon_path.replace_extension(); - page->set_icon(create_scaled_bitmap(icon_path.string(), m_parent, 20)); + bitmap = create_scaled_bitmap(icon_path.string(), m_parent, 20); } catch (const std::exception& error) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to load icon for plugin " << id.plugin_key << ": " << error.what(); } catch (...) { @@ -228,7 +244,15 @@ bool PluginPages::create_page(const PluginCapabilityId& id) } } - m_pages.emplace(id, page); + // Built the first time its tab is shown, so a language switch never creates the page's browser + // while the main window is being rebuilt. Never prebuilt: the idle queue cannot drop a page + // that remove_page() destroys. + auto* page = new GUI::LazyPage(m_parent, GUI::into_u8(page_tab_id(id)), -1, + [capability = std::move(capability)](wxWindow* parent) { + return new PluginPage(parent, capability); + }); + + m_pages.emplace(id, Page{page, bitmap}); m_order.push_back(id); return true; } @@ -257,16 +281,10 @@ void PluginPages::on_plugin_register(const std::string& plugin_key) void PluginPages::on_plugin_deregister(const std::string& plugin_key) { - for (auto it = m_pages.begin(); it != m_pages.end();) { - if (it->first.plugin_key != plugin_key) { - ++it; - continue; - } - - const PluginCapabilityId id = it->first; - ++it; - remove_page(id); - } + // In tab order, as in shutdown(). + for (const PluginCapabilityId& id : std::vector(m_order)) + if (id.plugin_key == plugin_key) + remove_page(id); } void PluginPages::remove_page(const PluginCapabilityId& id) @@ -275,8 +293,10 @@ void PluginPages::remove_page(const PluginCapabilityId& id) if (it == m_pages.end()) return; - PluginPage* page = it->second; - page->detach_capability(); + GUI::LazyPage* page = it->second.page; + // Only a built page has installed a message sender on the capability. + if (PluginPage* built = page->get()) + built->detach_capability(); m_pages.erase(it); m_order.erase(std::remove(m_order.begin(), m_order.end(), id), m_order.end()); @@ -334,26 +354,27 @@ void PluginPages::relayout() bool up_to_date = page_count >= tab_ids.size(); for (size_t i = 0; up_to_date && i < tab_ids.size(); ++i) up_to_date = m_parent->GetPageName(page_count - tab_ids.size() + i) == page_tab_id(tab_ids[i]); - for (const auto& [id, page] : m_pages) { + for (const auto& [id, entry] : m_pages) { if (!up_to_date) break; const bool wanted = std::find(tab_ids.begin(), tab_ids.end(), id) != tab_ids.end(); - up_to_date = (m_parent->FindPage(page) != wxNOT_FOUND) == wanted; + up_to_date = entry.page->in_book() == wanted; } if (!up_to_date) { const wxString id_to_reselect = m_parent->GetSelectedPageName(); - for (const auto& [id, page] : m_pages) { - const int idx = m_parent->FindPage(page); + // In tab order, as in shutdown(). + for (const auto& id : m_order) { + const int idx = m_parent->FindPage(m_pages.at(id).page); if (idx != wxNOT_FOUND) m_parent->RemovePage(idx); } for (const auto& id : tab_ids) { - PluginPage* page = m_pages.at(id); - m_parent->InsertPage(m_parent->GetPageCount(), page_tab_id(id), page, wxString::FromUTF8(id.name), "", - false, page->icon()); + const Page& entry = m_pages.at(id); + m_parent->InsertPage(m_parent->GetPageCount(), page_tab_id(id), entry.page, wxString::FromUTF8(id.name), "", + false, entry.icon); } if (!id_to_reselect.empty()) diff --git a/src/slic3r/plugin/host/PluginPages.hpp b/src/slic3r/plugin/host/PluginPages.hpp index 59d34fe9ff..90d8c28a03 100644 --- a/src/slic3r/plugin/host/PluginPages.hpp +++ b/src/slic3r/plugin/host/PluginPages.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -12,6 +13,7 @@ #include #include +#include #include class Notebook; @@ -28,8 +30,6 @@ public: void detach_capability(); void push_message(const std::string& message); - void set_icon(const wxBitmap& icon) { m_icon = icon; } - const wxBitmap& icon() const { return m_icon; } protected: std::optional page_html() override; @@ -40,7 +40,6 @@ private: std::shared_ptr m_cap; std::shared_ptr> m_lifetime; - wxBitmap m_icon; }; class PluginPages @@ -72,7 +71,13 @@ private: void show_overflow_menu(); static wxString page_tab_id(const PluginCapabilityId& id); - std::map m_pages; + struct Page + { + GUI::LazyPage* page{nullptr}; + wxBitmap icon; + }; + + std::map m_pages; std::vector m_order; Notebook* m_parent{nullptr}; diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp index e009f4426f..e6ab45246b 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapability.cpp @@ -2,10 +2,17 @@ #include "PagesPluginCapabilityTrampoline.hpp" #include "../../PluginFsUtils.hpp" +#include +#include #include +#include +#include +#include #include +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include #include namespace py = pybind11; diff --git a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp index f6e13c981b..24b98bea24 100644 --- a/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp @@ -3,8 +3,14 @@ #include "PagesPluginCapability.hpp" #include "../../PluginFsUtils.hpp" #include "../../PyPluginTrampoline.hpp" +#include +#include #include +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include "slic3r/plugin/PythonInterpreter.hpp" +#include namespace Slic3r { diff --git a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.cpp b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.cpp index d0c88404fe..eac19199bf 100644 --- a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.cpp +++ b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.cpp @@ -2,11 +2,16 @@ #include "PrinterAgentPluginCapabilityTrampoline.hpp" #include "IPrinterAgent.hpp" +#include +#include "slic3r/Utils/bambu_networking.hpp" +#include #include #include #include +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" #include namespace py = pybind11; diff --git a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.hpp b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.hpp index d33cee7afe..e106a35f52 100644 --- a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.hpp +++ b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.hpp @@ -4,6 +4,8 @@ #include "../../PythonPluginInterface.hpp" #include "IPrinterAgent.hpp" +#include +#include "slic3r/Utils/bambu_networking.hpp" #include #include diff --git a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp index 2e15523430..790f6e3ac6 100644 --- a/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapabilityTrampoline.hpp @@ -5,9 +5,16 @@ #include "../../PyPluginTrampoline.hpp" #include "IPrinterAgent.hpp" +#include "slic3r/Utils/bambu_networking.hpp" #include "pybind11/pybind11.h" +#include +#include +#include +#include #include +#include "slic3r/plugin/PythonInterpreter.hpp" #include +#include #include #include diff --git a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.cpp b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.cpp index 712ba9b653..f9ff379cf8 100644 --- a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.cpp +++ b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.cpp @@ -3,8 +3,10 @@ #include "ScriptPluginCapabilityTrampoline.hpp" #include +#include #include #include +#include "slic3r/plugin/PythonPluginInterface.hpp" namespace py = pybind11; diff --git a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.hpp b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.hpp index fb1319e560..59055d7c8f 100644 --- a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.hpp +++ b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapability.hpp @@ -2,6 +2,7 @@ #define slic3r_ScriptPluginCapability_hpp_ #include "../../PythonPluginInterface.hpp" +#include namespace Slic3r { class ScriptPluginCapability : public PluginCapabilityInterface diff --git a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp index 62958a89d9..dc90001c57 100644 --- a/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp @@ -3,6 +3,8 @@ #include "ScriptPluginCapability.hpp" #include "../../PyPluginTrampoline.hpp" +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include namespace Slic3r { class PyScriptPluginCapabilityTrampoline : public PyPluginCommonTrampoline diff --git a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.cpp b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.cpp index d2e630242d..ed2a6aeecf 100644 --- a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.cpp +++ b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.cpp @@ -1,7 +1,14 @@ #include "SlicingPipelinePluginCapability.hpp" #include "SlicingPipelinePluginCapabilityTrampoline.hpp" +#include +#include +#include #include "slic3r/plugin/PluginBindingUtils.hpp" // config_value_or_none #include "libslic3r/libslic3r.h" // unscale<>, live SCALING_FACTOR +#include "libslic3r/Print.hpp" +#include +#include "slic3r/plugin/PythonPluginInterface.hpp" +#include namespace py = pybind11; namespace Slic3r { diff --git a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp index da0dbcbcbd..6bad90817f 100644 --- a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp +++ b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapability.hpp @@ -1,6 +1,7 @@ #pragma once #include "slic3r/plugin/PythonPluginInterface.hpp" #include "libslic3r/Print.hpp" // SlicingPipelineStepPlugin, Print, PrintObject +#include "libslic3r/PrintConfig.hpp" #include #include #include diff --git a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp index 5c9d527e42..82312c4200 100644 --- a/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp +++ b/src/slic3r/plugin/pluginTypes/slicingPipeline/SlicingPipelinePluginCapabilityTrampoline.hpp @@ -1,8 +1,10 @@ #pragma once #include "SlicingPipelinePluginCapability.hpp" +#include #include "slic3r/plugin/PyPluginTrampoline.hpp" #include "slic3r/plugin/PluginAuditManager.hpp" #include +#include "slic3r/plugin/PythonPluginInterface.hpp" namespace Slic3r { class PySlicingPipelinePluginCapabilityTrampoline : public PyPluginCommonTrampoline { diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp index a21ff236ce..4ae9649197 100644 --- a/tests/fff_print/test_cooling.cpp +++ b/tests/fff_print/test_cooling.cpp @@ -1,10 +1,16 @@ #include +#include #include "test_helpers.hpp" #include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/libslic3r.h" #include #include +#include #include using namespace Slic3r; diff --git a/tests/fff_print/test_extrusion_entity.cpp b/tests/fff_print/test_extrusion_entity.cpp index 57bc7e81e6..5b18b3ece5 100644 --- a/tests/fff_print/test_extrusion_entity.cpp +++ b/tests/fff_print/test_extrusion_entity.cpp @@ -1,7 +1,12 @@ +#include #include #include +#include +#include +#include +#include #include "libslic3r/ExtrusionEntityCollection.hpp" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/Point.hpp" diff --git a/tests/fff_print/test_extrusion_processor.cpp b/tests/fff_print/test_extrusion_processor.cpp index 47f9a62ecf..a3499a71b5 100644 --- a/tests/fff_print/test_extrusion_processor.cpp +++ b/tests/fff_print/test_extrusion_processor.cpp @@ -1,5 +1,11 @@ #include +#include +#include +#include +#include +#include +#include #include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/GCode/ExtrusionProcessor.hpp" #include "libslic3r/GCodeReader.hpp" @@ -9,7 +15,15 @@ #include #include +#include +#include "libslic3r/Line.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/Model.hpp" #include +#include #include using namespace Slic3r; diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index 1d5a3bd345..7247503824 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -2,13 +2,35 @@ #include #include +#include +#include #include +#include "libslic3r/Fill/FillBase.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include "libslic3r/Model.hpp" #include +#include +#include #include #include #include +#include #include +#include +#include +#include +#include +#include #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/Fill/Fill.hpp" @@ -1671,24 +1693,32 @@ TEST_CASE("Smoothing multiline lightning infill keeps its outlines connected", " // and the outlines of branches that run close to each other merge into one. Rounding the branches // before those outlines are built moves them apart, which breaks the merged outlines up into // separate loops - many more of them, each needing its own travel move. + // A micron change of the cube moves the loop count of a single slice by several percent, so the + // shapes of a few nearly equal cubes are added up. auto shape_for = [](const std::string &smooth_factor) { - Print print; - Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print, - {{"sparse_infill_pattern", "lightning"}, - {"sparse_infill_density", "50%"}, - {"fill_multiline", 2}, - {"sparse_infill_smooth_factor", smooth_factor}, - {"layer_height", 0.2}}); - return sparse_infill_shape(print); + SparseInfillShape sum; + for (const double size : {20., 20.001, 20.002, 20.003}) { + Print print; + Slic3r::Test::init_and_process_print({Slic3r::Test::cube(size)}, print, + {{"sparse_infill_pattern", "lightning"}, + {"sparse_infill_density", "50%"}, + {"fill_multiline", 2}, + {"sparse_infill_smooth_factor", smooth_factor}, + {"layer_height", 0.2}}); + const SparseInfillShape shape = sparse_infill_shape(print); + sum.path_count += shape.path_count; + sum.point_count += shape.point_count; + sum.sharp_turns += shape.sharp_turns; + } + return sum; }; const SparseInfillShape sharp = shape_for("0%"); const SparseInfillShape smooth = shape_for("100%"); REQUIRE(sharp.path_count > 0); - // The loop count varies by a loop or two between platforms and between runs, so this is not an - // exact comparison. Smoothing should leave it about where it was; uncapping the smoothing - // reach, the regression this guards against, adds about 10%. + // Smoothing should leave the loop count about where it was; uncapping the smoothing reach, the + // regression this guards against, adds about 10%. const size_t allowed_extra = sharp.path_count / 50; // 2% REQUIRE(smooth.path_count <= sharp.path_count + allowed_extra); // The outlines are still rounded. diff --git a/tests/fff_print/test_flow.cpp b/tests/fff_print/test_flow.cpp index 6025bb9b56..f0579c675f 100644 --- a/tests/fff_print/test_flow.cpp +++ b/tests/fff_print/test_flow.cpp @@ -1,8 +1,11 @@ #include +#include #include #include +#include +#include #include "test_helpers.hpp" // get access to init_print, etc #include "libslic3r/Config.hpp" diff --git a/tests/fff_print/test_gcode_timing.cpp b/tests/fff_print/test_gcode_timing.cpp index 8c08fc4f03..45a71cdd92 100644 --- a/tests/fff_print/test_gcode_timing.cpp +++ b/tests/fff_print/test_gcode_timing.cpp @@ -1,5 +1,9 @@ #include +#include +#include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/MultiNozzleUtils.hpp" @@ -8,9 +12,13 @@ #include "test_utils.hpp" #include +#include #include #include +#include "libslic3r/ExtrusionEntity.hpp" +#include #include +#include #include #include #include diff --git a/tests/fff_print/test_gcodeprocessor.cpp b/tests/fff_print/test_gcodeprocessor.cpp index 402a4757e1..6914ec4df9 100644 --- a/tests/fff_print/test_gcodeprocessor.cpp +++ b/tests/fff_print/test_gcodeprocessor.cpp @@ -1,5 +1,7 @@ #include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/GCode/GCodeProcessor.hpp" diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp index dc46df965d..992204d716 100644 --- a/tests/fff_print/test_gcodewriter.cpp +++ b/tests/fff_print/test_gcodewriter.cpp @@ -1,21 +1,38 @@ +#include #include #include #include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Extruder.hpp" +#include "libslic3r/libslic3r.h" #include #include +#include #include #include +#include #include +#include +#include +#include +#include +#include +#include #include "nlohmann/json.hpp" +#include "libslic3r/GCodeReader.hpp" #include "libslic3r/GCodeWriter.hpp" #include "libslic3r/GCode.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/Print.hpp" #include "libslic3r/ModelArrange.hpp" +#include #include #include "test_helpers.hpp" @@ -23,10 +40,7 @@ using namespace Slic3r; using namespace Slic3r::Test; -// Arrange on a finite bed, not an unbounded InfiniteBed: the latter places items -// near INT64_MIN/4 (~2.3e18), which reaches ClipperLib's coordinate limit and throws -// "Coordinate outside allowed range" on Windows/arm64. A 500x500 bed keeps coordinates -// small while still covering large printers. +// Arrange on a 500x500 bed, which keeps coordinates small while still covering large printers. static void arrange_objects_on_test_bed(Model &model, const DynamicPrintConfig &config) { const BoundingBox bed{Point::new_scale(0., 0.), Point::new_scale(500., 500.)}; @@ -100,6 +114,22 @@ SCENARIO("Origin manipulation", "[GCodeWriter]") { } } +TEST_CASE("A cached config slot is looked up again whenever its key changes", "[GCodeWriter]") +{ + GCode::ConfigIndexCache cache; + int lookups = 0; + auto slot = [&](int filament, size_t layer, size_t generation) { + return cache.get(filament, layer, generation, [&] { ++lookups; return filament * 100 + int(layer) * 10 + int(generation); }); + }; + REQUIRE(slot(1, 2, 3) == 123); + REQUIRE(slot(1, 2, 3) == 123); + REQUIRE(lookups == 1); + REQUIRE(slot(4, 2, 3) == 423); + REQUIRE(slot(4, 5, 3) == 453); + REQUIRE(slot(4, 5, 6) == 456); + REQUIRE(lookups == 4); +} + // Verify that emit_machine_limits_to_gcode emits the correct max value across // used extruders (regression for commit b4ee665: "Emit max value of machine // limit among used extruders"). @@ -875,3 +905,46 @@ TEST_CASE("Custom G-code motion limits are restored before generated moves", "[G REQUIRE(gcode.find("M204 S6000 ; adjust acceleration", custom_gcode_pos) != std::string::npos); REQUIRE(gcode.find("M205 X8 Y8 ; adjust jerk", custom_gcode_pos) != std::string::npos); } + +TEST_CASE("Percent accelerations resolve against the option they are a percentage of", "[GCodeWriter]") +{ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "gcode_flavor", "marlin" }, + { "machine_max_acceleration_extruding", "20000,20000" }, + { "default_acceleration", "4000" }, + { "initial_layer_acceleration", "0" }, + { "outer_wall_acceleration", "3000" }, + { "bridge_acceleration", "50%" }, + { "sparse_infill_acceleration", "25%" }, + { "internal_solid_infill_acceleration", "60%" }, + { "sparse_infill_density", "20%" }, + }); + // get_abs_value_at() resolves each percentage through the ratio_over in the config definitions. + const std::map expected = { + { "Bridge", int(config.get_abs_value_at("bridge_acceleration", 0)) }, + { "Sparse infill", int(config.get_abs_value_at("sparse_infill_acceleration", 0)) }, + { "Internal solid infill", int(config.get_abs_value_at("internal_solid_infill_acceleration", 0)) }, + }; + REQUIRE(expected.at("Bridge") == 1500); + REQUIRE(expected.at("Sparse infill") == 1000); + REQUIRE(expected.at("Internal solid infill") == 2400); + + std::map> accelerations_by_role; + std::string role; + int acceleration = 0; + GCodeReader reader; + reader.parse_buffer(Slic3r::Test::slice({ TestMesh::bridge }, config), [&](GCodeReader &self, const GCodeReader::GCodeLine &line) { + float value; + if (boost::starts_with(line.raw(), ";TYPE:")) + role = line.raw().substr(6); + else if (line.cmd_is("M204") && line.has_value('S', value)) + acceleration = int(value); + else if (line.extruding(self) && line.dist_XY(self) > 0) + accelerations_by_role[role].insert(acceleration); + }); + for (const auto &[role_name, value] : expected) { + INFO(role_name); + REQUIRE(accelerations_by_role[role_name] == std::set{ value }); + } +} diff --git a/tests/fff_print/test_helpers.cpp b/tests/fff_print/test_helpers.cpp index 89f9f9fdd1..c131b10f83 100644 --- a/tests/fff_print/test_helpers.cpp +++ b/tests/fff_print/test_helpers.cpp @@ -1,5 +1,6 @@ #include "test_helpers.hpp" +#include #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Config.hpp" @@ -7,11 +8,23 @@ #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/Format/STL.hpp" +#include #include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Exception.hpp" +#include "libslic3r/PrintConfig.hpp" +#include +#include "libslic3r/Point.hpp" +#include +#include +#include #include #include #include +#include +#include +#include #include "test_utils.hpp" diff --git a/tests/fff_print/test_helpers.hpp b/tests/fff_print/test_helpers.hpp index cbdc90c3d9..1ffc08c64e 100644 --- a/tests/fff_print/test_helpers.hpp +++ b/tests/fff_print/test_helpers.hpp @@ -8,6 +8,10 @@ #include "libslic3r/Print.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/PrintConfig.hpp" +#include #include #include #include diff --git a/tests/fff_print/test_mixed_filament.cpp b/tests/fff_print/test_mixed_filament.cpp index 25b426c210..bfa8985fd4 100644 --- a/tests/fff_print/test_mixed_filament.cpp +++ b/tests/fff_print/test_mixed_filament.cpp @@ -1,5 +1,16 @@ +#include #include +#include "libslic3r/PrintConfig.hpp" +#include +#include +#include "libslic3r/Model.hpp" +#include +#include "libslic3r/Config.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/PrintBase.hpp" +#include +#include #include "libslic3r/GCode/ToolOrdering.hpp" #include "libslic3r/MultiNozzleUtils.hpp" #include "libslic3r/Print.hpp" diff --git a/tests/fff_print/test_model.cpp b/tests/fff_print/test_model.cpp index 27bf539373..9e2c0790b3 100644 --- a/tests/fff_print/test_model.cpp +++ b/tests/fff_print/test_model.cpp @@ -1,10 +1,17 @@ +#include #include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Model.hpp" #include "libslic3r/ModelArrange.hpp" #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/PrintConfig.hpp" +#include +#include "libslic3r/Point.hpp" +#include #include "test_helpers.hpp" #include "test_utils.hpp" diff --git a/tests/fff_print/test_multifilament.cpp b/tests/fff_print/test_multifilament.cpp index 445b1c0694..9b9cae23db 100644 --- a/tests/fff_print/test_multifilament.cpp +++ b/tests/fff_print/test_multifilament.cpp @@ -1,5 +1,8 @@ #include +#include +#include +#include #include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/GCodeReader.hpp" @@ -12,6 +15,11 @@ #include #include #include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Print.hpp" #include #include #include diff --git a/tests/fff_print/test_perimeters.cpp b/tests/fff_print/test_perimeters.cpp index 459ba0a178..6ab3473e3c 100644 --- a/tests/fff_print/test_perimeters.cpp +++ b/tests/fff_print/test_perimeters.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include +#include #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" #include "libslic3r/Layer.hpp" @@ -10,8 +15,15 @@ #include #include +#include "libslic3r/PrintConfig.hpp" +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Point.hpp" #include #include +#include #include #include "test_helpers.hpp" diff --git a/tests/fff_print/test_precise_seam.cpp b/tests/fff_print/test_precise_seam.cpp index d324a91626..0dd422f0f5 100644 --- a/tests/fff_print/test_precise_seam.cpp +++ b/tests/fff_print/test_precise_seam.cpp @@ -1,9 +1,24 @@ #include +#include +#include +#include +#include +#include #include "test_helpers.hpp" #include "libslic3r/GCode/PreciseSeam.hpp" #include +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/Layer.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/GCode/SeamPlacer.hpp" +#include using namespace Slic3r; diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index 4176256021..9417934276 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -8,6 +8,20 @@ #include #endif +#include +#include +#include +#include +#include +#include "libslic3r/PrintConfig.hpp" +#include +#include "libslic3r/Surface.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintBase.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include + #include #include "libslic3r/libslic3r.h" diff --git a/tests/fff_print/test_printobject.cpp b/tests/fff_print/test_printobject.cpp index a373a1ad39..6671dabc4b 100644 --- a/tests/fff_print/test_printobject.cpp +++ b/tests/fff_print/test_printobject.cpp @@ -1,5 +1,11 @@ +#include #include +#include +#include +#include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Print.hpp" #include "libslic3r/Layer.hpp" @@ -10,7 +16,20 @@ #include "test_helpers.hpp" #include +#include #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/Surface.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/BoundingBox.hpp" #include #include #include diff --git a/tests/fff_print/test_seam_placer.cpp b/tests/fff_print/test_seam_placer.cpp index 81b7cd806c..40bbbdd117 100644 --- a/tests/fff_print/test_seam_placer.cpp +++ b/tests/fff_print/test_seam_placer.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include +#include #include "test_helpers.hpp" #include "libslic3r/GCode/SeamPlacer.hpp" #include "libslic3r/Layer.hpp" @@ -7,6 +12,16 @@ #include #include +#include "libslic3r/Model.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" using namespace Slic3r; diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 17a79a7828..d04b32361e 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -1,5 +1,11 @@ +#include #include +#include +#include +#include +#include +#include #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Config.hpp" #include "libslic3r/Geometry.hpp" @@ -9,6 +15,16 @@ #include #include +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include +#include "libslic3r/Model.hpp" +#include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/libslic3r.h" +#include #include "test_helpers.hpp" // get access to init_print, etc diff --git a/tests/fff_print/test_slicing_pipeline_hook.cpp b/tests/fff_print/test_slicing_pipeline_hook.cpp index d7ebd1fd60..8b328e5dde 100644 --- a/tests/fff_print/test_slicing_pipeline_hook.cpp +++ b/tests/fff_print/test_slicing_pipeline_hook.cpp @@ -1,4 +1,14 @@ #include +#include "libslic3r/Config.hpp" +#include "libslic3r/Model.hpp" +#include +#include +#include "libslic3r/Surface.hpp" +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/PrintConfig.hpp" #include "test_helpers.hpp" using namespace Slic3r; diff --git a/tests/fff_print/test_support_material.cpp b/tests/fff_print/test_support_material.cpp index 97a9cea9e1..d311130094 100644 --- a/tests/fff_print/test_support_material.cpp +++ b/tests/fff_print/test_support_material.cpp @@ -1,12 +1,28 @@ +#include #include +#include +#include +#include +#include +#include #include "libslic3r/GCodeReader.hpp" #include "libslic3r/Layer.hpp" #include +#include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/PrintBase.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/PrintConfig.hpp" #include +#include #include #include +#include +#include +#include #include #include "test_helpers.hpp" // get access to init_print, etc diff --git a/tests/fff_print/test_texture_displacement.cpp b/tests/fff_print/test_texture_displacement.cpp index 459a42d185..87047af618 100644 --- a/tests/fff_print/test_texture_displacement.cpp +++ b/tests/fff_print/test_texture_displacement.cpp @@ -1,10 +1,22 @@ +#include +#include #include +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include "libslic3r/PrintConfig.hpp" +#include +#include #include "libslic3r/Model.hpp" #include "libslic3r/PNGReadWrite.hpp" #include "libslic3r/Print.hpp" diff --git a/tests/fff_print/test_tree_support.cpp b/tests/fff_print/test_tree_support.cpp index fbb40bb8f3..677cf4359f 100644 --- a/tests/fff_print/test_tree_support.cpp +++ b/tests/fff_print/test_tree_support.cpp @@ -1,7 +1,15 @@ #include #include +#include +#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/libslic3r.h" +#include +#include #include "libslic3r/Layer.hpp" #include "libslic3r/TriangleMesh.hpp" diff --git a/tests/fff_print/test_trianglemesh.cpp b/tests/fff_print/test_trianglemesh.cpp index b21f6299fd..722732e207 100644 --- a/tests/fff_print/test_trianglemesh.cpp +++ b/tests/fff_print/test_trianglemesh.cpp @@ -1,5 +1,6 @@ #include +#include #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/Point.hpp" @@ -8,8 +9,14 @@ #include "libslic3r/libslic3r.h" #include +#include +#include +#include #include #include +#include +#include +#include "libslic3r/ExPolygon.hpp" //#include "test_options.hpp" #include "test_helpers.hpp" diff --git a/tests/fff_print/test_wipe.cpp b/tests/fff_print/test_wipe.cpp index 46ee0d6441..63cd847ccb 100644 --- a/tests/fff_print/test_wipe.cpp +++ b/tests/fff_print/test_wipe.cpp @@ -2,11 +2,27 @@ #include #include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/calib.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" #include #include #include +#include #include +#include +#include +#include +#include +#include #include "libslic3r/GCode/GCodeProcessor.hpp" #include "libslic3r/GCodeReader.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/fff_print/test_wipe_tower.cpp b/tests/fff_print/test_wipe_tower.cpp index 014eab6f8b..da3cbe2502 100644 --- a/tests/fff_print/test_wipe_tower.cpp +++ b/tests/fff_print/test_wipe_tower.cpp @@ -1,8 +1,23 @@ +#include #include +#include "libslic3r/Config.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polygon.hpp" +#include +#include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" #include #include +#include +#include +#include +#include +#include +#include +#include #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" diff --git a/tests/filament_group/fg_test_evaluator.hpp b/tests/filament_group/fg_test_evaluator.hpp index 00a2e1a6f5..ceec7cf154 100644 --- a/tests/filament_group/fg_test_evaluator.hpp +++ b/tests/filament_group/fg_test_evaluator.hpp @@ -2,13 +2,18 @@ #define FG_TEST_EVALUATOR_HPP #include "fg_test_serialization.hpp" +#include #include #include #include #include +#include +#include #include +#include #include +#include namespace Slic3r { namespace FGTest { diff --git a/tests/filament_group/fg_test_serialization.hpp b/tests/filament_group/fg_test_serialization.hpp index 5f59da619c..fa0ab3c9ff 100644 --- a/tests/filament_group/fg_test_serialization.hpp +++ b/tests/filament_group/fg_test_serialization.hpp @@ -1,6 +1,7 @@ #ifndef FG_TEST_SERIALIZATION_HPP #define FG_TEST_SERIALIZATION_HPP +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/filament_group/fg_test_utils.hpp b/tests/filament_group/fg_test_utils.hpp index 2d2864bf10..b493e44607 100644 --- a/tests/filament_group/fg_test_utils.hpp +++ b/tests/filament_group/fg_test_utils.hpp @@ -2,9 +2,16 @@ #define FG_TEST_UTILS_HPP #include "fg_test_serialization.hpp" +#include "libslic3r/FilamentGroupUtils.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/FilamentGroup.hpp" +#include #include #include #include +#include +#include +#include namespace Slic3r { namespace FGTest { diff --git a/tests/filament_group/filament_group_regression_main.cpp b/tests/filament_group/filament_group_regression_main.cpp index b2cc4bd178..c8933e6b6e 100644 --- a/tests/filament_group/filament_group_regression_main.cpp +++ b/tests/filament_group/filament_group_regression_main.cpp @@ -11,13 +11,19 @@ #include +#include +#include +#include +#include #include "fg_test_serialization.hpp" #include "fg_test_evaluator.hpp" #include "fg_test_utils.hpp" +#include #include #include #include +#include "libslic3r/FilamentGroup.hpp" #include #include #include diff --git a/tests/libnest2d/libnest2d_test_utils.hpp b/tests/libnest2d/libnest2d_test_utils.hpp index 55f184f60c..b9f8510a8a 100644 --- a/tests/libnest2d/libnest2d_test_utils.hpp +++ b/tests/libnest2d/libnest2d_test_utils.hpp @@ -8,7 +8,10 @@ // it here and include this header from every libnest2d test file. #include +#include +#include "libnest2d/common.hpp" +#include "libnest2d/geometry_traits_nfp.hpp" #include #include diff --git a/tests/libnest2d/libnest2d_tests.cpp b/tests/libnest2d/libnest2d_tests.cpp index 1657d45601..f5e3263b89 100644 --- a/tests/libnest2d/libnest2d_tests.cpp +++ b/tests/libnest2d/libnest2d_tests.cpp @@ -1,5 +1,10 @@ #include +#include "libnest2d/libnest2d.hpp" +#include +#include +#include "libnest2d/nester.hpp" +#include #include "libnest2d_test_utils.hpp" using namespace libnest2d; diff --git a/tests/libnest2d/printer_parts.hpp b/tests/libnest2d/printer_parts.hpp index 075e32a837..07a3e9153d 100644 --- a/tests/libnest2d/printer_parts.hpp +++ b/tests/libnest2d/printer_parts.hpp @@ -1,6 +1,7 @@ #ifndef PRINTER_PARTS_H #define PRINTER_PARTS_H +#include "libnest2d/backends/libslic3r/geometries.hpp" #include #include diff --git a/tests/libnest2d/test_geometry.cpp b/tests/libnest2d/test_geometry.cpp index 9c58a299e4..e32c47042a 100644 --- a/tests/libnest2d/test_geometry.cpp +++ b/tests/libnest2d/test_geometry.cpp @@ -1,5 +1,24 @@ +#include +#include +#include #include +#include +#include "libnest2d/libnest2d.hpp" +#include "libnest2d/geometry_traits.hpp" +#include "libnest2d/backends/libslic3r/geometries.hpp" +#include "libnest2d/common.hpp" +#include +#include +#include "libnest2d/placers/nfpplacer.hpp" +#include +#include +#include +#include +#include "libnest2d/utils/rotcalipers.hpp" +#include +#include +#include #include "libnest2d_test_utils.hpp" #include "printer_parts.hpp" diff --git a/tests/libnest2d/test_nfp.cpp b/tests/libnest2d/test_nfp.cpp index 1b5c5d3a1c..fdb43f7bfa 100644 --- a/tests/libnest2d/test_nfp.cpp +++ b/tests/libnest2d/test_nfp.cpp @@ -1,5 +1,17 @@ +#include #include +#include "libnest2d/libnest2d.hpp" +#include +#include "libnest2d/geometry_traits.hpp" +#include "libnest2d/backends/libslic3r/geometries.hpp" +#include "libnest2d/geometry_traits_nfp.hpp" +#include "libnest2d/utils/boost_alg.hpp" +#include "libnest2d/placers/nfpplacer.hpp" +#include +#include +#include +#include #include "libnest2d_test_utils.hpp" using namespace libnest2d; diff --git a/tests/libnest2d/test_nfp_placer.cpp b/tests/libnest2d/test_nfp_placer.cpp index 4446333f5d..02b711ec9d 100644 --- a/tests/libnest2d/test_nfp_placer.cpp +++ b/tests/libnest2d/test_nfp_placer.cpp @@ -1,5 +1,13 @@ #include +#include "libnest2d/libnest2d.hpp" +#include +#include +#include "libnest2d/geometry_traits.hpp" +#include "libnest2d/common.hpp" +#include +#include +#include #include "libnest2d_test_utils.hpp" using namespace libnest2d; diff --git a/tests/libslic3r/libslic3r_tests.cpp b/tests/libslic3r/libslic3r_tests.cpp index a46b69d124..178a869648 100644 --- a/tests/libslic3r/libslic3r_tests.cpp +++ b/tests/libslic3r/libslic3r_tests.cpp @@ -1,5 +1,10 @@ #include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include #include "libslic3r/Utils.hpp" #define NANOSVG_IMPLEMENTATION #include "nanosvg/nanosvg.h" diff --git a/tests/libslic3r/test_3mf.cpp b/tests/libslic3r/test_3mf.cpp index 846caf5432..a8fd1eb888 100644 --- a/tests/libslic3r/test_3mf.cpp +++ b/tests/libslic3r/test_3mf.cpp @@ -1,4 +1,9 @@ +#include +#include +#include +#include +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/bbs_3mf.hpp" @@ -14,6 +19,15 @@ #include "test_utils.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/Geometry.hpp" +#include +#include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/TriangleSelector.hpp" +#include +#include +#include #include #include @@ -25,8 +39,12 @@ #include #include #include +#include +#include #include // for std::enable_if_t #include // for typeid +#include +#include namespace Catch { template diff --git a/tests/libslic3r/test_aabbindirect.cpp b/tests/libslic3r/test_aabbindirect.cpp index 122e4756f1..e97b8d193b 100644 --- a/tests/libslic3r/test_aabbindirect.cpp +++ b/tests/libslic3r/test_aabbindirect.cpp @@ -1,8 +1,13 @@ #include +#include +#include #include "test_utils.hpp" +#include +#include #include #include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_appconfig.cpp b/tests/libslic3r/test_appconfig.cpp index d3811c9827..3eb35d7490 100644 --- a/tests/libslic3r/test_appconfig.cpp +++ b/tests/libslic3r/test_appconfig.cpp @@ -1,5 +1,6 @@ #include +#include #include "libslic3r/AppConfig.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_arachne_walls.cpp b/tests/libslic3r/test_arachne_walls.cpp index 2b6580ed11..be4df5d3b1 100644 --- a/tests/libslic3r/test_arachne_walls.cpp +++ b/tests/libslic3r/test_arachne_walls.cpp @@ -17,6 +17,9 @@ #include +#include +#include +#include #include "libslic3r/Arachne/WallToolPaths.hpp" #include "libslic3r/Arachne/SkeletalTrapezoidation.hpp" #include "libslic3r/Arachne/utils/ExtrusionLine.hpp" @@ -31,6 +34,14 @@ #include #include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include "libslic3r/Arachne/utils/ExtrusionJunction.hpp" +#include "libslic3r/PerimeterGenerator.hpp" +#include "libslic3r/PrintConfig.hpp" using namespace Slic3r; using namespace Slic3r::Arachne; diff --git a/tests/libslic3r/test_arrange.cpp b/tests/libslic3r/test_arrange.cpp index 3906cba8ba..2f8df3166a 100644 --- a/tests/libslic3r/test_arrange.cpp +++ b/tests/libslic3r/test_arrange.cpp @@ -1,5 +1,19 @@ +#include #include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Config.hpp" +#include +#include +#include +#include +#include +#include +#include +#include #include "libslic3r/Arrange.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" diff --git a/tests/libslic3r/test_bambu_networking.cpp b/tests/libslic3r/test_bambu_networking.cpp index 5cf55030f8..ec16e96c19 100644 --- a/tests/libslic3r/test_bambu_networking.cpp +++ b/tests/libslic3r/test_bambu_networking.cpp @@ -1,5 +1,6 @@ #include +#include #include "slic3r/Utils/bambu_networking.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_buildvolume.cpp b/tests/libslic3r/test_buildvolume.cpp index b2e8040d68..3438f7517f 100644 --- a/tests/libslic3r/test_buildvolume.cpp +++ b/tests/libslic3r/test_buildvolume.cpp @@ -1,5 +1,10 @@ #include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include #include "libslic3r/BuildVolume.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_caddocument.cpp b/tests/libslic3r/test_caddocument.cpp index d69ada09b6..afb4acf409 100644 --- a/tests/libslic3r/test_caddocument.cpp +++ b/tests/libslic3r/test_caddocument.cpp @@ -1,4 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/TriangleMesh.hpp" +#include +#include // Substring assertions, spelled so this file compiles UNCHANGED on both forks. // Catch2 v2 (Snapmaker) spells it Matchers::Contains; v3 (orca_cad / mainline) spells it diff --git a/tests/libslic3r/test_calib.cpp b/tests/libslic3r/test_calib.cpp index 0092a7dedd..81fa59ff93 100644 --- a/tests/libslic3r/test_calib.cpp +++ b/tests/libslic3r/test_calib.cpp @@ -1,9 +1,13 @@ #include #include +#include "libslic3r/CustomGCode.hpp" #include #include +#include +#include +#include #include "libslic3r/calib.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/TriangleMesh.hpp" diff --git a/tests/libslic3r/test_clipper_offset.cpp b/tests/libslic3r/test_clipper_offset.cpp index 3b855130be..7a816a2174 100644 --- a/tests/libslic3r/test_clipper_offset.cpp +++ b/tests/libslic3r/test_clipper_offset.cpp @@ -1,8 +1,15 @@ #include +#include #include #include +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/Polygon.hpp" +#include +#include +#include #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ExPolygon.hpp" #include "libslic3r/SVG.hpp" @@ -22,7 +29,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") { WHEN("Slic3r::offset()") { for (double miter : { 2.0, 1.5, 1.2 }) { DYNAMIC_SECTION("plus 1mm, miter " << miter << "x") { - output = Slic3r::offset(box20mm, 1. * s, ClipperLib::jtMiter, miter); + output = Slic3r::offset(box20mm, 1. * s, jtMiter, miter); #ifdef TESTS_EXPORT_SVGS { SVG svg(debug_out_path("constant_offset_box20mm_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output)); @@ -36,7 +43,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") { } } DYNAMIC_SECTION("minus 1mm, miter " << miter << "x") { - output = Slic3r::offset(box20mm, - 1. * s, ClipperLib::jtMiter, miter); + output = Slic3r::offset(box20mm, - 1. * s, jtMiter, miter); #ifdef TESTS_EXPORT_SVGS { SVG svg(debug_out_path("constant_offset_box20mm_minus1mm_miter%lf.svg", miter).c_str(), get_extents(output)); @@ -96,7 +103,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") { for (double miter : { 2.0, 1.5, 1.2 }) { DYNAMIC_SECTION("miter " << miter << "x") { WHEN("plus 1mm") { - output = Slic3r::offset_ex(box20mm, 1. * s, ClipperLib::jtMiter, miter); + output = Slic3r::offset_ex(box20mm, 1. * s, jtMiter, miter); #ifdef TESTS_EXPORT_SVGS { SVG svg(debug_out_path("constant_offset_box20mm_10mm_hole_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output)); @@ -110,7 +117,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") { } } WHEN("minus 1mm") { - output = Slic3r::offset_ex(box20mm, - 1. * s, ClipperLib::jtMiter, miter); + output = Slic3r::offset_ex(box20mm, - 1. * s, jtMiter, miter); #ifdef TESTS_EXPORT_SVGS { SVG svg(debug_out_path("constant_offset_box20mm_10mm_hole_minus1mm_miter%lf.svg", miter).c_str(), get_extents(output)); @@ -176,7 +183,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") { SECTION("Slic3r::offset()") { for (double miter : { 2.0, 1.5, 1.2 }) { DYNAMIC_SECTION("Outer offset 1mm, miter " << miter << "x") { - output = Slic3r::offset(triangle20mm, offset * s, ClipperLib::jtMiter, 2.0); + output = Slic3r::offset(triangle20mm, offset * s, jtMiter, 2.0); #ifdef TESTS_EXPORT_SVGS { SVG svg(debug_out_path("constant_offset_triangle20mm_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output)); diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index fe9961a771..3b32bba7cf 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -1,15 +1,44 @@ +#include #include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Polyline.hpp" +#include +#include "libslic3r/libslic3r.h" #include #include #include +#include +#include +#include #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ExPolygon.hpp" #include "libslic3r/SVG.hpp" using namespace Slic3r; +// Clipper may start an output polygon at any of its vertices. +static Polygon start_at_min(Polygon polygon) +{ + std::rotate(polygon.points.begin(), std::min_element(polygon.points.begin(), polygon.points.end()), polygon.points.end()); + return polygon; +} +static Polygons start_at_min(Polygons polygons) +{ + for (Polygon &polygon : polygons) + polygon = start_at_min(std::move(polygon)); + return polygons; +} +static ExPolygons start_at_min(ExPolygons expolygons) +{ + for (ExPolygon &expolygon : expolygons) { + expolygon.contour = start_at_min(std::move(expolygon.contour)); + expolygon.holes = start_at_min(std::move(expolygon.holes)); + } + return expolygons; +} + SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { // CCW oriented contour Slic3r::Polygon square{ { 200, 100 }, {200, 200}, {100, 200}, {100, 100} }; @@ -20,25 +49,25 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") { WHEN("offset") { Polygons result = Slic3r::offset(square_with_hole, 5.f); THEN("offset matches") { - REQUIRE(result == Polygons { + REQUIRE(start_at_min(result) == start_at_min(Polygons { { { 205, 205 }, { 95, 205 }, { 95, 95 }, { 205, 95 }, }, - { { 155, 145 }, { 145, 145 }, { 145, 155 }, { 155, 155 } } }); + { { 155, 145 }, { 145, 145 }, { 145, 155 }, { 155, 155 } } })); } } WHEN("offset_ex") { ExPolygons result = Slic3r::offset_ex(square_with_hole, 5.f); THEN("offset matches") { - REQUIRE(result == ExPolygons { { + REQUIRE(start_at_min(result) == start_at_min(ExPolygons { { { { 205, 205 }, { 95, 205 }, { 95, 95 }, { 205, 95 }, }, - { { 145, 145 }, { 145, 155 }, { 155, 155 }, { 155, 145 } } } } ); + { { 145, 145 }, { 145, 155 }, { 155, 155 }, { 155, 145 } } } })); } } WHEN("offset2_ex") { ExPolygons result = Slic3r::offset2_ex({ square_with_hole }, 5.f, -2.f); THEN("offset matches") { - REQUIRE(result == ExPolygons { { + REQUIRE(start_at_min(result) == start_at_min(ExPolygons { { { { 203, 203 }, { 97, 203 }, { 97, 97 }, { 203, 97 } }, - { { 143, 143 }, { 143, 157 }, { 157, 157 }, { 157, 143 } } } } ); + { { 143, 143 }, { 143, 157 }, { 157, 157 }, { 157, 143 } } } })); } } } @@ -225,24 +254,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { } } -template -double polytree_area(const Tree &tree, std::vector *out) -{ - traverse_pt(tree, out); - - return std::accumulate(out->begin(), out->end(), 0.0, - [](double a, const P &p) { return a + p.area(); }); -} - -size_t count_polys(const ExPolygons& expolys) -{ - size_t c = 0; - for (auto &ep : expolys) c += ep.holes.size() + 1; - - return c; -} - -TEST_CASE("Traversing Clipper PolyTree", "[ClipperUtils]") { +TEST_CASE("Top level expolygons of an even-odd union", "[ClipperUtils]") { // Create a polygon representing unit box Polygon unitbox; const auto UNIT = coord_t(1. / SCALING_FACTOR); @@ -266,36 +278,24 @@ TEST_CASE("Traversing Clipper PolyTree", "[ClipperUtils]") { Polygon inner_right = inner_left; inner_right.translate(UNIT * 10, 0); - Polygons reference = union_({box_frame, hole_left, hole_right, inner_left, inner_right}); + ExPolygons reference; + for (const Polygon &polygon : union_({box_frame, hole_left, hole_right, inner_left, inner_right})) + reference.emplace_back(polygon); - ClipperLib::PolyTree tree = union_pt(reference); double area_sum = box_frame.area() + hole_left.area() + hole_right.area() + inner_left.area() + inner_right.area(); REQUIRE(area_sum > 0); - SECTION("Traverse into Polygons WITHOUT spatial ordering") { - Polygons output; - REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output))); - REQUIRE(output.size() == reference.size()); - } - - SECTION("Traverse into ExPolygons WITHOUT spatial ordering") { - ExPolygons output; - REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output))); - REQUIRE(count_polys(output) == reference.size()); - } - - SECTION("Traverse into Polygons WITH spatial ordering") { - Polygons output; - REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output))); - REQUIRE(output.size() == reference.size()); - } - - SECTION("Traverse into ExPolygons WITH spatial ordering") { - ExPolygons output; - REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output))); - REQUIRE(count_polys(output) == reference.size()); - } + ExPolygons nested; + ExPolygons top_level = top_level_expolygons(reference, &nested); + auto area = [](const ExPolygons &expolys) { + return std::accumulate(expolys.begin(), expolys.end(), 0.0, [](double a, const ExPolygon &e) { return a + e.area(); }); + }; + REQUIRE(top_level.size() == 1); + REQUIRE(top_level.front().holes.size() == 2); + REQUIRE(nested.size() == 2); + REQUIRE(area_sum == Catch::Approx(area(top_level) + area(nested))); + REQUIRE(top_level_expolygons(reference).size() == 1); } diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index d7803f300b..bb51735bfe 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include +#include #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfigConstants.hpp" #include "libslic3r/LocalesUtils.hpp" @@ -13,9 +18,16 @@ #include #include +#include "libslic3r/Config.hpp" +#include +#include +#include #include +#include #include +#include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_config_variant_expansion.cpp b/tests/libslic3r/test_config_variant_expansion.cpp index f30ad985e3..240a6e25fa 100644 --- a/tests/libslic3r/test_config_variant_expansion.cpp +++ b/tests/libslic3r/test_config_variant_expansion.cpp @@ -1,5 +1,15 @@ #include +#include "libslic3r/Config.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "libslic3r/PrintConfig.hpp" #include "libslic3r/Preset.hpp" diff --git a/tests/libslic3r/test_drc.cpp b/tests/libslic3r/test_drc.cpp index 917fd5c714..06a329e4e3 100644 --- a/tests/libslic3r/test_drc.cpp +++ b/tests/libslic3r/test_drc.cpp @@ -1,12 +1,21 @@ #include +#include #include "libslic3r/Format/DRC.hpp" #include "libslic3r/TriangleMesh.hpp" #include +#include +#include +#include +#include #include +#include +#include #include +#include +#include #include "test_utils.hpp" diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp index f509c6c0dd..6388dab184 100644 --- a/tests/libslic3r/test_elephant_foot_compensation.cpp +++ b/tests/libslic3r/test_elephant_foot_compensation.cpp @@ -2,7 +2,11 @@ #include #include +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/libslic3r.h" +#include #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ElephantFootCompensation.hpp" #include "libslic3r/ExPolygon.hpp" @@ -14,7 +18,7 @@ using namespace Slic3r; // #define TESTS_EXPORT_SVGS namespace Slic3r { - ClipperLib::Path mittered_offset_path_scaled(const Points& contour, const std::vector& deltas, double miter_limit); + Points mittered_offset_path_scaled(const Points& contour, const std::vector& deltas, double miter_limit); } static ExPolygon spirograph_gear_1mm() diff --git a/tests/libslic3r/test_filament_mixer.cpp b/tests/libslic3r/test_filament_mixer.cpp index ade0c910dc..f43a8e7588 100644 --- a/tests/libslic3r/test_filament_mixer.cpp +++ b/tests/libslic3r/test_filament_mixer.cpp @@ -1,5 +1,13 @@ #include +#include +#include +#include "libslic3r/Config.hpp" +#include +#include +#include +#include +#include #include "libslic3r/FilamentMixer.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/libslic3r/test_fill_corner_smoothing.cpp b/tests/libslic3r/test_fill_corner_smoothing.cpp index a9e752f250..ebad09e9e5 100644 --- a/tests/libslic3r/test_fill_corner_smoothing.cpp +++ b/tests/libslic3r/test_fill_corner_smoothing.cpp @@ -2,8 +2,12 @@ #include #include +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/Polygon.hpp" #include +#include #include "libslic3r/Fill/FillCornerSmoothing.hpp" #include "libslic3r/Polyline.hpp" #include "libslic3r/libslic3r.h" diff --git a/tests/libslic3r/test_fill_plane_path.cpp b/tests/libslic3r/test_fill_plane_path.cpp index 7fc7f4a6b0..e28d74b4fc 100644 --- a/tests/libslic3r/test_fill_plane_path.cpp +++ b/tests/libslic3r/test_fill_plane_path.cpp @@ -2,9 +2,18 @@ #include #include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Fill/FillBase.hpp" +#include +#include +#include "libslic3r/Config.hpp" #include #include +#include +#include +#include #include "libslic3r/Fill/FillPlanePath.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp index b4bbe86cc6..6f12b1113a 100644 --- a/tests/libslic3r/test_geometry.cpp +++ b/tests/libslic3r/test_geometry.cpp @@ -1,5 +1,8 @@ +#include #include +#include +#include #include "libslic3r/Point.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/Polygon.hpp" @@ -17,7 +20,14 @@ #include "../libnest2d/printer_parts.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include #include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index dc39b47373..6e1baef4cc 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -1,7 +1,10 @@ #include #include #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/libslic3r.h" +#include #include "libslic3r/SLA/Hollowing.hpp" #include "test_utils.hpp" diff --git a/tests/libslic3r/test_indexed_triangle_set.cpp b/tests/libslic3r/test_indexed_triangle_set.cpp index 43116936d3..c65bf589a8 100644 --- a/tests/libslic3r/test_indexed_triangle_set.cpp +++ b/tests/libslic3r/test_indexed_triangle_set.cpp @@ -1,8 +1,17 @@ +#include +#include +#include #include #include +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include #include #include +#include +#include +#include #include "libslic3r/TriangleMesh.hpp" #include "test_utils.hpp" diff --git a/tests/libslic3r/test_instance_lock.cpp b/tests/libslic3r/test_instance_lock.cpp index 207dd77173..5ee14c665f 100644 --- a/tests/libslic3r/test_instance_lock.cpp +++ b/tests/libslic3r/test_instance_lock.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -6,6 +7,7 @@ #include +#include #include "libslic3r/InstanceLock.hpp" #include "test_utils.hpp" diff --git a/tests/libslic3r/test_lay_on_face.cpp b/tests/libslic3r/test_lay_on_face.cpp index 60226a9aab..76a197efe7 100644 --- a/tests/libslic3r/test_lay_on_face.cpp +++ b/tests/libslic3r/test_lay_on_face.cpp @@ -1,5 +1,15 @@ #include +#include "libslic3r/Point.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include #include "libslic3r/LayOnFace.hpp" #include "libslic3r/Model.hpp" diff --git a/tests/libslic3r/test_locales_utils.cpp b/tests/libslic3r/test_locales_utils.cpp index 6f1528649d..2bb134af6b 100644 --- a/tests/libslic3r/test_locales_utils.cpp +++ b/tests/libslic3r/test_locales_utils.cpp @@ -1,7 +1,9 @@ #include #include +#include +#include #include "libslic3r/LocalesUtils.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_marchingsquares.cpp b/tests/libslic3r/test_marchingsquares.cpp index 9a11f49faa..e9d0f8ebc2 100644 --- a/tests/libslic3r/test_marchingsquares.cpp +++ b/tests/libslic3r/test_marchingsquares.cpp @@ -2,6 +2,28 @@ #define NOMINMAX #endif +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Polygon.hpp" +#include +#include +#include "libslic3r/SLA/RasterBase.hpp" +#include +#include +#include +#include +#include "libslic3r/ExPolygon.hpp" +#include +#include +#include +#include +#include "libslic3r/TriangleMesh.hpp" +#include +#include + #include #include "test_utils.hpp" diff --git a/tests/libslic3r/test_meshboolean.cpp b/tests/libslic3r/test_meshboolean.cpp index b7208349cc..4c0faa1bb0 100644 --- a/tests/libslic3r/test_meshboolean.cpp +++ b/tests/libslic3r/test_meshboolean.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "test_utils.hpp" #include diff --git a/tests/libslic3r/test_minimum_spanning_tree.cpp b/tests/libslic3r/test_minimum_spanning_tree.cpp index 5f9998171c..b6685b0d1e 100644 --- a/tests/libslic3r/test_minimum_spanning_tree.cpp +++ b/tests/libslic3r/test_minimum_spanning_tree.cpp @@ -1,7 +1,11 @@ #include #include +#include +#include +#include +#include #include "libslic3r/MinimumSpanningTree.hpp" #include "libslic3r/Point.hpp" diff --git a/tests/libslic3r/test_miniz_extension.cpp b/tests/libslic3r/test_miniz_extension.cpp index ff3274a886..3a10a8eb8e 100644 --- a/tests/libslic3r/test_miniz_extension.cpp +++ b/tests/libslic3r/test_miniz_extension.cpp @@ -1,5 +1,12 @@ +#include +#include +#include +#include #include +#include +#include +#include #include "libslic3r/miniz_extension.hpp" #include "test_utils.hpp" @@ -7,8 +14,11 @@ #include #include +#include #include +#include #include +#include #include #include #include diff --git a/tests/libslic3r/test_model.cpp b/tests/libslic3r/test_model.cpp index 3a580e3be2..24d690ac9e 100644 --- a/tests/libslic3r/test_model.cpp +++ b/tests/libslic3r/test_model.cpp @@ -1,5 +1,10 @@ #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/BoundingBox.hpp" +#include "libslic3r/Point.hpp" +#include #include "libslic3r/Model.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_multimaterial_segmentation.cpp b/tests/libslic3r/test_multimaterial_segmentation.cpp index 271b9d5660..065a143ce1 100644 --- a/tests/libslic3r/test_multimaterial_segmentation.cpp +++ b/tests/libslic3r/test_multimaterial_segmentation.cpp @@ -3,6 +3,12 @@ // MultiMaterialSegmentation.hpp declares boost::polygon traits for ColoredLine, so its // geometry/boost dependencies must be included first. #include +#include +#include +#include +#include +#include +#include #include "libslic3r/Line.hpp" #include "libslic3r/Flow.hpp" #include "libslic3r/MultiMaterialSegmentation.hpp" diff --git a/tests/libslic3r/test_mutable_polygon.cpp b/tests/libslic3r/test_mutable_polygon.cpp index 906dffe50a..a233454427 100644 --- a/tests/libslic3r/test_mutable_polygon.cpp +++ b/tests/libslic3r/test_mutable_polygon.cpp @@ -1,5 +1,9 @@ #include +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/Polygon.hpp" +#include #include "libslic3r/Point.hpp" #include "libslic3r/MutablePolygon.hpp" diff --git a/tests/libslic3r/test_mutable_priority_queue.cpp b/tests/libslic3r/test_mutable_priority_queue.cpp index db7124df78..67191793da 100644 --- a/tests/libslic3r/test_mutable_priority_queue.cpp +++ b/tests/libslic3r/test_mutable_priority_queue.cpp @@ -1,8 +1,15 @@ +#include #include #include +#include +#include +#include +#include #include +#include +#include #include "libslic3r/MutablePriorityQueue.hpp" // based on https://raw.githubusercontent.com/rollbear/prio_queue/master/self_test.cpp diff --git a/tests/libslic3r/test_nozzle_volume_type.cpp b/tests/libslic3r/test_nozzle_volume_type.cpp index 99ad375f93..289133bb03 100644 --- a/tests/libslic3r/test_nozzle_volume_type.cpp +++ b/tests/libslic3r/test_nozzle_volume_type.cpp @@ -1,5 +1,9 @@ #include +#include +#include "libslic3r/Config.hpp" +#include +#include #include "libslic3r/PrintConfig.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_obj.cpp b/tests/libslic3r/test_obj.cpp index 2cbf57ff04..abab016b2a 100644 --- a/tests/libslic3r/test_obj.cpp +++ b/tests/libslic3r/test_obj.cpp @@ -1,9 +1,16 @@ +#include #include +#include +#include +#include #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Format/OBJ.hpp" #include +#include +#include "libslic3r/Point.hpp" +#include #include "test_utils.hpp" diff --git a/tests/libslic3r/test_optimizers.cpp b/tests/libslic3r/test_optimizers.cpp index 8783ac1428..232481f23c 100644 --- a/tests/libslic3r/test_optimizers.cpp +++ b/tests/libslic3r/test_optimizers.cpp @@ -1,9 +1,13 @@ #include +#include #include "test_utils.hpp" +#include #include #include +#include "libslic3r/Optimize/Optimizer.hpp" +#include "libslic3r/libslic3r.h" void check_opt_result(double score, double ref, double abs_err, double rel_err) { diff --git a/tests/libslic3r/test_ordering_strategies.cpp b/tests/libslic3r/test_ordering_strategies.cpp index ddbca07ae6..f6e0cd94f2 100644 --- a/tests/libslic3r/test_ordering_strategies.cpp +++ b/tests/libslic3r/test_ordering_strategies.cpp @@ -1,4 +1,12 @@ +#include #include +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include #define SLIC3R_TEST_HARNESS diff --git a/tests/libslic3r/test_parallel_resolve.cpp b/tests/libslic3r/test_parallel_resolve.cpp index 76811f1475..4e7e52dca2 100644 --- a/tests/libslic3r/test_parallel_resolve.cpp +++ b/tests/libslic3r/test_parallel_resolve.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,6 +10,7 @@ #include #include +#include #include "libslic3r/ParallelResolve.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index 4a95156c34..0a490a6bdd 100644 --- a/tests/libslic3r/test_placeholder_parser.cpp +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -1,5 +1,12 @@ #include +#include +#include +#include "libslic3r/Config.hpp" +#include +#include +#include +#include #include "libslic3r/PlaceholderParser.hpp" #include "libslic3r/PrintConfig.hpp" diff --git a/tests/libslic3r/test_polygon.cpp b/tests/libslic3r/test_polygon.cpp index feae4ff50c..08fd21d3c0 100644 --- a/tests/libslic3r/test_polygon.cpp +++ b/tests/libslic3r/test_polygon.cpp @@ -1,5 +1,9 @@ +#include #include +#include +#include "libslic3r/libslic3r.h" +#include #include "libslic3r/Point.hpp" #include "libslic3r/Polygon.hpp" diff --git a/tests/libslic3r/test_precise_seam_3mf.cpp b/tests/libslic3r/test_precise_seam_3mf.cpp index 6449236744..cda140ebce 100644 --- a/tests/libslic3r/test_precise_seam_3mf.cpp +++ b/tests/libslic3r/test_precise_seam_3mf.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include +#include #include "test_utils.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/PrintConfig.hpp" @@ -12,7 +17,13 @@ #include #include +#include "libslic3r/Config.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include +#include "libslic3r/Geometry.hpp" +#include #include +#include #include using namespace Slic3r; diff --git a/tests/libslic3r/test_preset_bundle_loading.cpp b/tests/libslic3r/test_preset_bundle_loading.cpp index 4741e28f6b..c8cc1784de 100644 --- a/tests/libslic3r/test_preset_bundle_loading.cpp +++ b/tests/libslic3r/test_preset_bundle_loading.cpp @@ -1,9 +1,19 @@ +#include +#include +#include +#include #include #include #include +#include #include +#include +#include +#include +#include +#include #include "libslic3r/PresetBundle.hpp" #include "libslic3r/ParallelResolve.hpp" #include "libslic3r/AppConfig.hpp" @@ -17,6 +27,19 @@ #include #include #include +#include +#include +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Preset.hpp" +#include +#include "libslic3r/Config.hpp" +#include +#include "libslic3r/libslic3r.h" +#include "libslic3r/PublishSettings.hpp" +#include +#include "libslic3r/TriangleSelector.hpp" +#include +#include #ifndef _WIN32 #include // geteuid diff --git a/tests/libslic3r/test_preset_diff.cpp b/tests/libslic3r/test_preset_diff.cpp index 22255c049e..036e2aa922 100644 --- a/tests/libslic3r/test_preset_diff.cpp +++ b/tests/libslic3r/test_preset_diff.cpp @@ -1,9 +1,15 @@ #include +#include +#include #include "libslic3r/Preset.hpp" #include "libslic3r/PrintConfig.hpp" #include +#include "libslic3r/Config.hpp" +#include +#include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_preset_options.cpp b/tests/libslic3r/test_preset_options.cpp index 1763f5fbc7..cf878ca9f8 100644 --- a/tests/libslic3r/test_preset_options.cpp +++ b/tests/libslic3r/test_preset_options.cpp @@ -16,10 +16,14 @@ #include +#include +#include #include "libslic3r/Preset.hpp" #include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Config.hpp" #include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_preset_setting_id.cpp b/tests/libslic3r/test_preset_setting_id.cpp index 5c06335381..0b5736ad26 100644 --- a/tests/libslic3r/test_preset_setting_id.cpp +++ b/tests/libslic3r/test_preset_setting_id.cpp @@ -1,5 +1,8 @@ #include +#include +#include +#include #include "libslic3r/Preset.hpp" using namespace Slic3r; diff --git a/tests/libslic3r/test_sketchconstraints.cpp b/tests/libslic3r/test_sketchconstraints.cpp index d0c5844b40..2142398e68 100644 --- a/tests/libslic3r/test_sketchconstraints.cpp +++ b/tests/libslic3r/test_sketchconstraints.cpp @@ -1,4 +1,11 @@ #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include +#include +#include +#include +#include +#include +#include #include "libslic3r/CAD/SketchConstraints.hpp" #include "libslic3r/CAD/SketchEngine.hpp" diff --git a/tests/libslic3r/test_sketchedit.cpp b/tests/libslic3r/test_sketchedit.cpp index 634e743b99..b289b71e69 100644 --- a/tests/libslic3r/test_sketchedit.cpp +++ b/tests/libslic3r/test_sketchedit.cpp @@ -1,9 +1,16 @@ +#include +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include +#include +#include #include "libslic3r/CAD/SketchEngine.hpp" #include #include #include #include +#include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_sketchimport.cpp b/tests/libslic3r/test_sketchimport.cpp index 3e3f7c906e..3e6636fd7d 100644 --- a/tests/libslic3r/test_sketchimport.cpp +++ b/tests/libslic3r/test_sketchimport.cpp @@ -1,10 +1,16 @@ +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include +#include +#include #include "libslic3r/CAD/SketchImport.hpp" #include "libslic3r/Utils.hpp" // resources_dir #include "test_utils.hpp" // ScopedTemporaryFile +#include #include +#include "libslic3r/Point.hpp" #include using namespace Slic3r; diff --git a/tests/libslic3r/test_sketchinference.cpp b/tests/libslic3r/test_sketchinference.cpp index cbdd90628b..6ff9768b8f 100644 --- a/tests/libslic3r/test_sketchinference.cpp +++ b/tests/libslic3r/test_sketchinference.cpp @@ -1,4 +1,9 @@ +#include +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include "libslic3r/CAD/SketchEngine.hpp" +#include "libslic3r/Point.hpp" +#include using Catch::Approx; // v3 scopes Approx into the Catch namespace; v2 had it at global scope #include "libslic3r/CAD/SketchInference.hpp" diff --git a/tests/libslic3r/test_sketchprofile.cpp b/tests/libslic3r/test_sketchprofile.cpp index 7f455eb936..6c33599847 100644 --- a/tests/libslic3r/test_sketchprofile.cpp +++ b/tests/libslic3r/test_sketchprofile.cpp @@ -9,11 +9,19 @@ // So these cases assert the loop, not the coordinates. That is the invariant every sketch // operation has to preserve and the only one that predicts whether the GUI can build a solid // out of the result. +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include +#include +#include #include "libslic3r/CAD/SketchEngine.hpp" #include #include #include +#include "libslic3r/Point.hpp" +#include +#include +#include using namespace Slic3r; using Catch::Matchers::WithinAbs; diff --git a/tests/libslic3r/test_slvs_constraints.cpp b/tests/libslic3r/test_slvs_constraints.cpp index 6dfac07348..4f5c27ba7d 100644 --- a/tests/libslic3r/test_slvs_constraints.cpp +++ b/tests/libslic3r/test_slvs_constraints.cpp @@ -1,4 +1,9 @@ +#include +#include #include // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp) +#include "libslic3r/Point.hpp" +#include +#include using Catch::Approx; // v3 scopes Approx into the Catch namespace; v2 had it at global scope #include "libslic3r/CAD/SketchSolver.hpp" diff --git a/tests/libslic3r/test_step.cpp b/tests/libslic3r/test_step.cpp index a2aa7218f1..3635c977dd 100644 --- a/tests/libslic3r/test_step.cpp +++ b/tests/libslic3r/test_step.cpp @@ -1,7 +1,11 @@ #include #include +#include +#include +#include +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/STEP.hpp" #include "test_utils.hpp" diff --git a/tests/libslic3r/test_stl.cpp b/tests/libslic3r/test_stl.cpp index a8addeca16..0223392c3f 100644 --- a/tests/libslic3r/test_stl.cpp +++ b/tests/libslic3r/test_stl.cpp @@ -1,5 +1,8 @@ #include +#include +#include "libslic3r/Point.hpp" +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/STL.hpp" diff --git a/tests/libslic3r/test_texture_displacement.cpp b/tests/libslic3r/test_texture_displacement.cpp index 04713d3fd9..1d9a89481b 100644 --- a/tests/libslic3r/test_texture_displacement.cpp +++ b/tests/libslic3r/test_texture_displacement.cpp @@ -1,6 +1,29 @@ #ifndef NOMINMAX #define NOMINMAX #endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/Point.hpp" +#include +#include +#include +#include +#include "libslic3r/TextureBake/TextureBakeDisplace.hpp" +#include "libslic3r/TextureBake/TextureBakeIndex.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include #include #include diff --git a/tests/libslic3r/test_timeutils.cpp b/tests/libslic3r/test_timeutils.cpp index 221dd07d81..213b5e6788 100644 --- a/tests/libslic3r/test_timeutils.cpp +++ b/tests/libslic3r/test_timeutils.cpp @@ -1,10 +1,13 @@ #include +#include #include "libslic3r/Time.hpp" +#include #include #include #include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_toolordering_nozzle_group.cpp b/tests/libslic3r/test_toolordering_nozzle_group.cpp index 4074a80995..7c41b2315e 100644 --- a/tests/libslic3r/test_toolordering_nozzle_group.cpp +++ b/tests/libslic3r/test_toolordering_nozzle_group.cpp @@ -1,5 +1,9 @@ +#include #include +#include +#include +#include #include "libslic3r/FilamentGroupUtils.hpp" #include "libslic3r/MultiNozzleUtils.hpp" #include "libslic3r/PrintConfig.hpp" @@ -11,7 +15,11 @@ #include "test_utils.hpp" #include +#include "libslic3r/Config.hpp" +#include "libslic3r/GCode/ToolOrderUtils.hpp" +#include "libslic3r/PrintBase.hpp" #include +#include #include #include #include @@ -510,6 +518,22 @@ TEST_CASE("Print config-index resolvers pick per-filament Hybrid slots", "[Print } } +TEST_CASE("Regrouping or rewriting the filament maps changes the config-index generation", "[Print][H2C]") +{ + Model model; + model.add_object("cube", "", make_cube(20, 20, 20))->add_instance(); + Print print; + print.apply(model, DynamicPrintConfig::full_print_config()); + + size_t generation = print.config_index_generation(); + print.set_nozzle_group_result(nullptr); + REQUIRE(print.config_index_generation() != generation); + + generation = print.config_index_generation(); + print.update_filament_maps_to_config({1}, {(int) nvtStandard}, {0}); + REQUIRE(print.config_index_generation() != generation); +} + TEST_CASE("Re-applying an unchanged config after slicing keeps the result valid", "[Print][H2C]") { // apply() rebuilds m_config.filament_map_2 to the real per-filament slot map, while the diff --git a/tests/libslic3r/test_triangle_selector.cpp b/tests/libslic3r/test_triangle_selector.cpp index c207ee66ad..9886308bdd 100644 --- a/tests/libslic3r/test_triangle_selector.cpp +++ b/tests/libslic3r/test_triangle_selector.cpp @@ -1,9 +1,16 @@ #include +#include +#include +#include #include "libslic3r/TriangleSelector.hpp" #include "libslic3r/TriangleMesh.hpp" #include +#include "libslic3r/libslic3r.h" +#include +#include +#include using namespace Slic3r; diff --git a/tests/libslic3r/test_utils.cpp b/tests/libslic3r/test_utils.cpp index ad5110aa5e..35094f056a 100644 --- a/tests/libslic3r/test_utils.cpp +++ b/tests/libslic3r/test_utils.cpp @@ -1,5 +1,14 @@ +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include "libslic3r/Utils.hpp" #include "test_utils.hpp" @@ -8,10 +17,14 @@ #include #include +#include #include +#include +#include #include #include #include +#include #ifndef _WIN32 #include // getuid diff --git a/tests/libslic3r/test_vendor_cache.cpp b/tests/libslic3r/test_vendor_cache.cpp index be8b97943c..b78ce77e1f 100644 --- a/tests/libslic3r/test_vendor_cache.cpp +++ b/tests/libslic3r/test_vendor_cache.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -5,19 +7,32 @@ #include #include #include +#include #include #include #include +#include +#include +#include "libslic3r/Semver.hpp" +#include "libslic3r/Config.hpp" #include #include #include #include #include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include #include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetCacheFormat.hpp" #include "libslic3r/Preset.hpp" diff --git a/tests/libslic3r/test_voronoi.cpp b/tests/libslic3r/test_voronoi.cpp index b86f448c02..b512fe38fe 100644 --- a/tests/libslic3r/test_voronoi.cpp +++ b/tests/libslic3r/test_voronoi.cpp @@ -1,6 +1,14 @@ +#include #include +#include #include "test_utils.hpp" +#include "libslic3r/Geometry/Voronoi.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include +#include +#include "libslic3r/BoundingBox.hpp" #include #include #include @@ -9,8 +17,11 @@ #include #include +#include "libslic3r/libslic3r.h" +#include #include #include +#include // #define VORONOI_DEBUG_OUT diff --git a/tests/libslic3r/test_wipe_path.cpp b/tests/libslic3r/test_wipe_path.cpp index b637ad2b87..731a8626d4 100644 --- a/tests/libslic3r/test_wipe_path.cpp +++ b/tests/libslic3r/test_wipe_path.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include +#include #include "libslic3r/GCode/WipePathHelpers.hpp" #include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/Polyline.hpp" @@ -9,7 +14,12 @@ #include #include +#include "libslic3r/ExtrusionEntity.hpp" +#include #include +#include +#include +#include using namespace Slic3r; using Slic3r::AABBTreeLines::LinesDistancer; diff --git a/tests/libslic3r/test_wipe_tower.cpp b/tests/libslic3r/test_wipe_tower.cpp index 6f6daa74b8..9c64ae1b53 100644 --- a/tests/libslic3r/test_wipe_tower.cpp +++ b/tests/libslic3r/test_wipe_tower.cpp @@ -1,7 +1,17 @@ #include #include +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/GCode/WipeTower.hpp" diff --git a/tests/libslic3r/test_wipe_tower_estimate.cpp b/tests/libslic3r/test_wipe_tower_estimate.cpp index 22b9b2d6c5..6f0b268801 100644 --- a/tests/libslic3r/test_wipe_tower_estimate.cpp +++ b/tests/libslic3r/test_wipe_tower_estimate.cpp @@ -1,5 +1,10 @@ +#include #include +#include +#include +#include +#include #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/GCode/WipeTower.hpp" @@ -8,8 +13,14 @@ #include "libslic3r/PrintConfig.hpp" #include +#include "libslic3r/Config.hpp" +#include +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" #include #include +#include using namespace Slic3r; using Catch::Matchers::WithinAbs; diff --git a/tests/sla_print/sla_print_tests.cpp b/tests/sla_print/sla_print_tests.cpp index 308925a163..e095c0543a 100644 --- a/tests/sla_print/sla_print_tests.cpp +++ b/tests/sla_print/sla_print_tests.cpp @@ -1,14 +1,34 @@ +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/SLA/SupportTree.hpp" +#include "libslic3r/SLA/SupportPointGenerator.hpp" +#include "libslic3r/MTUtils.hpp" +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/Point.hpp" +#include +#include "libslic3r/SLA/Pad.hpp" +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/SLA/AGGRaster.hpp" +#include +#include "libslic3r/SLA/SupportTreeBuilder.hpp" +#include "libslic3r/Execution/Execution.hpp" +#include "libslic3r/Execution/ExecutionTBB.hpp" #include #include #include #include #include +#include +#include #include "sla_test_utils.hpp" +#include "test_utils.hpp" #include #include #include +#include namespace { diff --git a/tests/sla_print/sla_raycast_tests.cpp b/tests/sla_print/sla_raycast_tests.cpp index 8a520a241f..e050e35845 100644 --- a/tests/sla_print/sla_raycast_tests.cpp +++ b/tests/sla_print/sla_raycast_tests.cpp @@ -1,8 +1,15 @@ +#include #include +#include +#include #include "test_utils.hpp" +#include "libslic3r/Point.hpp" +#include +#include #include #include +#include #include "sla_test_utils.hpp" diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 32f049d78e..091bfa2d66 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -1,8 +1,21 @@ +#include #include +#include #include "test_utils.hpp" +#include +#include #include #include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/SLA/SpatIndex.hpp" +#include +#include "libslic3r/SLA/SupportPointGenerator.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/SLA/Hollowing.hpp" #include "sla_test_utils.hpp" diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index a74bad09e4..2a769692c8 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -1,8 +1,39 @@ #include "sla_test_utils.hpp" +#include +#include +#include #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/SLA/AGGRaster.hpp" +#include "test_utils.hpp" +#include +#include +#include +#include #include +#include +#include "libslic3r/SLA/SupportTree.hpp" +#include "libslic3r/SLA/Hollowing.hpp" +#include +#include "libslic3r/ExPolygon.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/libslic3r.h" +#include +#include "libslic3r/SVG.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/MTUtils.hpp" +#include "libslic3r/SLA/IndexedMesh.hpp" +#include "libslic3r/SLA/SupportPointGenerator.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" +#include "libslic3r/SLA/SupportTreeBuildsteps.hpp" +#include +#include "libslic3r/SLA/SupportTreeBuilder.hpp" +#include "libslic3r/SLA/Pad.hpp" +#include "libslic3r/SLA/ConcaveHull.hpp" +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/BoundingBox.hpp" void test_support_model_collision(const std::string &obj_filename, const sla::SupportTreeConfig &input_supportcfg, @@ -261,7 +292,8 @@ static void _test_concave_hull(const Polygons &hull, const ExPolygons &polys) REQUIRE(cchull_holes == 0); - Polygons intr = diff(to_polygons(polys), hull); + // Hull vertices where the connectors cross the input are rounded, so the hull may miss the input by a unit or two. + Polygons intr = diff(to_polygons(polys), offset(hull, float(SCALED_EPSILON))); REQUIRE(intr.empty()); } diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp index 1d27030c9d..03d4bfd3c9 100644 --- a/tests/sla_print/sla_test_utils.hpp +++ b/tests/sla_print/sla_test_utils.hpp @@ -2,11 +2,26 @@ #define SLA_TEST_UTILS_HPP #include +#include #include "test_utils.hpp" // Debug +#include +#include +#include +#include #include +#include +#include "libslic3r/SLA/SupportTree.hpp" +#include "libslic3r/SLA/Hollowing.hpp" +#include +#include +#include +#include "libslic3r/SLA/RasterBase.hpp" +#include "libslic3r/SLA/SupportPoint.hpp" #include +#include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Format/OBJ.hpp" diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index 4d419a4b57..566835f495 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(${_TEST_NAME}_tests test_device_manager_integration.cpp test_web_media_controller.cpp test_scene_raycaster.cpp + test_scene_benchmark.cpp test_lazy.cpp test_prebuild_queue.cpp test_staged_build.cpp diff --git a/tests/slic3rutils/plugin_test_utils.hpp b/tests/slic3rutils/plugin_test_utils.hpp index cbdcf1ff95..133a5aac9e 100644 --- a/tests/slic3rutils/plugin_test_utils.hpp +++ b/tests/slic3rutils/plugin_test_utils.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/tests/slic3rutils/python_test_support.hpp b/tests/slic3rutils/python_test_support.hpp index 29747a88c4..e9b0aaac8d 100644 --- a/tests/slic3rutils/python_test_support.hpp +++ b/tests/slic3rutils/python_test_support.hpp @@ -4,7 +4,9 @@ // interpreter (test_plugin_host_api.cpp, test_slicing_pipeline_bindings.cpp, ...). #include #include +#include #include +#include #include #include #include diff --git a/tests/slic3rutils/slic3rutils_tests_main.cpp b/tests/slic3rutils/slic3rutils_tests_main.cpp index 176e34a5df..f8d2b4fac5 100644 --- a/tests/slic3rutils/slic3rutils_tests_main.cpp +++ b/tests/slic3rutils/slic3rutils_tests_main.cpp @@ -1,5 +1,6 @@ #include +#include #include "slic3r/Utils/Http.hpp" TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") { diff --git a/tests/slic3rutils/test_action_source.cpp b/tests/slic3rutils/test_action_source.cpp index eec38d7291..315721ca9b 100644 --- a/tests/slic3rutils/test_action_source.cpp +++ b/tests/slic3rutils/test_action_source.cpp @@ -1,11 +1,15 @@ +#include +#include #include +#include #include "slic3r/GUI/ActionRegistry.hpp" #include "slic3r/GUI/NativeCommands.hpp" #include "slic3r/GUI/SettingsIndex.hpp" #include +#include "libslic3r/Config.hpp" #include #include #include @@ -238,7 +242,8 @@ TEST_CASE("Native command catalog includes the Help and developer-mode commands" const Slic3r::GUI::NativeCommand* first = find("help_keyboard_shortcuts"); REQUIRE(first != nullptr); for (const char* key : {"help_setup_wizard", "help_open_config_folder", "help_troubleshoot", "help_network_test", - "help_tip_of_the_day", "help_check_updates", "help_about", "open_wiki", "open_youtube"}) { + "help_benchmark_3d_scene", "help_tip_of_the_day", "help_check_updates", "help_about", "open_wiki", + "open_youtube"}) { const Slic3r::GUI::NativeCommand* c = find(key); REQUIRE(c != nullptr); CHECK(c->group == first->group); diff --git a/tests/slic3rutils/test_bambu_filament_ids.cpp b/tests/slic3rutils/test_bambu_filament_ids.cpp index 5f6215d7ca..7d9e0df1f1 100644 --- a/tests/slic3rutils/test_bambu_filament_ids.cpp +++ b/tests/slic3rutils/test_bambu_filament_ids.cpp @@ -2,7 +2,9 @@ #include #include #include +#include +#include #include "libslic3r/Utils.hpp" #include "slic3r/Utils/BBLPrinterAgent.hpp" #include "slic3r/Utils/OrcaPrinterAgent.hpp" diff --git a/tests/slic3rutils/test_creality_cfs_match.cpp b/tests/slic3rutils/test_creality_cfs_match.cpp index 06606684b7..6b8faf4b79 100644 --- a/tests/slic3rutils/test_creality_cfs_match.cpp +++ b/tests/slic3rutils/test_creality_cfs_match.cpp @@ -1,4 +1,6 @@ +#include #include +#include #include "libslic3r/Preset.hpp" #include "libslic3r/PresetBundle.hpp" diff --git a/tests/slic3rutils/test_dev_mapping.cpp b/tests/slic3rutils/test_dev_mapping.cpp index 658117d2e4..4e32bcc20d 100644 --- a/tests/slic3rutils/test_dev_mapping.cpp +++ b/tests/slic3rutils/test_dev_mapping.cpp @@ -13,6 +13,12 @@ #include #endif +#include +#include "slic3r/GUI/DeviceCore/DevDefs.h" +#include "libslic3r/ProjectTask.hpp" +#include +#include + #include #include diff --git a/tests/slic3rutils/test_device_manager_integration.cpp b/tests/slic3rutils/test_device_manager_integration.cpp index 2b042d4f8e..7e58dc7696 100644 --- a/tests/slic3rutils/test_device_manager_integration.cpp +++ b/tests/slic3rutils/test_device_manager_integration.cpp @@ -1,8 +1,11 @@ +#include #include #include #include #include +#include "slic3r/Utils/IPrinterAgent.hpp" +#include "slic3r/Utils/CloudProvider.hpp" #include #include #include diff --git a/tests/slic3rutils/test_device_progress.cpp b/tests/slic3rutils/test_device_progress.cpp index 96dead46f0..3d42b012a2 100644 --- a/tests/slic3rutils/test_device_progress.cpp +++ b/tests/slic3rutils/test_device_progress.cpp @@ -12,6 +12,9 @@ #include #endif +#include +#include "libslic3r/ProjectTask.hpp" + #include #include diff --git a/tests/slic3rutils/test_filament_bitmap_utils.cpp b/tests/slic3rutils/test_filament_bitmap_utils.cpp index 997a119521..df5bba0567 100644 --- a/tests/slic3rutils/test_filament_bitmap_utils.cpp +++ b/tests/slic3rutils/test_filament_bitmap_utils.cpp @@ -11,6 +11,12 @@ #include #endif +#include +#include "libslic3r/Config.hpp" +#include +#include +#include + #include #include diff --git a/tests/slic3rutils/test_file_url.cpp b/tests/slic3rutils/test_file_url.cpp index 484067b57e..f22b21612a 100644 --- a/tests/slic3rutils/test_file_url.cpp +++ b/tests/slic3rutils/test_file_url.cpp @@ -1,10 +1,13 @@ #include #include +#include #include "slic3r/GUI/GUI.hpp" #include +#include +#include #include using namespace Slic3r::GUI; diff --git a/tests/slic3rutils/test_lazy.cpp b/tests/slic3rutils/test_lazy.cpp index c04a27e9d1..156c478791 100644 --- a/tests/slic3rutils/test_lazy.cpp +++ b/tests/slic3rutils/test_lazy.cpp @@ -2,9 +2,12 @@ #include #include +#include "slic3r/GUI/StagedBuild.hpp" #include +#include #include +#include #include "slic3r/GUI/Lazy.hpp" using Slic3r::GUI::Lazy; diff --git a/tests/slic3rutils/test_network_versions.cpp b/tests/slic3rutils/test_network_versions.cpp index 349082a965..bfddcb5423 100644 --- a/tests/slic3rutils/test_network_versions.cpp +++ b/tests/slic3rutils/test_network_versions.cpp @@ -1,8 +1,13 @@ +#include #include #include #include +#include +#include "libslic3r/AppConfig.hpp" +#include +#include #include "libslic3r/Utils.hpp" #include "slic3r/Utils/bambu_networking.hpp" diff --git a/tests/slic3rutils/test_orca_cloud_agent.cpp b/tests/slic3rutils/test_orca_cloud_agent.cpp index 5f325751cb..8657310f27 100644 --- a/tests/slic3rutils/test_orca_cloud_agent.cpp +++ b/tests/slic3rutils/test_orca_cloud_agent.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -6,6 +8,7 @@ #include #include +#include #include "slic3r/Utils/OrcaCloudServiceAgent.hpp" #include "test_utils.hpp" diff --git a/tests/slic3rutils/test_plugin_audit.cpp b/tests/slic3rutils/test_plugin_audit.cpp index 71ce692671..ca8c46fabd 100644 --- a/tests/slic3rutils/test_plugin_audit.cpp +++ b/tests/slic3rutils/test_plugin_audit.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include @@ -5,6 +7,8 @@ #include #include // secret_constants::USER_SECRET_FILENAME +#include +#include "libslic3r_version.h" #include "plugin_test_utils.hpp" #include diff --git a/tests/slic3rutils/test_plugin_capabilities_in_use.cpp b/tests/slic3rutils/test_plugin_capabilities_in_use.cpp index 16ba6e91ac..e33c9980dd 100644 --- a/tests/slic3rutils/test_plugin_capabilities_in_use.cpp +++ b/tests/slic3rutils/test_plugin_capabilities_in_use.cpp @@ -1,5 +1,7 @@ +#include #include +#include "libslic3r/Config.hpp" #include #include #include diff --git a/tests/slic3rutils/test_plugin_capability_config.cpp b/tests/slic3rutils/test_plugin_capability_config.cpp index 39ecd1002d..34c380bba9 100644 --- a/tests/slic3rutils/test_plugin_capability_config.cpp +++ b/tests/slic3rutils/test_plugin_capability_config.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -7,7 +8,11 @@ #include #include +#include #include "plugin_test_utils.hpp" +#include +#include +#include #include #include diff --git a/tests/slic3rutils/test_plugin_cloud_metadata.cpp b/tests/slic3rutils/test_plugin_cloud_metadata.cpp index 241ef3ed90..09ac877eca 100644 --- a/tests/slic3rutils/test_plugin_cloud_metadata.cpp +++ b/tests/slic3rutils/test_plugin_cloud_metadata.cpp @@ -1,5 +1,8 @@ +#include +#include #include +#include #include #include #include @@ -8,6 +11,8 @@ #include #include +#include +#include #include "plugin_test_utils.hpp" #include diff --git a/tests/slic3rutils/test_plugin_config.cpp b/tests/slic3rutils/test_plugin_config.cpp index 99de5e53db..ac7bae36be 100644 --- a/tests/slic3rutils/test_plugin_config.cpp +++ b/tests/slic3rutils/test_plugin_config.cpp @@ -1,15 +1,20 @@ +#include +#include #include +#include #include #include #include +#include #include "plugin_test_utils.hpp" #include #include #include +#include "slic3r/plugin/PythonPluginInterface.hpp" #include using namespace Slic3r; diff --git a/tests/slic3rutils/test_plugin_host_api.cpp b/tests/slic3rutils/test_plugin_host_api.cpp index 0283bb5744..7919b273db 100644 --- a/tests/slic3rutils/test_plugin_host_api.cpp +++ b/tests/slic3rutils/test_plugin_host_api.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -8,7 +9,13 @@ #include #include +#include +#include +#include +#include #include "plugin_test_utils.hpp" +#include +#include #include "python_test_support.hpp" #include @@ -16,6 +23,7 @@ #include +#include #include namespace py = pybind11; diff --git a/tests/slic3rutils/test_plugin_install.cpp b/tests/slic3rutils/test_plugin_install.cpp index ae16703fa6..539bd917e0 100644 --- a/tests/slic3rutils/test_plugin_install.cpp +++ b/tests/slic3rutils/test_plugin_install.cpp @@ -1,10 +1,16 @@ +#include +#include #include +#include #include #include #include #include +#include +#include +#include #include "plugin_test_utils.hpp" #include diff --git a/tests/slic3rutils/test_plugin_lifecycle.cpp b/tests/slic3rutils/test_plugin_lifecycle.cpp index d90a166835..0c0399e2d3 100644 --- a/tests/slic3rutils/test_plugin_lifecycle.cpp +++ b/tests/slic3rutils/test_plugin_lifecycle.cpp @@ -1,13 +1,19 @@ +#include +#include #include +#include #include #include +#include #include #include #include #include #include +#include +#include #include "plugin_test_utils.hpp" #include @@ -17,8 +23,10 @@ #include #include #include +#include "slic3r/plugin/PythonPluginInterface.hpp" #include #include +#include #include using namespace Slic3r; diff --git a/tests/slic3rutils/test_plugin_printer_agent.cpp b/tests/slic3rutils/test_plugin_printer_agent.cpp index c1bba8a88e..50570f8712 100644 --- a/tests/slic3rutils/test_plugin_printer_agent.cpp +++ b/tests/slic3rutils/test_plugin_printer_agent.cpp @@ -1,5 +1,6 @@ #include +#include "slic3r/Utils/bambu_networking.hpp" #include #include #include @@ -12,7 +13,11 @@ #include #include +#include #include "plugin_test_utils.hpp" +#include +#include +#include namespace py = pybind11; using namespace Slic3r; diff --git a/tests/slic3rutils/test_plugin_sort.cpp b/tests/slic3rutils/test_plugin_sort.cpp index 58db799dd8..8af2ce3b5b 100644 --- a/tests/slic3rutils/test_plugin_sort.cpp +++ b/tests/slic3rutils/test_plugin_sort.cpp @@ -1,7 +1,10 @@ +#include #include #include +#include "slic3r/GUI/PluginSource.hpp" +#include "slic3r/GUI/PluginStatus.hpp" #include #include diff --git a/tests/slic3rutils/test_plugin_status.cpp b/tests/slic3rutils/test_plugin_status.cpp index c51c54c6c6..ab206c22ce 100644 --- a/tests/slic3rutils/test_plugin_status.cpp +++ b/tests/slic3rutils/test_plugin_status.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/tests/slic3rutils/test_prebuild_queue.cpp b/tests/slic3rutils/test_prebuild_queue.cpp index 8cc5444345..dc797ca60a 100644 --- a/tests/slic3rutils/test_prebuild_queue.cpp +++ b/tests/slic3rutils/test_prebuild_queue.cpp @@ -1,8 +1,10 @@ #include +#include "slic3r/GUI/Lazy.hpp" #include #include +#include #include "slic3r/GUI/PrebuildQueue.hpp" using Slic3r::GUI::LazyBase; diff --git a/tests/slic3rutils/test_precise_seam_plugin.cpp b/tests/slic3rutils/test_precise_seam_plugin.cpp index 244a4c3405..0375b96b9e 100644 --- a/tests/slic3rutils/test_precise_seam_plugin.cpp +++ b/tests/slic3rutils/test_precise_seam_plugin.cpp @@ -1,7 +1,11 @@ #include +#include #include "libslic3r/Model.hpp" #include "libslic3r/TriangleMesh.hpp" +#include +#include +#include #include "python_test_support.hpp" #include diff --git a/tests/slic3rutils/test_printer_agent.cpp b/tests/slic3rutils/test_printer_agent.cpp index 1418001205..8113326cc2 100644 --- a/tests/slic3rutils/test_printer_agent.cpp +++ b/tests/slic3rutils/test_printer_agent.cpp @@ -1,8 +1,14 @@ #include +#include +#include "slic3r/Utils/ICloudServiceAgent.hpp" +#include "slic3r/Utils/IPrinterAgent.hpp" #include #include +#include +#include +#include #include "python_test_support.hpp" #include diff --git a/tests/slic3rutils/test_printhost.cpp b/tests/slic3rutils/test_printhost.cpp index c4df56ebb6..c7ce9dccaa 100644 --- a/tests/slic3rutils/test_printhost.cpp +++ b/tests/slic3rutils/test_printhost.cpp @@ -3,10 +3,18 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include "libslic3r/LifecycleEvents.hpp" #include "slic3r/Utils/PrintHost.hpp" #include "slic3r/Utils/Flashforge.hpp" diff --git a/tests/slic3rutils/test_scene_benchmark.cpp b/tests/slic3rutils/test_scene_benchmark.cpp new file mode 100644 index 0000000000..c0e04fd690 --- /dev/null +++ b/tests/slic3rutils/test_scene_benchmark.cpp @@ -0,0 +1,57 @@ +#include + +#include "slic3r/GUI/SceneBenchmark.hpp" + +#include +#include +#include +#include + +using Catch::Matchers::WithinAbs; +using Slic3r::GUI::frame_time_stats; +using Slic3r::GUI::FrameTimeStats; + +TEST_CASE("Frame time statistics take percentiles by nearest rank", "[SceneBenchmark]") +{ + // 1 to 100 ms in shuffled order: the p-th percentile is the p-th frame time. + std::vector frame_ms(100); + std::iota(frame_ms.begin(), frame_ms.end(), 1.0); + std::shuffle(frame_ms.begin(), frame_ms.end(), std::mt19937(42)); + + const FrameTimeStats stats = frame_time_stats(frame_ms); + CHECK_THAT(stats.average_ms, WithinAbs(50.5, 1e-9)); + CHECK_THAT(stats.fps, WithinAbs(1000.0 / 50.5, 1e-9)); + CHECK_THAT(stats.median_ms, WithinAbs(50.0, 1e-9)); + CHECK_THAT(stats.p95_ms, WithinAbs(95.0, 1e-9)); + CHECK_THAT(stats.p99_ms, WithinAbs(99.0, 1e-9)); + CHECK_THAT(stats.max_ms, WithinAbs(100.0, 1e-9)); +} + +TEST_CASE("Frame time percentiles are measured frame times", "[SceneBenchmark]") +{ + // 360 frames, as in a benchmark pass: rank 342 for p95 and rank 357 for p99. + std::vector frame_ms(360); + std::iota(frame_ms.begin(), frame_ms.end(), 1.0); + + const FrameTimeStats stats = frame_time_stats(frame_ms); + CHECK_THAT(stats.median_ms, WithinAbs(180.0, 1e-9)); + CHECK_THAT(stats.p95_ms, WithinAbs(342.0, 1e-9)); + CHECK_THAT(stats.p99_ms, WithinAbs(357.0, 1e-9)); +} + +TEST_CASE("Frame time statistics of a single frame are that frame", "[SceneBenchmark]") +{ + const FrameTimeStats stats = frame_time_stats({ 4.0 }); + CHECK_THAT(stats.fps, WithinAbs(250.0, 1e-9)); + CHECK_THAT(stats.median_ms, WithinAbs(4.0, 1e-9)); + CHECK_THAT(stats.p99_ms, WithinAbs(4.0, 1e-9)); + CHECK_THAT(stats.max_ms, WithinAbs(4.0, 1e-9)); +} + +TEST_CASE("Frame time statistics of no frames are zero", "[SceneBenchmark]") +{ + const FrameTimeStats stats = frame_time_stats({}); + CHECK_THAT(stats.fps, WithinAbs(0.0, 1e-9)); + CHECK_THAT(stats.average_ms, WithinAbs(0.0, 1e-9)); + CHECK_THAT(stats.max_ms, WithinAbs(0.0, 1e-9)); +} diff --git a/tests/slic3rutils/test_scene_raycaster.cpp b/tests/slic3rutils/test_scene_raycaster.cpp index d51671e5c5..a1be46f216 100644 --- a/tests/slic3rutils/test_scene_raycaster.cpp +++ b/tests/slic3rutils/test_scene_raycaster.cpp @@ -11,6 +11,16 @@ #include #endif +#include +#include "slic3r/GUI/MeshUtils.hpp" +#include "libslic3r/Point.hpp" +#include +#include +#include +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Geometry.hpp" +#include + #include #include "slic3r/GUI/Camera.hpp" diff --git a/tests/slic3rutils/test_shortcuts.cpp b/tests/slic3rutils/test_shortcuts.cpp index 350e87f48a..ed7975b1e5 100644 --- a/tests/slic3rutils/test_shortcuts.cpp +++ b/tests/slic3rutils/test_shortcuts.cpp @@ -1,10 +1,16 @@ #include #include +#include #include "libslic3r/AppConfig.hpp" #include "slic3r/GUI/KeyChord.hpp" #include "slic3r/GUI/Shortcuts.hpp" +#include +#include +#include +#include +#include #include using namespace Slic3r; diff --git a/tests/slic3rutils/test_slicing_pipeline_bindings.cpp b/tests/slic3rutils/test_slicing_pipeline_bindings.cpp index 5e819c09e0..7552fe15af 100644 --- a/tests/slic3rutils/test_slicing_pipeline_bindings.cpp +++ b/tests/slic3rutils/test_slicing_pipeline_bindings.cpp @@ -1,4 +1,18 @@ #include +#include +#include +#include +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include "libslic3r/Config.hpp" +#include "libslic3r/Print.hpp" +#include +#include "libslic3r/SurfaceCollection.hpp" +#include "libslic3r/Polygon.hpp" +#include +#include #include "slic3r/plugin/PythonPluginInterface.hpp" using namespace Slic3r; diff --git a/tests/slic3rutils/test_slicing_pipeline_config.cpp b/tests/slic3rutils/test_slicing_pipeline_config.cpp index 37984cff34..1e8e728f4d 100644 --- a/tests/slic3rutils/test_slicing_pipeline_config.cpp +++ b/tests/slic3rutils/test_slicing_pipeline_config.cpp @@ -1,13 +1,26 @@ +#include +#include #include +#include +#include +#include "libslic3r/Print.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Config.hpp" #include #include +#include "slic3r/plugin/PluginFsUtils.hpp" #include #include #include +#include +#include #include "fff_print/test_helpers.hpp" #include "plugin_test_utils.hpp" +#include +#include #include #include diff --git a/tests/slic3rutils/test_staged_build.cpp b/tests/slic3rutils/test_staged_build.cpp index 3afcd9e5fc..df56d0c6e7 100644 --- a/tests/slic3rutils/test_staged_build.cpp +++ b/tests/slic3rutils/test_staged_build.cpp @@ -2,6 +2,7 @@ #include +#include #include "slic3r/GUI/StagedBuild.hpp" using Slic3r::GUI::StagedBuild; diff --git a/tests/slic3rutils/test_user_manager.cpp b/tests/slic3rutils/test_user_manager.cpp index cfccebe1cc..3c60552f22 100644 --- a/tests/slic3rutils/test_user_manager.cpp +++ b/tests/slic3rutils/test_user_manager.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include "slic3r/GUI/UserManager.hpp" using namespace Slic3r; diff --git a/tests/slic3rutils/test_web_media_controller.cpp b/tests/slic3rutils/test_web_media_controller.cpp index cdf756ca3a..fdf271fe10 100644 --- a/tests/slic3rutils/test_web_media_controller.cpp +++ b/tests/slic3rutils/test_web_media_controller.cpp @@ -1,7 +1,15 @@ +#include #include #include +#include +#include +#include +#include +#include +#include "slic3r/Utils/IPrinterAgent.hpp" +#include #include #include diff --git a/tests/test_utils.hpp b/tests/test_utils.hpp index 0b04e6ad11..d0817ce128 100644 --- a/tests/test_utils.hpp +++ b/tests/test_utils.hpp @@ -1,6 +1,9 @@ #ifndef SLIC3R_TEST_UTILS #define SLIC3R_TEST_UTILS +#include +#include +#include "libslic3r/BoundingBox.hpp" #include #include #include