diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 34aa95edadc..6fdfacc552e 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -200,7 +200,7 @@ License: MPL-2.0 Files: thirdparty/clipper2/* Comment: Clipper2 -Copyright: 2010-2024, Angus Johnson +Copyright: 2010-2025, Angus Johnson License: BSL-1.0 Files: thirdparty/cvtt/* diff --git a/thirdparty/README.md b/thirdparty/README.md index 575d4d6135c..cf71d5ba2ba 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -107,7 +107,7 @@ Files extracted from upstream source: ## clipper2 - Upstream: https://github.com/AngusJohnson/Clipper2 -- Version: 1.4.0 (736ddb0b53d97fd5f65dd3d9bbf8a0993eaf387c, 2024) +- Version: 1.5.2 (6901921c4be75126d1de60bfd24bd86a61319fd0, 2025) - License: BSL 1.0 Files extracted from upstream source: @@ -118,7 +118,7 @@ Files extracted from upstream source: Patches: - `0001-disable-exceptions.patch` (GH-80796) -- `0002-llvm-disable-int1280-math.patch` (GH-95964) +- `0002-llvm-disable-int128-math.patch` (GH-95964) ## cvtt diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h index dd1b873d5de..aa003bf0322 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.core.h +++ b/thirdparty/clipper2/include/clipper2/clipper.core.h @@ -1,26 +1,23 @@ /******************************************************************************* * Author : Angus Johnson * * Date : 12 May 2024 * -* Website : http://www.angusj.com * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : Core Clipper Library structures and functions * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_CORE_H #define CLIPPER_CORE_H +#include "clipper2/clipper.version.h" #include -#include -#include #include #include #include #include -#include #include -#include -#include "clipper2/clipper.version.h" +#include #define CLIPPER2_THROW(exception) std::abort() @@ -33,7 +30,7 @@ namespace Clipper2Lib public: explicit Clipper2Exception(const char* description) : m_descr(description) {} - virtual const char* what() const throw() override { return m_descr.c_str(); } + virtual const char* what() const noexcept override { return m_descr.c_str(); } private: std::string m_descr; }; @@ -90,6 +87,9 @@ namespace Clipper2Lib CLIPPER2_THROW(Clipper2Exception(undefined_error)); case range_error_i: CLIPPER2_THROW(Clipper2Exception(range_error)); + // Should never happen, but adding this to stop a compiler warning + default: + CLIPPER2_THROW(Clipper2Exception("Unknown error")); } #else if(error_code) {}; // only to stop compiler 'parameter not used' warning @@ -109,6 +109,10 @@ namespace Clipper2Lib //https://en.wikipedia.org/wiki/Nonzero-rule enum class FillRule { EvenOdd, NonZero, Positive, Negative }; +#ifdef USINGZ + using z_type = int64_t; +#endif + // Point ------------------------------------------------------------------------ template @@ -116,10 +120,10 @@ namespace Clipper2Lib T x; T y; #ifdef USINGZ - int64_t z; + z_type z; template - inline void Init(const T2 x_ = 0, const T2 y_ = 0, const int64_t z_ = 0) + inline void Init(const T2 x_ = 0, const T2 y_ = 0, const z_type z_ = 0) { if constexpr (std::is_integral_v && is_round_invocable::value && !std::is_integral_v) @@ -139,7 +143,7 @@ namespace Clipper2Lib explicit Point() : x(0), y(0), z(0) {}; template - Point(const T2 x_, const T2 y_, const int64_t z_ = 0) + Point(const T2 x_, const T2 y_, const z_type z_ = 0) { Init(x_, y_); z = z_; @@ -152,7 +156,7 @@ namespace Clipper2Lib } template - explicit Point(const Point& p, int64_t z_) + explicit Point(const Point& p, z_type z_) { Init(p.x, p.y, z_); } @@ -162,7 +166,7 @@ namespace Clipper2Lib return Point(x * scale, y * scale, z); } - void SetZ(const int64_t z_value) { z = z_value; } + void SetZ(const z_type z_value) { z = z_value; } friend std::ostream& operator<<(std::ostream& os, const Point& point) { @@ -326,10 +330,10 @@ namespace Clipper2Lib { Path result; result.reserve(4); - result.push_back(Point(left, top)); - result.push_back(Point(right, top)); - result.push_back(Point(right, bottom)); - result.push_back(Point(left, bottom)); + result.emplace_back(left, top); + result.emplace_back(right, top); + result.emplace_back(right, bottom); + result.emplace_back(left, bottom); return result; } @@ -364,6 +368,22 @@ namespace Clipper2Lib top == other.top && bottom == other.bottom; } + Rect& operator+=(const Rect& other) + { + left = (std::min)(left, other.left); + top = (std::min)(top, other.top); + right = (std::max)(right, other.right); + bottom = (std::max)(bottom, other.bottom); + return *this; + } + + Rect operator+(const Rect& other) const + { + Rect result = *this; + result += other; + return result; + } + friend std::ostream& operator<<(std::ostream& os, const Rect& rect) { os << "(" << rect.left << "," << rect.top << "," << rect.right << "," << rect.bottom << ") "; return os; @@ -597,13 +617,13 @@ namespace Clipper2Lib result.reserve(path.size()); typename Path::const_iterator path_iter = path.cbegin(); Point first_pt = *path_iter++, last_pt = first_pt; - result.push_back(first_pt); + result.emplace_back(first_pt); for (; path_iter != path.cend(); ++path_iter) { if (!NearEqual(*path_iter, last_pt, max_dist_sqrd)) { last_pt = *path_iter; - result.push_back(last_pt); + result.emplace_back(last_pt); } } if (!is_closed_path) return result; @@ -621,7 +641,7 @@ namespace Clipper2Lib for (typename Paths::const_iterator paths_citer = paths.cbegin(); paths_citer != paths.cend(); ++paths_citer) { - result.push_back(StripNearEqual(*paths_citer, max_dist_sqrd, is_closed_path)); + result.emplace_back(std::move(StripNearEqual(*paths_citer, max_dist_sqrd, is_closed_path))); } return result; } @@ -697,11 +717,11 @@ namespace Clipper2Lib { // Work around LLVM issue: https://github.com/llvm/llvm-project/issues/16778 // Details: https://github.com/godotengine/godot/pull/95964#issuecomment-2306581804 -//#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); -// return ab == cd; -//#else +// #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); +// return ab == cd; +// #else // nb: unsigned values needed for calculating overflow carry const auto abs_a = static_cast(std::abs(a)); const auto abs_b = static_cast(std::abs(b)); @@ -768,7 +788,7 @@ namespace Clipper2Lib const Point& line1, const Point& line2) { //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) - //see http://en.wikipedia.org/wiki/Perpendicular_distance + //see https://en.wikipedia.org/wiki/Perpendicular_distance double a = static_cast(pt.x - line1.x); double b = static_cast(pt.y - line1.y); double c = static_cast(line2.x - line1.x); diff --git a/thirdparty/clipper2/include/clipper2/clipper.engine.h b/thirdparty/clipper2/include/clipper2/clipper.engine.h index f6108832cd5..f4e1e183859 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.engine.h +++ b/thirdparty/clipper2/include/clipper2/clipper.engine.h @@ -1,25 +1,19 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 5 July 2024 * -* Website : http://www.angusj.com * +* Date : 17 September 2024 * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : This is the main polygon clipping module * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_ENGINE_H #define CLIPPER_ENGINE_H -#include -#include //#541 -#include -#include -#include -#include -#include -#include - #include "clipper2/clipper.core.h" +#include +#include +#include namespace Clipper2Lib { @@ -32,13 +26,13 @@ namespace Clipper2Lib { struct HorzSegment; //Note: all clipping operations except for Difference are commutative. - enum class ClipType { None, Intersection, Union, Difference, Xor }; + enum class ClipType { NoClip, Intersection, Union, Difference, Xor }; enum class PathType { Subject, Clip }; - enum class JoinWith { None, Left, Right }; + enum class JoinWith { NoJoin, Left, Right }; enum class VertexFlags : uint32_t { - None = 0, OpenStart = 1, OpenEnd = 2, LocalMax = 4, LocalMin = 8 + Empty = 0, OpenStart = 1, OpenEnd = 2, LocalMax = 4, LocalMin = 8 }; constexpr enum VertexFlags operator &(enum VertexFlags a, enum VertexFlags b) @@ -55,7 +49,7 @@ namespace Clipper2Lib { Point64 pt; Vertex* next = nullptr; Vertex* prev = nullptr; - VertexFlags flags = VertexFlags::None; + VertexFlags flags = VertexFlags::Empty; }; struct OutPt { @@ -131,7 +125,7 @@ namespace Clipper2Lib { Vertex* vertex_top = nullptr; LocalMinima* local_min = nullptr; // the bottom of an edge 'bound' (also Vatti) bool is_left_bound = false; - JoinWith join_with = JoinWith::None; + JoinWith join_with = JoinWith::NoJoin; }; struct LocalMinima { @@ -167,7 +161,7 @@ namespace Clipper2Lib { }; #ifdef USINGZ - typedef std::function ZCallback64; typedef std::function vertex_lists_; std::priority_queue scanline_list_; IntersectNodeList intersect_nodes_; - HorzSegmentList horz_seg_list_; + HorzSegmentList horz_seg_list_; std::vector horz_join_list_; void Reset(); inline void InsertScanline(int64_t y); diff --git a/thirdparty/clipper2/include/clipper2/clipper.export.h b/thirdparty/clipper2/include/clipper2/clipper.export.h index 53a445368e4..79856e2eb56 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.export.h +++ b/thirdparty/clipper2/include/clipper2/clipper.export.h @@ -1,16 +1,16 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 14 May 2024 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2024 * +* Date : 24 January 2025 * +* Website : https://www.angusj.com * +* Copyright : Angus Johnson 2010-2025 * * Purpose : This module exports the Clipper2 Library (ie DLL/so) * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ /* Boolean clipping: - cliptype: None=0, Intersection=1, Union=2, Difference=3, Xor=4 + cliptype: NoClip=0, Intersection=1, Union=2, Difference=3, Xor=4 fillrule: EvenOdd=0, NonZero=1, Positive=2, Negative=3 Polygon offsetting (inflate/deflate): @@ -19,73 +19,104 @@ 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 converted into very simple array data structures -(of either int64_t for CPath64 or double for CPathD) that can be parsed by -just about any programming language. +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 +array whose data type could be either int64_t or double. + +For conciseness, the following letters are used in the diagrams below: +N: Number of vertices in a given path +C: Count (ie number) of paths (or PolyPaths) in the structure +A: Number of elements in an array + CPath64 and CPathD: -These are arrays of consecutive x and y path coordinates preceeded by -a pair of values containing the path's length (N) and a 0 value. -__________________________________ -|counter|coord1|coord2|...|coordN| -|N, 0 |x1, y1|x2, y2|...|xN, yN| -__________________________________ +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 | +| N, 0 | x1, y1, (z1) | x2, y2, (z2) | ... | xN, yN, (zN) | +--------------------------------------------------------------- + CPaths64 and CPathsD: -These are also arrays containing any number of consecutive CPath64 or -CPathD structures. But preceeding these consecutive paths, there is pair of -values that contain the total length of the array structure (A) and the -number of CPath64 or CPathD it contains (C). The space these structures will -occupy in memory = A * sizeof(int64_t) or A * sizeof(double) respectively. -_______________________________ -|counter|path1|path2|...|pathC| -|A , C | | -_______________________________ +These are also arrays of either int64_t or double values that +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 +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) +__________________________________________ +| counters | path1 | path2 | ... | pathC | +| A, C | | | ... | | +------------------------------------------ + CPolytree64 and CPolytreeD: -These are also arrays consisting of CPolyPath structures that represent -individual paths in a tree structure. However, the very first (ie top) -CPolyPath is just the tree container that doesn't have a path. And because -of that, its structure will be very slightly different from the remaining -CPolyPath. This difference will be discussed below. +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 +CPolyPath children, and these collectively make a tree structure. +_________________________________________________________ +| counters | CPolyPath1 | CPolyPath2 | ... | CPolyPathC | +| A, C | | | ... | | +--------------------------------------------------------- + CPolyPath64 and CPolyPathD: -These are simple arrays consisting of a series of path coordinates followed -by any number of child (ie nested) CPolyPath. Preceeding these are two values -indicating the length of the path (N) and the number of child CPolyPath (C). -____________________________________________________________ -|counter|coord1|coord2|...|coordN| child1|child2|...|childC| -|N , C |x1, y1|x2, y2|...|xN, yN| | -____________________________________________________________ +These array structures consist of a pair of counter values followed by a +series of polygon vertices and a series of nested CPolyPath children. +The first counter values indicates the number of vertices in the +polygon (N), and the second counter indicates the CPolyPath child count (C). +_____________________________________________________________________________ +|cntrs |vertex1 |vertex2 |...|vertexN |child1|child2|...|childC| +|N, C |x1, y1, (z1)| x2, y2, (z2)|...|xN, yN, (zN)| | |...| | +----------------------------------------------------------------------------- -As mentioned above, the very first CPolyPath structure is just a container -that owns (both directly and indirectly) every other CPolyPath in the tree. -Since this first CPolyPath has no path, instead of a path length, its very -first value will contain the total length of the CPolytree array (not its -total bytes length). -Again, all theses exported structures (CPaths64, CPathsD, CPolyTree64 & -CPolyTreeD) are arrays of either type int64_t or double, and the first -value in these arrays will always be the length of that array. +DisposeArray64 & DisposeArrayD: +All array structures are allocated in heap memory which will eventually +need to be released. However, since applications linking to these DLL +functions may use different memory managers, the only safe way to release +this memory is to use the exported DisposeArray functions. + + +(Optional) Z-Values: +Structures will only contain user-defined z-values when the USINGZ +pre-processor identifier is used. The library does not assign z-values +because this field is intended for users to assign custom values to vertices. +Z-values in input paths (subject and clip) will be copied to solution paths. +New vertices at path intersections will generate a callback event that allows +users to assign z-values at these new vertices. The user's callback function +must conform with the DLLZCallback definition and be registered with the +DLL via SetZCallback. To assist the user in assigning z-values, the library +passes in the callback function the new intersection point together with +the four vertices that define the two segments that are intersecting. -These array structures are allocated in heap memory which will eventually -need to be released. However, since applications dynamically linking to -these functions may use different memory managers, the only safe way to -free up this memory is to use the exported DisposeArray64 and -DisposeArrayD functions (see below). */ - - #ifndef CLIPPER2_EXPORT_H #define CLIPPER2_EXPORT_H -#include -#include - #include "clipper2/clipper.core.h" #include "clipper2/clipper.engine.h" #include "clipper2/clipper.offset.h" #include "clipper2/clipper.rectclip.h" +#include namespace Clipper2Lib { @@ -127,6 +158,12 @@ inline Rect CRectToRect(const CRect& rect) return result; } +template +inline T1 Reinterpret(T2 value) { + return *reinterpret_cast(&value); +} + + #ifdef _WIN32 #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport) #else @@ -178,11 +215,22 @@ EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths, double delta, uint8_t jointype, uint8_t endtype, double miter_limit = 2.0, double arc_tolerance = 0.0, bool reverse_solution = false); + EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths, double delta, uint8_t jointype, uint8_t endtype, int precision = 2, double miter_limit = 2.0, double arc_tolerance = 0.0, bool reverse_solution = false); +EXTERN_DLL_EXPORT CPaths64 InflatePath64(const CPath64 path, + double delta, uint8_t jointype, uint8_t endtype, + double miter_limit = 2.0, double arc_tolerance = 0.0, + bool reverse_solution = false); + +EXTERN_DLL_EXPORT CPathsD InflatePathD(const CPathD path, + double delta, uint8_t jointype, uint8_t endtype, + int precision = 2, double miter_limit = 2.0, + double arc_tolerance = 0.0, bool reverse_solution = false); + // RectClip & RectClipLines: EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, const CPaths64 paths); @@ -197,6 +245,15 @@ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect, // INTERNAL FUNCTIONS ////////////////////////////////////////////////////// +#ifdef USINGZ +ZCallback64 dllCallback64 = nullptr; +ZCallbackD dllCallbackD = nullptr; + +constexpr int EXPORT_VERTEX_DIMENSIONALITY = 3; +#else +constexpr int EXPORT_VERTEX_DIMENSIONALITY = 2; +#endif + template static void GetPathCountAndCPathsArrayLen(const Paths& paths, size_t& cnt, size_t& array_len) @@ -206,30 +263,47 @@ static void GetPathCountAndCPathsArrayLen(const Paths& paths, for (const Path& path : paths) if (path.size()) { - array_len += path.size() * 2 + 2; + array_len += path.size() * EXPORT_VERTEX_DIMENSIONALITY + 2; ++cnt; } } -static size_t GetPolyPath64ArrayLen(const PolyPath64& pp) +static size_t GetPolyPathArrayLen64(const PolyPath64& pp) { size_t result = 2; // poly_length + child_count - result += pp.Polygon().size() * 2; + result += pp.Polygon().size() * EXPORT_VERTEX_DIMENSIONALITY; //plus nested children :) for (size_t i = 0; i < pp.Count(); ++i) - result += GetPolyPath64ArrayLen(*pp[i]); + result += GetPolyPathArrayLen64(*pp[i]); return result; } -static void GetPolytreeCountAndCStorageSize(const PolyTree64& tree, +static size_t GetPolyPathArrayLenD(const PolyPathD& pp) +{ + size_t result = 2; // poly_length + child_count + result += pp.Polygon().size() * EXPORT_VERTEX_DIMENSIONALITY; + //plus nested children :) + for (size_t i = 0; i < pp.Count(); ++i) + result += GetPolyPathArrayLenD(*pp[i]); + return result; +} + +static void GetPolytreeCountAndCStorageSize64(const PolyTree64& tree, size_t& cnt, size_t& array_len) { cnt = tree.Count(); // nb: top level count only - array_len = GetPolyPath64ArrayLen(tree); + array_len = GetPolyPathArrayLen64(tree); +} + +static void GetPolytreeCountAndCStorageSizeD(const PolyTreeD& tree, + size_t& cnt, size_t& array_len) +{ + cnt = tree.Count(); // nb: top level count only + array_len = GetPolyPathArrayLenD(tree); } template -static T* CreateCPaths(const Paths& paths) +static T* CreateCPathsFromPathsT(const Paths& paths) { size_t cnt = 0, array_len = 0; GetPathCountAndCPathsArrayLen(paths, cnt, array_len); @@ -245,11 +319,38 @@ static T* CreateCPaths(const Paths& paths) { *v++ = pt.x; *v++ = pt.y; +#ifdef USINGZ + *v++ = Reinterpret(pt.z); +#endif } } return result; } +CPathsD CreateCPathsDFromPathsD(const PathsD& paths) +{ + if (!paths.size()) return nullptr; + size_t cnt, array_len; + GetPathCountAndCPathsArrayLen(paths, cnt, array_len); + CPathsD result = new double[array_len], v = result; + *v++ = (double)array_len; + *v++ = (double)cnt; + for (const PathD& path : paths) + { + if (!path.size()) continue; + *v = (double)path.size(); + ++v; *v++ = 0; + for (const PointD& pt : path) + { + *v++ = pt.x; + *v++ = pt.y; +#ifdef USINGZ + * v++ = Reinterpret(pt.z); +#endif + } + } + return result; +} CPathsD CreateCPathsDFromPaths64(const Paths64& paths, double scale) { @@ -268,13 +369,16 @@ CPathsD CreateCPathsDFromPaths64(const Paths64& paths, double scale) { *v++ = pt.x * scale; *v++ = pt.y * scale; +#ifdef USINGZ + *v++ = Reinterpret(pt.z); +#endif } } return result; } template -static Path ConvertCPath(T* path) +static Path ConvertCPathToPathT(T* path) { Path result; if (!path) return result; @@ -284,14 +388,19 @@ static Path ConvertCPath(T* path) result.reserve(cnt); for (size_t j = 0; j < cnt; ++j) { - T x = *v++, y = *v++; - result.push_back(Point(x, y)); + T x = *v++, y = *v++; +#ifdef USINGZ + z_type z = Reinterpret(*v++); + result.emplace_back(x, y, z); +#else + result.emplace_back(x, y); +#endif } return result; } template -static Paths ConvertCPaths(T* paths) +static Paths ConvertCPathsToPathsT(T* paths) { Paths result; if (!paths) return result; @@ -301,19 +410,45 @@ static Paths ConvertCPaths(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) { T x = *v++, y = *v++; - path.push_back(Point(x, y)); +#ifdef USINGZ + z_type z = Reinterpret(*v++); + path.emplace_back(x, y, z); +#else + path.emplace_back(x, y); +#endif } - result.push_back(path); + result.emplace_back(std::move(path)); } return result; } +static Path64 ConvertCPathDToPath64WithScale(const CPathD path, double scale) +{ + Path64 result; + if (!path) return result; + double* v = path; + size_t cnt = static_cast(*v); + v += 2; // skip 0 value + result.reserve(cnt); + for (size_t j = 0; j < cnt; ++j) + { + double x = *v++ * scale; + double y = *v++ * scale; +#ifdef USINGZ + z_type z = Reinterpret(*v++); + result.emplace_back(x, y, z); +#else + result.emplace_back(x, y); +#endif + } + return result; +} static Paths64 ConvertCPathsDToPaths64(const CPathsD paths, double scale) { @@ -333,42 +468,78 @@ static Paths64 ConvertCPathsDToPaths64(const CPathsD paths, double scale) { double x = *v++ * scale; double y = *v++ * scale; - path.push_back(Point64(x, y)); +#ifdef USINGZ + z_type z = Reinterpret(*v++); + path.emplace_back(x, y, z); +#else + path.emplace_back(x, y); +#endif } - result.push_back(path); + result.emplace_back(std::move(path)); } return result; } -template -static void CreateCPolyPath(const PolyPath64* pp, T*& v, T scale) +static void CreateCPolyPath64(const PolyPath64* pp, int64_t*& v) { - *v++ = static_cast(pp->Polygon().size()); - *v++ = static_cast(pp->Count()); + *v++ = static_cast(pp->Polygon().size()); + *v++ = static_cast(pp->Count()); for (const Point64& pt : pp->Polygon()) { - *v++ = static_cast(pt.x * scale); - *v++ = static_cast(pt.y * scale); + *v++ = pt.x; + *v++ = pt.y; +#ifdef USINGZ + * v++ = Reinterpret(pt.z); // raw memory copy +#endif } for (size_t i = 0; i < pp->Count(); ++i) - CreateCPolyPath(pp->Child(i), v, scale); + CreateCPolyPath64(pp->Child(i), v); } -template -static T* CreateCPolyTree(const PolyTree64& tree, T scale) +static void CreateCPolyPathD(const PolyPathD* pp, double*& v) +{ + *v++ = static_cast(pp->Polygon().size()); + *v++ = static_cast(pp->Count()); + for (const PointD& pt : pp->Polygon()) + { + *v++ = pt.x; + *v++ = pt.y; +#ifdef USINGZ + * v++ = Reinterpret(pt.z); // raw memory copy +#endif + } + for (size_t i = 0; i < pp->Count(); ++i) + CreateCPolyPathD(pp->Child(i), v); +} + +static int64_t* CreateCPolyTree64(const PolyTree64& tree) { - if (scale == 0) scale = 1; size_t cnt, array_len; - GetPolytreeCountAndCStorageSize(tree, cnt, array_len); + GetPolytreeCountAndCStorageSize64(tree, cnt, array_len); if (!cnt) return nullptr; // allocate storage - T* result = new T[array_len]; - T* v = result; - - *v++ = static_cast(array_len); - *v++ = static_cast(tree.Count()); + int64_t* result = new int64_t[array_len]; + int64_t* v = result; + *v++ = static_cast(array_len); + *v++ = static_cast(tree.Count()); for (size_t i = 0; i < tree.Count(); ++i) - CreateCPolyPath(tree.Child(i), v, scale); + CreateCPolyPath64(tree.Child(i), v); + return result; +} + +static double* CreateCPolyTreeD(const PolyTreeD& tree) +{ + double scale = std::log10(tree.Scale()); + size_t cnt, array_len; + GetPolytreeCountAndCStorageSizeD(tree, cnt, array_len); + if (!cnt) return nullptr; + // allocate storage + double* result = new double[array_len]; + double* v = result; + *v++ = static_cast(array_len); + *v++ = static_cast(tree.Count()); + for (size_t i = 0; i < tree.Count(); ++i) + CreateCPolyPathD(tree.Child(i), v); return result; } @@ -391,20 +562,24 @@ EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype, if (fillrule > static_cast(FillRule::Negative)) return -3; Paths64 sub, sub_open, clp, sol, sol_open; - sub = ConvertCPaths(subjects); - sub_open = ConvertCPaths(subjects_open); - clp = ConvertCPaths(clips); + sub = ConvertCPathsToPathsT(subjects); + sub_open = ConvertCPathsToPathsT(subjects_open); + clp = ConvertCPathsToPathsT(clips); Clipper64 clipper; clipper.PreserveCollinear(preserve_collinear); clipper.ReverseSolution(reverse_solution); +#ifdef USINGZ + if (dllCallback64) + clipper.SetZCallback(dllCallback64); +#endif if (sub.size() > 0) clipper.AddSubject(sub); if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); if (clp.size() > 0) clipper.AddClip(clp); if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open)) return -1; // clipping bug - should never happen :) - solution = CreateCPaths(sol); - solution_open = CreateCPaths(sol_open); + solution = CreateCPathsFromPathsT(sol); + solution_open = CreateCPathsFromPathsT(sol_open); return 0; //success !! } @@ -417,22 +592,26 @@ EXTERN_DLL_EXPORT int BooleanOp_PolyTree64(uint8_t cliptype, if (cliptype > static_cast(ClipType::Xor)) return -4; if (fillrule > static_cast(FillRule::Negative)) return -3; Paths64 sub, sub_open, clp, sol_open; - sub = ConvertCPaths(subjects); - sub_open = ConvertCPaths(subjects_open); - clp = ConvertCPaths(clips); + sub = ConvertCPathsToPathsT(subjects); + sub_open = ConvertCPathsToPathsT(subjects_open); + clp = ConvertCPathsToPathsT(clips); PolyTree64 tree; Clipper64 clipper; clipper.PreserveCollinear(preserve_collinear); clipper.ReverseSolution(reverse_solution); +#ifdef USINGZ + if (dllCallback64) + clipper.SetZCallback(dllCallback64); +#endif if (sub.size() > 0) clipper.AddSubject(sub); if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); if (clp.size() > 0) clipper.AddClip(clp); if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), tree, sol_open)) return -1; // clipping bug - should never happen :) - sol_tree = CreateCPolyTree(tree, (int64_t)1); - solution_open = CreateCPaths(sol_open); + sol_tree = CreateCPolyTree64(tree); + solution_open = CreateCPathsFromPathsT(sol_open); return 0; //success !! } @@ -445,23 +624,27 @@ EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype, if (precision < -8 || precision > 8) return -5; if (cliptype > static_cast(ClipType::Xor)) return -4; if (fillrule > static_cast(FillRule::Negative)) return -3; - const double scale = std::pow(10, precision); + //const double scale = std::pow(10, precision); - Paths64 sub, sub_open, clp, sol, sol_open; - sub = ConvertCPathsDToPaths64(subjects, scale); - sub_open = ConvertCPathsDToPaths64(subjects_open, scale); - clp = ConvertCPathsDToPaths64(clips, scale); + PathsD sub, sub_open, clp, sol, sol_open; + sub = ConvertCPathsToPathsT(subjects); + sub_open = ConvertCPathsToPathsT(subjects_open); + clp = ConvertCPathsToPathsT(clips); - Clipper64 clipper; + ClipperD clipper(precision); clipper.PreserveCollinear(preserve_collinear); clipper.ReverseSolution(reverse_solution); +#ifdef USINGZ + if (dllCallbackD) + clipper.SetZCallback(dllCallbackD); +#endif if (sub.size() > 0) clipper.AddSubject(sub); if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); if (clp.size() > 0) clipper.AddClip(clp); if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open)) return -1; - solution = CreateCPathsDFromPaths64(sol, 1 / scale); - solution_open = CreateCPathsDFromPaths64(sol_open, 1 / scale); + solution = CreateCPathsDFromPathsD(sol); + solution_open = CreateCPathsDFromPathsD(sol_open); return 0; } @@ -474,27 +657,30 @@ EXTERN_DLL_EXPORT int BooleanOp_PolyTreeD(uint8_t cliptype, if (precision < -8 || precision > 8) return -5; if (cliptype > static_cast(ClipType::Xor)) return -4; if (fillrule > static_cast(FillRule::Negative)) return -3; - - double scale = std::pow(10, precision); + //double scale = std::pow(10, precision); int err = 0; - Paths64 sub, sub_open, clp, sol_open; - sub = ConvertCPathsDToPaths64(subjects, scale); - sub_open = ConvertCPathsDToPaths64(subjects_open, scale); - clp = ConvertCPathsDToPaths64(clips, scale); + PathsD sub, sub_open, clp, sol_open; + sub = ConvertCPathsToPathsT(subjects); + sub_open = ConvertCPathsToPathsT(subjects_open); + clp = ConvertCPathsToPathsT(clips); - PolyTree64 tree; - Clipper64 clipper; + PolyTreeD tree; + ClipperD clipper(precision); clipper.PreserveCollinear(preserve_collinear); clipper.ReverseSolution(reverse_solution); +#ifdef USINGZ + if (dllCallbackD) + clipper.SetZCallback(dllCallbackD); +#endif if (sub.size() > 0) clipper.AddSubject(sub); if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); if (clp.size() > 0) clipper.AddClip(clp); if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), tree, sol_open)) return -1; // clipping bug - should never happen :) - solution = CreateCPolyTree(tree, 1/scale); - solution_open = CreateCPathsDFromPaths64(sol_open, 1 / scale); + solution = CreateCPolyTreeD(tree); + solution_open = CreateCPathsDFromPathsD(sol_open); return 0; //success !! } @@ -503,13 +689,13 @@ EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths, double arc_tolerance, bool reverse_solution) { Paths64 pp; - pp = ConvertCPaths(paths); + pp = ConvertCPathsToPathsT(paths); ClipperOffset clip_offset( miter_limit, arc_tolerance, reverse_solution); clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype)); Paths64 result; clip_offset.Execute(delta, result); - return CreateCPaths(result); + return CreateCPathsFromPathsT(result); } EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths, @@ -525,18 +711,49 @@ EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths, clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype)); Paths64 result; clip_offset.Execute(delta * scale, result); - return CreateCPathsDFromPaths64(result, 1 / scale); } + +EXTERN_DLL_EXPORT CPaths64 InflatePath64(const CPath64 path, + double delta, uint8_t jointype, uint8_t endtype, double miter_limit, + double arc_tolerance, bool reverse_solution) +{ + Path64 pp; + pp = ConvertCPathToPathT(path); + ClipperOffset clip_offset(miter_limit, + arc_tolerance, reverse_solution); + clip_offset.AddPath(pp, JoinType(jointype), EndType(endtype)); + Paths64 result; + clip_offset.Execute(delta, result); + return CreateCPathsFromPathsT(result); +} + +EXTERN_DLL_EXPORT CPathsD InflatePathD(const CPathD path, + double delta, uint8_t jointype, uint8_t endtype, + int precision, double miter_limit, + double arc_tolerance, bool reverse_solution) +{ + if (precision < -8 || precision > 8 || !path) return nullptr; + + const double scale = std::pow(10, precision); + ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution); + Path64 pp = ConvertCPathDToPath64WithScale(path, scale); + clip_offset.AddPath(pp, JoinType(jointype), EndType(endtype)); + Paths64 result; + clip_offset.Execute(delta * scale, result); + + return CreateCPathsDFromPaths64(result, 1 / scale); +} + EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, const CPaths64 paths) { if (CRectIsEmpty(rect) || !paths) return nullptr; Rect64 r64 = CRectToRect(rect); class RectClip64 rc(r64); - Paths64 pp = ConvertCPaths(paths); + Paths64 pp = ConvertCPathsToPathsT(paths); Paths64 result = rc.Execute(pp); - return CreateCPaths(result); + return CreateCPathsFromPathsT(result); } EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect, const CPathsD paths, int precision) @@ -560,9 +777,9 @@ EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect, if (CRectIsEmpty(rect) || !paths) return nullptr; Rect64 r = CRectToRect(rect); class RectClipLines64 rcl (r); - Paths64 pp = ConvertCPaths(paths); + Paths64 pp = ConvertCPathsToPathsT(paths); Paths64 result = rcl.Execute(pp); - return CreateCPaths(result); + return CreateCPathsFromPathsT(result); } EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect, @@ -581,20 +798,35 @@ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect, EXTERN_DLL_EXPORT CPaths64 MinkowskiSum64(const CPath64& cpattern, const CPath64& cpath, bool is_closed) { - Path64 path = ConvertCPath(cpath); - Path64 pattern = ConvertCPath(cpattern); + Path64 path = ConvertCPathToPathT(cpath); + Path64 pattern = ConvertCPathToPathT(cpattern); Paths64 solution = MinkowskiSum(pattern, path, is_closed); - return CreateCPaths(solution); + return CreateCPathsFromPathsT(solution); } EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath64& cpath, bool is_closed) { - Path64 path = ConvertCPath(cpath); - Path64 pattern = ConvertCPath(cpattern); + Path64 path = ConvertCPathToPathT(cpath); + Path64 pattern = ConvertCPathToPathT(cpattern); Paths64 solution = MinkowskiDiff(pattern, path, is_closed); - return CreateCPaths(solution); + return CreateCPathsFromPathsT(solution); } -} // end Clipper2Lib namespace +#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); +EXTERN_DLL_EXPORT void SetZCallback64(DLLZCallback64 callback) +{ + dllCallback64 = callback; +} + +EXTERN_DLL_EXPORT void SetZCallbackD(DLLZCallbackD callback) +{ + dllCallbackD = callback; +} + +#endif + +} #endif // CLIPPER2_EXPORT_H diff --git a/thirdparty/clipper2/include/clipper2/clipper.h b/thirdparty/clipper2/include/clipper2/clipper.h index a2fe5c3cc28..b75bbd35323 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.h +++ b/thirdparty/clipper2/include/clipper2/clipper.h @@ -1,24 +1,21 @@ /******************************************************************************* * Author : Angus Johnson * * Date : 27 April 2024 * -* Website : http://www.angusj.com * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : This module provides a simple interface to the Clipper Library * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_H #define CLIPPER_H -#include -#include -#include - #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 namespace Clipper2Lib { @@ -272,14 +269,14 @@ namespace Clipper2Lib { inline void PolyPathToPaths64(const PolyPath64& polypath, Paths64& paths) { - paths.push_back(polypath.Polygon()); + paths.emplace_back(polypath.Polygon()); for (const auto& child : polypath) PolyPathToPaths64(*child, paths); } inline void PolyPathToPathsD(const PolyPathD& polypath, PathsD& paths) { - paths.push_back(polypath.Polygon()); + paths.emplace_back(polypath.Polygon()); for (const auto& child : polypath) PolyPathToPathsD(*child, paths); } @@ -348,9 +345,9 @@ namespace Clipper2Lib { result.reserve(array_size / 2); for (size_t i = 0; i < array_size; i +=2) #ifdef USINGZ - result.push_back( U{ an_array[i], an_array[i + 1], 0} ); + result.emplace_back( an_array[i], an_array[i + 1], 0 ); #else - result.push_back( U{ an_array[i], an_array[i + 1]} ); + result.emplace_back( an_array[i], an_array[i + 1] ); #endif } @@ -518,20 +515,20 @@ namespace Clipper2Lib { } prevIt = srcIt++; - dst.push_back(*prevIt); + dst.emplace_back(*prevIt); for (; srcIt != stop; ++srcIt) { if (!IsCollinear(*prevIt, *srcIt, *(srcIt + 1))) { prevIt = srcIt; - dst.push_back(*prevIt); + dst.emplace_back(*prevIt); } } if (is_open_path) - dst.push_back(*srcIt); + dst.emplace_back(*srcIt); else if (!IsCollinear(*prevIt, *stop, dst[0])) - dst.push_back(*stop); + dst.emplace_back(*stop); else { while (dst.size() > 2 && @@ -603,10 +600,10 @@ namespace Clipper2Lib { double dx = co, dy = si; Path result; result.reserve(steps); - result.push_back(Point(center.x + radiusX, static_cast(center.y))); + result.emplace_back(center.x + radiusX, static_cast(center.y)); for (size_t i = 1; i < steps; ++i) { - result.push_back(Point(center.x + radiusX * dx, center.y + radiusY * dy)); + result.emplace_back(center.x + radiusX * dx, center.y + radiusY * dy); double x = dx * co - dy * si; dy = dy * co + dx * si; dx = x; @@ -700,7 +697,7 @@ namespace Clipper2Lib { Path result; result.reserve(len); for (typename Path::size_type i = 0; i < len; ++i) - if (!flags[i]) result.push_back(path[i]); + if (!flags[i]) result.emplace_back(path[i]); return result; } @@ -711,7 +708,7 @@ namespace Clipper2Lib { Paths result; result.reserve(paths.size()); for (const auto& path : paths) - result.push_back(SimplifyPath(path, epsilon, isClosedPath)); + result.emplace_back(std::move(SimplifyPath(path, epsilon, isClosedPath))); return result; } @@ -749,7 +746,7 @@ namespace Clipper2Lib { result.reserve(len); for (typename Path::size_type i = 0; i < len; ++i) if (flags[i]) - result.push_back(path[i]); + result.emplace_back(path[i]); return result; } diff --git a/thirdparty/clipper2/include/clipper2/clipper.minkowski.h b/thirdparty/clipper2/include/clipper2/clipper.minkowski.h index a3ddcf86f3a..3a85ba5d1e7 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.minkowski.h +++ b/thirdparty/clipper2/include/clipper2/clipper.minkowski.h @@ -1,18 +1,15 @@ /******************************************************************************* * Author : Angus Johnson * * Date : 1 November 2023 * -* Website : http://www.angusj.com * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : Minkowski Sum and Difference * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_MINKOWSKI_H #define CLIPPER_MINKOWSKI_H -#include -#include -#include #include "clipper2/clipper.core.h" namespace Clipper2Lib @@ -35,7 +32,7 @@ namespace Clipper2Lib Path64 path2(pattern.size()); std::transform(pattern.cbegin(), pattern.cend(), path2.begin(), [p](const Point64& pt2) {return p + pt2; }); - tmp.push_back(path2); + tmp.emplace_back(std::move(path2)); } } else @@ -45,7 +42,7 @@ namespace Clipper2Lib Path64 path2(pattern.size()); std::transform(pattern.cbegin(), pattern.cend(), path2.begin(), [p](const Point64& pt2) {return p - pt2; }); - tmp.push_back(path2); + tmp.emplace_back(std::move(path2)); } } @@ -59,14 +56,14 @@ namespace Clipper2Lib Path64 quad; quad.reserve(4); { - quad.push_back(tmp[g][h]); - quad.push_back(tmp[i][h]); - quad.push_back(tmp[i][j]); - quad.push_back(tmp[g][j]); + quad.emplace_back(tmp[g][h]); + quad.emplace_back(tmp[i][h]); + quad.emplace_back(tmp[i][j]); + quad.emplace_back(tmp[g][j]); }; if (!IsPositive(quad)) std::reverse(quad.begin(), quad.end()); - result.push_back(quad); + result.emplace_back(std::move(quad)); h = j; } g = i; diff --git a/thirdparty/clipper2/include/clipper2/clipper.offset.h b/thirdparty/clipper2/include/clipper2/clipper.offset.h index bb075a6d492..90ccd5ec977 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.offset.h +++ b/thirdparty/clipper2/include/clipper2/clipper.offset.h @@ -1,10 +1,10 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 24 March 2024 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2024 * +* Date : 22 January 2025 * +* Website : https://www.angusj.com * +* Copyright : Angus Johnson 2010-2025 * * Purpose : Path Offset (Inflate/Shrink) * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_OFFSET_H_ @@ -12,6 +12,7 @@ #include "clipper.core.h" #include "clipper.engine.h" +#include namespace Clipper2Lib { @@ -96,7 +97,7 @@ public: void AddPaths(const Paths64& paths, JoinType jt_, EndType et_); void Clear() { groups_.clear(); norms.clear(); }; - void Execute(double delta, Paths64& paths); + void Execute(double delta, Paths64& sols_64); void Execute(double delta, PolyTree64& polytree); void Execute(DeltaCallback64 delta_cb, Paths64& paths); diff --git a/thirdparty/clipper2/include/clipper2/clipper.rectclip.h b/thirdparty/clipper2/include/clipper2/clipper.rectclip.h index bfcfacf2e7c..e7cf2f45423 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.rectclip.h +++ b/thirdparty/clipper2/include/clipper2/clipper.rectclip.h @@ -1,19 +1,17 @@ /******************************************************************************* * Author : Angus Johnson * * Date : 5 July 2024 * -* Website : http://www.angusj.com * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : FAST rectangular clipping * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ #ifndef CLIPPER_RECTCLIP_H #define CLIPPER_RECTCLIP_H -#include -#include -#include #include "clipper2/clipper.core.h" +#include namespace Clipper2Lib { diff --git a/thirdparty/clipper2/include/clipper2/clipper.version.h b/thirdparty/clipper2/include/clipper2/clipper.version.h index 61464095f6b..661b0f1c588 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.version.h +++ b/thirdparty/clipper2/include/clipper2/clipper.version.h @@ -1,6 +1,6 @@ #ifndef CLIPPER_VERSION_H #define CLIPPER_VERSION_H -constexpr auto CLIPPER2_VERSION = "1.4.0"; +constexpr auto CLIPPER2_VERSION = "1.5.2"; #endif // CLIPPER_VERSION_H diff --git a/thirdparty/clipper2/patches/0001-disable-exceptions.patch b/thirdparty/clipper2/patches/0001-disable-exceptions.patch index 89be96f1fb8..a014dbb3912 100644 --- a/thirdparty/clipper2/patches/0001-disable-exceptions.patch +++ b/thirdparty/clipper2/patches/0001-disable-exceptions.patch @@ -1,17 +1,17 @@ diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h -index 925c04685e..67dd731af6 100644 +index ab71aeb072..110bee4c10 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.core.h +++ b/thirdparty/clipper2/include/clipper2/clipper.core.h -@@ -22,6 +22,8 @@ - #include - #include "clipper2/clipper.version.h" +@@ -19,6 +19,8 @@ + #include + #include +#define CLIPPER2_THROW(exception) std::abort() + namespace Clipper2Lib { -@@ -79,18 +81,18 @@ namespace Clipper2Lib +@@ -76,21 +78,21 @@ namespace Clipper2Lib switch (error_code) { case precision_error_i: @@ -29,6 +29,10 @@ index 925c04685e..67dd731af6 100644 case range_error_i: - throw Clipper2Exception(range_error); + CLIPPER2_THROW(Clipper2Exception(range_error)); + // Should never happen, but adding this to stop a compiler warning + default: +- throw Clipper2Exception("Unknown error"); ++ CLIPPER2_THROW(Clipper2Exception("Unknown error")); } #else - ++error_code; // only to stop compiler warning diff --git a/thirdparty/clipper2/patches/0002-llvm-disable-int1280-math.patch b/thirdparty/clipper2/patches/0002-llvm-disable-int128-math.patch similarity index 74% rename from thirdparty/clipper2/patches/0002-llvm-disable-int1280-math.patch rename to thirdparty/clipper2/patches/0002-llvm-disable-int128-math.patch index ffa06e72b86..c69ec8e4cee 100644 --- a/thirdparty/clipper2/patches/0002-llvm-disable-int1280-math.patch +++ b/thirdparty/clipper2/patches/0002-llvm-disable-int128-math.patch @@ -1,8 +1,8 @@ diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h -index 67dd731af6..dd1b873d5d 100644 +index 110bee4c10..aa003bf032 100644 --- a/thirdparty/clipper2/include/clipper2/clipper.core.h +++ b/thirdparty/clipper2/include/clipper2/clipper.core.h -@@ -695,11 +695,13 @@ namespace Clipper2Lib +@@ -715,11 +715,13 @@ namespace Clipper2Lib // returns true if (and only if) a * b == c * d inline bool ProductsAreEqual(int64_t a, int64_t b, int64_t c, int64_t d) { @@ -13,15 +13,15 @@ index 67dd731af6..dd1b873d5d 100644 -#else +// Work around LLVM issue: https://github.com/llvm/llvm-project/issues/16778 +// Details: https://github.com/godotengine/godot/pull/95964#issuecomment-2306581804 -+//#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); -+// return ab == cd; -+//#else ++// #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); ++// return ab == cd; ++// #else // nb: unsigned values needed for calculating overflow carry const auto abs_a = static_cast(std::abs(a)); const auto abs_b = static_cast(std::abs(b)); -@@ -714,7 +716,7 @@ namespace Clipper2Lib +@@ -734,7 +736,7 @@ namespace Clipper2Lib const auto sign_cd = TriSign(c) * TriSign(d); return abs_ab == abs_cd && sign_ab == sign_cd; diff --git a/thirdparty/clipper2/src/clipper.engine.cpp b/thirdparty/clipper2/src/clipper.engine.cpp index 8f120267c3c..927e7a75809 100644 --- a/thirdparty/clipper2/src/clipper.engine.cpp +++ b/thirdparty/clipper2/src/clipper.engine.cpp @@ -1,21 +1,15 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 27 April 2024 * -* Website : http://www.angusj.com * +* Date : 17 September 2024 * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : This is the main polygon clipping module * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ -#include -#include -#include -#include -#include -#include - #include "clipper2/clipper.engine.h" #include "clipper2/clipper.h" +#include // https://github.com/AngusJohnson/Clipper2/discussions/334 // #discussioncomment-4248602 @@ -85,7 +79,7 @@ namespace Clipper2Lib { inline bool IsOpenEnd(const Vertex& v) { return (v.flags & (VertexFlags::OpenStart | VertexFlags::OpenEnd)) != - VertexFlags::None; + VertexFlags::Empty; } @@ -220,7 +214,7 @@ namespace Clipper2Lib { inline bool IsMaxima(const Vertex& v) { - return ((v.flags & VertexFlags::LocalMax) != VertexFlags::None); + return ((v.flags & VertexFlags::LocalMax) != VertexFlags::Empty); } @@ -235,12 +229,12 @@ namespace Clipper2Lib { if (e.wind_dx > 0) while ((result->next->pt.y == result->pt.y) && ((result->flags & (VertexFlags::OpenEnd | - VertexFlags::LocalMax)) == VertexFlags::None)) + VertexFlags::LocalMax)) == VertexFlags::Empty)) result = result->next; else while (result->prev->pt.y == result->pt.y && ((result->flags & (VertexFlags::OpenEnd | - VertexFlags::LocalMax)) == VertexFlags::None)) + VertexFlags::LocalMax)) == VertexFlags::Empty)) result = result->prev; if (!IsMaxima(*result)) result = nullptr; // not a maxima return result; @@ -478,7 +472,7 @@ namespace Clipper2Lib { inline bool IsJoined(const Active& e) { - return e.join_with != JoinWith::None; + return e.join_with != JoinWith::NoJoin; } inline void SetOwner(OutRec* outrec, OutRec* new_owner) @@ -517,7 +511,7 @@ namespace Clipper2Lib { while (op2 != op && op2->pt.y > pt.y) op2 = op2->next; if (op2 == op) break; - // must have touched or crossed the pt.Y horizonal + // must have touched or crossed the pt.Y horizontal // and this must happen an even number of times if (op2->pt.y == pt.y) // touching the horizontal @@ -564,7 +558,7 @@ namespace Clipper2Lib { while (op2->next != op && ((op2->pt.x == op2->next->pt.x && op2->pt.x == op2->prev->pt.x) || (op2->pt.y == op2->next->pt.y && op2->pt.y == op2->prev->pt.y))) op2 = op2->next; - result.push_back(op2->pt); + result.emplace_back(op2->pt); OutPt* prevOp = op2; op2 = op2->next; while (op2 != op) @@ -572,7 +566,7 @@ namespace Clipper2Lib { if ((op2->pt.x != op2->next->pt.x || op2->pt.x != prevOp->pt.x) && (op2->pt.y != op2->next->pt.y || op2->pt.y != prevOp->pt.y)) { - result.push_back(op2->pt); + result.emplace_back(op2->pt); prevOp = op2; } op2 = op2->next; @@ -608,10 +602,10 @@ namespace Clipper2Lib { Vertex& vert, PathType polytype, bool is_open) { //make sure the vertex is added only once ... - if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return; + if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return; vert.flags = (vert.flags | VertexFlags::LocalMin); - list.push_back(std::make_unique (&vert, polytype, is_open)); + list.emplace_back(std::make_unique (&vert, polytype, is_open)); } void AddPaths_(const Paths64& paths, PathType polytype, bool is_open, @@ -643,7 +637,7 @@ namespace Clipper2Lib { } curr_v->prev = prev_v; curr_v->pt = pt; - curr_v->flags = VertexFlags::None; + curr_v->flags = VertexFlags::Empty; prev_v = curr_v++; cnt++; } @@ -725,10 +719,10 @@ namespace Clipper2Lib { void ReuseableDataContainer64::AddLocMin(Vertex& vert, PathType polytype, bool is_open) { //make sure the vertex is added only once ... - if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return; + if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return; vert.flags = (vert.flags | VertexFlags::LocalMin); - minima_list_.push_back(std::make_unique (&vert, polytype, is_open)); + minima_list_.emplace_back(std::make_unique (&vert, polytype, is_open)); } void ReuseableDataContainer64::AddPaths(const Paths64& paths, @@ -836,9 +830,7 @@ namespace Clipper2Lib { void ClipperBase::AddPath(const Path64& path, PathType polytype, bool is_open) { - Paths64 tmp; - tmp.push_back(path); - AddPaths(tmp, polytype, is_open); + AddPaths(Paths64(1, path), polytype, is_open); } void ClipperBase::AddPaths(const Paths64& paths, PathType polytype, bool is_open) @@ -857,7 +849,7 @@ namespace Clipper2Lib { LocalMinimaList::const_iterator i; for (i = reuseable_data.minima_list_.cbegin(); i != reuseable_data.minima_list_.cend(); ++i) { - minima_list_.push_back(std::make_unique ((*i)->vertex, (*i)->polytype, (*i)->is_open)); + minima_list_.emplace_back(std::make_unique ((*i)->vertex, (*i)->polytype, (*i)->is_open)); if ((*i)->is_open) has_open_paths_ = true; } } @@ -907,10 +899,10 @@ namespace Clipper2Lib { void ClipperBase::AddLocMin(Vertex& vert, PathType polytype, bool is_open) { //make sure the vertex is added only once ... - if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return; + if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return; vert.flags = (vert.flags | VertexFlags::LocalMin); - minima_list_.push_back(std::make_unique (&vert, polytype, is_open)); + minima_list_.emplace_back(std::make_unique (&vert, polytype, is_open)); } bool ClipperBase::IsContributingClosed(const Active& e) const @@ -928,11 +920,14 @@ namespace Clipper2Lib { case FillRule::Negative: if (e.wind_cnt != -1) return false; break; + // Should never happen, but adding this to stop a compiler warning + default: + break; } switch (cliptype_) { - case ClipType::None: + case ClipType::NoClip: return false; case ClipType::Intersection: switch (fillrule_) @@ -978,6 +973,9 @@ namespace Clipper2Lib { break; case ClipType::Xor: return true; break; + // Should never happen, but adding this to stop a compiler warning + default: + break; } return false; // we should never get here } @@ -1208,7 +1206,7 @@ namespace Clipper2Lib { while (PopLocalMinima(bot_y, local_minima)) { - if ((local_minima->vertex->flags & VertexFlags::OpenStart) != VertexFlags::None) + if ((local_minima->vertex->flags & VertexFlags::OpenStart) != VertexFlags::Empty) { left_bound = nullptr; } @@ -1224,7 +1222,7 @@ namespace Clipper2Lib { SetDx(*left_bound); } - if ((local_minima->vertex->flags & VertexFlags::OpenEnd) != VertexFlags::None) + if ((local_minima->vertex->flags & VertexFlags::OpenEnd) != VertexFlags::Empty) { right_bound = nullptr; } @@ -1488,7 +1486,7 @@ namespace Clipper2Lib { { OutRec* result = new OutRec(); result->idx = outrec_list_.size(); - outrec_list_.push_back(result); + outrec_list_.emplace_back(result); result->pts = nullptr; result->owner = nullptr; result->polypath = nullptr; @@ -1631,12 +1629,12 @@ namespace Clipper2Lib { if (Path1InsidePath2(prevOp, newOp)) { newOr->splits = new OutRecList(); - newOr->splits->push_back(outrec); + newOr->splits->emplace_back(outrec); } else { if (!outrec->splits) outrec->splits = new OutRecList(); - outrec->splits->push_back(newOr); + outrec->splits->emplace_back(newOr); } } } @@ -1955,7 +1953,7 @@ namespace Clipper2Lib { else if (IsFront(e1) || (e1.outrec == e2.outrec)) { //this 'else if' condition isn't strictly needed but - //it's sensible to split polygons that ony touch at + //it's sensible to split polygons that only touch at //a common vertex (not at common edges). #ifdef USINGZ @@ -2125,7 +2123,7 @@ namespace Clipper2Lib { using_polytree_ = use_polytrees; Reset(); int64_t y; - if (ct == ClipType::None || !PopScanline(y)) return true; + if (ct == ClipType::NoClip || !PopScanline(y)) return true; while (succeeded_) { @@ -2239,7 +2237,7 @@ namespace Clipper2Lib { HorzJoin join = HorzJoin( DuplicateOp(hs1->left_op, true), DuplicateOp(hs2->left_op, false)); - horz_join_list_.push_back(join); + horz_join_list_.emplace_back(join); } else { @@ -2252,7 +2250,7 @@ namespace Clipper2Lib { HorzJoin join = HorzJoin( DuplicateOp(hs2->left_op, true), DuplicateOp(hs1->left_op, false)); - horz_join_list_.push_back(join); + horz_join_list_.emplace_back(join); } } } @@ -2264,7 +2262,7 @@ namespace Clipper2Lib { if (!toOr->splits) toOr->splits = new OutRecList(); OutRecList::iterator orIter = fromOr->splits->begin(); for (; orIter != fromOr->splits->end(); ++orIter) - toOr->splits->push_back(*orIter); + toOr->splits->emplace_back(*orIter); fromOr->splits->clear(); } @@ -2317,7 +2315,7 @@ namespace Clipper2Lib { or2->owner = or1->owner; if (!or1->splits) or1->splits = new OutRecList(); - or1->splits->push_back(or2); + or1->splits->emplace_back(or2); } else or2->owner = or1; @@ -2376,7 +2374,7 @@ namespace Clipper2Lib { else ip.x = TopX(e2, ip.y); } } - intersect_nodes_.push_back(IntersectNode(&e1, &e2, ip)); + intersect_nodes_.emplace_back(&e1, &e2, ip); } bool ClipperBase::BuildIntersectList(const int64_t top_y) @@ -2497,7 +2495,7 @@ namespace Clipper2Lib { void ClipperBase::AddTrialHorzJoin(OutPt* op) { if (op->outrec->is_open) return; - horz_seg_list_.push_back(HorzSegment(op)); + horz_seg_list_.emplace_back(op); } bool ClipperBase::ResetHorzDirection(const Active& horz, @@ -2655,7 +2653,7 @@ namespace Clipper2Lib { if (horz.outrec) { - //nb: The outrec containining the op returned by IntersectEdges + //nb: The outrec containing the op returned by IntersectEdges //above may no longer be associated with horzEdge. AddTrialHorzJoin(GetLastOp(horz)); } @@ -2789,14 +2787,14 @@ namespace Clipper2Lib { { if (e.join_with == JoinWith::Right) { - e.join_with = JoinWith::None; - e.next_in_ael->join_with = JoinWith::None; + e.join_with = JoinWith::NoJoin; + e.next_in_ael->join_with = JoinWith::NoJoin; AddLocalMinPoly(e, *e.next_in_ael, pt, true); } else { - e.join_with = JoinWith::None; - e.prev_in_ael->join_with = JoinWith::None; + e.join_with = JoinWith::NoJoin; + e.prev_in_ael->join_with = JoinWith::NoJoin; AddLocalMinPoly(*e.prev_in_ael, e, pt, true); } } @@ -2899,14 +2897,14 @@ namespace Clipper2Lib { lastPt = op->pt; op2 = op->next; } - path.push_back(lastPt); + path.emplace_back(lastPt); while (op2 != op) { if (op2->pt != lastPt) { lastPt = op2->pt; - path.push_back(lastPt); + path.emplace_back(lastPt); } if (reverse) op2 = op2->prev; @@ -3031,7 +3029,7 @@ namespace Clipper2Lib { { Path64 path; if (BuildPath64(outrec->pts, reverse_solution_, true, path)) - open_paths.push_back(path); + open_paths.emplace_back(std::move(path)); continue; } @@ -3060,9 +3058,9 @@ namespace Clipper2Lib { op2 = op->next; } #ifdef USINGZ - path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z)); + path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z); #else - path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale)); + path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale); #endif while (op2 != op) @@ -3071,9 +3069,9 @@ namespace Clipper2Lib { { lastPt = op2->pt; #ifdef USINGZ - path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z)); + path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z); #else - path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale)); + path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale); #endif } @@ -3137,7 +3135,7 @@ namespace Clipper2Lib { { PathD path; if (BuildPathD(outrec->pts, reverse_solution_, true, path, invScale_)) - open_paths.push_back(path); + open_paths.emplace_back(std::move(path)); continue; } diff --git a/thirdparty/clipper2/src/clipper.offset.cpp b/thirdparty/clipper2/src/clipper.offset.cpp index 508a7f0831d..23e405ed1d5 100644 --- a/thirdparty/clipper2/src/clipper.offset.cpp +++ b/thirdparty/clipper2/src/clipper.offset.cpp @@ -1,21 +1,34 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 17 April 2024 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2024 * +* Date : 22 January 2025 * +* Website : https://www.angusj.com * +* Copyright : Angus Johnson 2010-2025 * * Purpose : Path Offset (Inflate/Shrink) * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ -#include #include "clipper2/clipper.h" #include "clipper2/clipper.offset.h" namespace Clipper2Lib { -const double default_arc_tolerance = 0.25; const double floating_point_tolerance = 1e-12; +// Clipper2 approximates arcs by using series of relatively short straight +//line segments. And logically, shorter line segments will produce better arc +// approximations. But very short segments can degrade performance, usually +// with little or no discernable improvement in curve quality. Very short +// segments can even detract from curve quality, due to the effects of integer +// rounding. Since there isn't an optimal number of line segments for any given +// arc radius (that perfectly balances curve approximation with performance), +// arc tolerance is user defined. Nevertheless, when the user doesn't define +// an arc tolerance (ie leaves alone the 0 default value), the calculated +// default arc tolerance (offset_radius / 500) generally produces good (smooth) +// arc approximations without producing excessively small segment lengths. +// See also: https://www.angusj.com/clipper2/Docs/Trigonometry.htm +const double arc_const = 0.002; // <-- 1/500 + + //------------------------------------------------------------------------------ // Miscellaneous methods //------------------------------------------------------------------------------ @@ -38,13 +51,22 @@ std::optional GetLowestClosedPathIdx(const Paths64& paths) return result; } -PointD GetUnitNormal(const Point64& pt1, const Point64& pt2) +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, + // 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); +} + +static PointD GetUnitNormal(const Point64& pt1, const Point64& pt2) { - double dx, dy, inverse_hypot; if (pt1 == pt2) return PointD(0.0, 0.0); - dx = static_cast(pt2.x - pt1.x); - dy = static_cast(pt2.y - pt1.y); - inverse_hypot = 1.0 / hypot(dx, dy); + double dx = static_cast(pt2.x - pt1.x); + double dy = static_cast(pt2.y - pt1.y); + double inverse_hypot = 1.0 / Hypot(dx, dy); dx *= inverse_hypot; dy *= inverse_hypot; return PointD(dy, -dx); @@ -55,12 +77,6 @@ inline bool AlmostZero(double value, double epsilon = 0.001) return std::fabs(value) < epsilon; } -inline double Hypot(double x, double y) -{ - //see https://stackoverflow.com/a/32436148/359538 - return std::sqrt(x * x + y * y); -} - inline PointD NormalizeVector(const PointD& vec) { double h = Hypot(vec.x, vec.y); @@ -79,7 +95,7 @@ inline bool IsClosedPath(EndType et) return et == EndType::Polygon || et == EndType::Joined; } -inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta) +static inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta) { #ifdef USINGZ return Point64(pt.x + norm.x * delta, pt.y + norm.y * delta, pt.z); @@ -129,11 +145,11 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType // 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()) && Area(paths_in[lowest_path_idx.value()]) < 0; } else { - lowest_path_idx = std::nullopt; + lowest_path_idx = std::nullopt; is_reversed = false; } } @@ -144,15 +160,13 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType void ClipperOffset::AddPath(const Path64& path, JoinType jt_, EndType et_) { - Paths64 paths; - paths.push_back(path); - AddPaths(paths, jt_, et_); + groups_.emplace_back(Paths64(1, path), jt_, et_); } void ClipperOffset::AddPaths(const Paths64 &paths, JoinType jt_, EndType et_) { if (paths.size() == 0) return; - groups_.push_back(Group(paths, jt_, et_)); + groups_.emplace_back(paths, jt_, et_); } void ClipperOffset::BuildNormals(const Path64& path) @@ -162,8 +176,8 @@ void ClipperOffset::BuildNormals(const Path64& path) if (path.size() == 0) return; Path64::const_iterator path_iter, path_stop_iter = --path.cend(); for (path_iter = path.cbegin(); path_iter != path_stop_iter; ++path_iter) - norms.push_back(GetUnitNormal(*path_iter,*(path_iter +1))); - norms.push_back(GetUnitNormal(*path_stop_iter, *(path.cbegin()))); + norms.emplace_back(GetUnitNormal(*path_iter,*(path_iter +1))); + norms.emplace_back(GetUnitNormal(*path_stop_iter, *(path.cbegin()))); } void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k) @@ -190,8 +204,8 @@ void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k) pt2 = PointD(path[j].x + group_delta_ * norms[j].x, path[j].y + group_delta_ * norms[j].y); #endif } - path_out.push_back(Point64(pt1)); - path_out.push_back(Point64(pt2)); + path_out.emplace_back(pt1); + path_out.emplace_back(pt2); } void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k) @@ -220,17 +234,17 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k) PointD pt = ptQ; GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt); //get the second intersect point through reflecion - path_out.push_back(Point64(ReflectPoint(pt, ptQ))); - path_out.push_back(Point64(pt)); + path_out.emplace_back(ReflectPoint(pt, ptQ)); + path_out.emplace_back(pt); } else { PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_); PointD pt = ptQ; GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt); - path_out.push_back(Point64(pt)); + path_out.emplace_back(pt); //get the second intersect point through reflecion - path_out.push_back(Point64(ReflectPoint(pt, ptQ))); + path_out.emplace_back(ReflectPoint(pt, ptQ)); } } @@ -238,14 +252,14 @@ void ClipperOffset::DoMiter(const Path64& path, size_t j, size_t k, double cos_a { double q = group_delta_ / (cos_a + 1); #ifdef USINGZ - path_out.push_back(Point64( + 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)); + path[j].z); #else - path_out.push_back(Point64( + 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].y + (norms[k].y + norms[j].y) * q); #endif } @@ -256,8 +270,7 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle // so we'll need to do the following calculations for *every* vertex. double abs_delta = std::fabs(group_delta_); double arcTol = (arc_tolerance_ > floating_point_tolerance ? - std::min(abs_delta, arc_tolerance_) : - std::log10(2 + abs_delta) * default_arc_tolerance); + std::min(abs_delta, arc_tolerance_) : abs_delta * arc_const); double steps_per_360 = std::min(PI / std::acos(1 - arcTol / abs_delta), abs_delta * PI); step_sin_ = std::sin(2 * PI / steps_per_360); step_cos_ = std::cos(2 * PI / steps_per_360); @@ -270,9 +283,9 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle if (j == k) offsetVec.Negate(); #ifdef USINGZ - path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z)); + path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z); #else - path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y)); + 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 for (int i = 1; i < steps; ++i) // ie 1 less than steps @@ -280,12 +293,12 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y, offsetVec.x * step_sin_ + offsetVec.y * step_cos_); #ifdef USINGZ - path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z)); + path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z); #else - path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y)); + path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y); #endif } - path_out.push_back(GetPerpendic(path[j], norms[j], group_delta_)); + path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_)); } void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size_t k) @@ -309,28 +322,25 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size } if (std::fabs(group_delta_) <= floating_point_tolerance) { - path_out.push_back(path[j]); + path_out.emplace_back(path[j]); return; } if (cos_a > -0.999 && (sin_a * group_delta_ < 0)) // test for concavity first (#593) { - // is concave (so insert 3 points that will create a negative region) + // 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 + // to ensure that path reversals (ie over-shrunk paths) are removed. #ifdef USINGZ - path_out.push_back(Point64(GetPerpendic(path[j], norms[k], group_delta_), path[j].z)); + path_out.emplace_back(GetPerpendic(path[j], norms[k], group_delta_), path[j].z); + path_out.emplace_back(path[j]); // (#405, #873, #916) + path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_), path[j].z); #else - path_out.push_back(GetPerpendic(path[j], norms[k], group_delta_)); -#endif - - // this extra point is the only simple way to ensure that path reversals - // (ie over-shrunk paths) are fully cleaned out with the trailing union op. - // However it's probably safe to skip this whenever an angle is almost flat. - if (cos_a < 0.99) path_out.push_back(path[j]); // (#405) - -#ifdef USINGZ - path_out.push_back(Point64(GetPerpendic(path[j], norms[j], group_delta_), path[j].z)); -#else - path_out.push_back(GetPerpendic(path[j], norms[j], group_delta_)); + path_out.emplace_back(GetPerpendic(path[j], norms[k], group_delta_)); + path_out.emplace_back(path[j]); // (#405, #873, #916) + path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_)); #endif } else if (cos_a > 0.999 && join_type_ != JoinType::Round) @@ -357,7 +367,7 @@ 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); - solution->push_back(path_out); + solution->emplace_back(path_out); } void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path) @@ -368,7 +378,7 @@ void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path) //rebuild normals std::reverse(norms.begin(), norms.end()); - norms.push_back(norms[0]); + norms.emplace_back(norms[0]); norms.erase(norms.begin()); NegatePath(norms); @@ -381,7 +391,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path) if (deltaCallback64_) group_delta_ = deltaCallback64_(path, norms, 0, 0); if (std::fabs(group_delta_) <= floating_point_tolerance) - path_out.push_back(path[0]); + path_out.emplace_back(path[0]); else { switch (end_type_) @@ -413,7 +423,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path) group_delta_ = deltaCallback64_(path, norms, highI, highI); if (std::fabs(group_delta_) <= floating_point_tolerance) - path_out.push_back(path[highI]); + path_out.emplace_back(path[highI]); else { switch (end_type_) @@ -432,7 +442,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path) for (size_t j = highI -1, k = highI; j > 0; k = j, --j) OffsetPoint(group, path, j, k); - solution->push_back(path_out); + solution->emplace_back(path_out); } void ClipperOffset::DoGroupOffset(Group& group) @@ -454,13 +464,12 @@ void ClipperOffset::DoGroupOffset(Group& group) if (group.join_type == JoinType::Round || group.end_type == EndType::Round) { // calculate the number of steps required to approximate a circle - // (see http://www.angusj.com/clipper2/Docs/Trigonometry.htm) + // (see https://www.angusj.com/clipper2/Docs/Trigonometry.htm) // arcTol - when arc_tolerance_ is undefined (0) then curve imprecision // will be relative to the size of the offset (delta). Obviously very //large offsets will almost always require much less precision. - double arcTol = (arc_tolerance_ > floating_point_tolerance ? - std::min(abs_delta, arc_tolerance_) : - std::log10(2 + abs_delta) * default_arc_tolerance); + double arcTol = (arc_tolerance_ > floating_point_tolerance) ? + std::min(abs_delta, arc_tolerance_) : abs_delta * arc_const; double steps_per_360 = std::min(PI / std::acos(1 - arcTol / abs_delta), abs_delta * PI); step_sin_ = std::sin(2 * PI / steps_per_360); @@ -507,7 +516,7 @@ void ClipperOffset::DoGroupOffset(Group& group) #endif } - solution->push_back(path_out); + solution->emplace_back(path_out); continue; } // end of offsetting a single point @@ -588,7 +597,7 @@ 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); @@ -617,10 +626,10 @@ void ClipperOffset::ExecuteInternal(double delta) } } -void ClipperOffset::Execute(double delta, Paths64& paths) +void ClipperOffset::Execute(double delta, Paths64& paths64) { - paths.clear(); - solution = &paths; + paths64.clear(); + solution = &paths64; solution_tree = nullptr; ExecuteInternal(delta); } diff --git a/thirdparty/clipper2/src/clipper.rectclip.cpp b/thirdparty/clipper2/src/clipper.rectclip.cpp index 23809b5ef6b..a5d66df4630 100644 --- a/thirdparty/clipper2/src/clipper.rectclip.cpp +++ b/thirdparty/clipper2/src/clipper.rectclip.cpp @@ -1,13 +1,12 @@ /******************************************************************************* * Author : Angus Johnson * * Date : 5 July 2024 * -* Website : http://www.angusj.com * +* Website : https://www.angusj.com * * Copyright : Angus Johnson 2010-2024 * * Purpose : FAST rectangular clipping * -* License : http://www.boost.org/LICENSE_1_0.txt * +* License : https://www.boost.org/LICENSE_1_0.txt * *******************************************************************************/ -#include #include "clipper2/clipper.h" #include "clipper2/clipper.rectclip.h" @@ -282,7 +281,7 @@ namespace Clipper2Lib { { if (op->edge) return; op->edge = &edge; - edge.push_back(op); + edge.emplace_back(op); } inline void UncoupleEdge(OutPt2* op) @@ -328,7 +327,7 @@ namespace Clipper2Lib { result->pt = pt; result->next = result; result->prev = result; - results_.push_back(result); + results_.emplace_back(result); } else { @@ -489,7 +488,7 @@ namespace Clipper2Lib { { bool isClockw = IsClockwise(prev, loc, prev_pt, path[i], rect_mp_); do { - start_locs_.push_back(prev); + start_locs_.emplace_back(prev); prev = GetAdjacentLocation(prev, isClockw); } while (prev != loc); crossing_loc = crossing_prev; // still not crossed @@ -514,7 +513,7 @@ namespace Clipper2Lib { if (first_cross_ == Location::Inside) { first_cross_ = crossing_loc; - start_locs_.push_back(prev); + start_locs_.emplace_back(prev); } else if (prev != crossing_loc) { @@ -536,7 +535,7 @@ namespace Clipper2Lib { if (first_cross_ == Location::Inside) { first_cross_ = loc; - start_locs_.push_back(prev); + start_locs_.emplace_back(prev); } loc = crossing_loc; @@ -750,7 +749,7 @@ namespace Clipper2Lib { if (!isRejoining) { size_t new_idx = results_.size(); - results_.push_back(p1a); + results_.emplace_back(p1a); SetNewOwner(p1a, new_idx); } @@ -861,11 +860,11 @@ namespace Clipper2Lib { if (!op2) return Path64(); Path64 result; - result.push_back(op->pt); + result.emplace_back(op->pt); op2 = op->next; while (op2 != op) { - result.push_back(op2->pt); + result.emplace_back(op2->pt); op2 = op2->next; } return result; @@ -885,7 +884,7 @@ namespace Clipper2Lib { else if (rect_.Contains(path_bounds_)) { // the path must be completely inside rect_ - result.push_back(path); + result.emplace_back(path); continue; } @@ -898,7 +897,7 @@ namespace Clipper2Lib { { Path64 tmp = GetPath(op); if (!tmp.empty()) - result.emplace_back(tmp); + result.emplace_back(std::move(tmp)); } //clean up after every loop @@ -930,7 +929,7 @@ namespace Clipper2Lib { { Path64 tmp = GetPath(op); if (!tmp.empty()) - result.emplace_back(tmp); + result.emplace_back(std::move(tmp)); } results_.clear(); @@ -1015,11 +1014,11 @@ namespace Clipper2Lib { Path64 result; if (!op || op == op->next) return result; op = op->next; // starting at path beginning - result.push_back(op->pt); + result.emplace_back(op->pt); OutPt2 *op2 = op->next; while (op2 != op) { - result.push_back(op2->pt); + result.emplace_back(op2->pt); op2 = op2->next; } return result;