clipper2 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +165 -0
- data/examples/larb_transform.rb +17 -0
- data/examples/rugl_mesh.rb +33 -0
- data/examples/svg_boolean.rb +28 -0
- data/ext/clipper2/CMakeLists.txt +27 -0
- data/ext/clipper2/clipper2_native.cpp +2 -0
- data/ext/clipper2/extconf.rb +27 -0
- data/ext/clipper2/generate_bindings.rb +73 -0
- data/ext/clipper2/memory_check.cpp +48 -0
- data/ext/clipper2/vendor/LICENSE +23 -0
- data/ext/clipper2/vendor/UPSTREAM.md +11 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.core.h +1159 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.engine.h +635 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.export.h +851 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.h +796 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.minkowski.h +117 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.offset.h +125 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.rectclip.h +80 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.triangulation.h +27 -0
- data/ext/clipper2/vendor/include/clipper2/clipper.version.h +6 -0
- data/ext/clipper2/vendor/src/clipper.engine.cpp +3152 -0
- data/ext/clipper2/vendor/src/clipper.offset.cpp +661 -0
- data/ext/clipper2/vendor/src/clipper.rectclip.cpp +1027 -0
- data/ext/clipper2/vendor/src/clipper.triangulation.cpp +1221 -0
- data/lib/clipper2/api.rb +45 -0
- data/lib/clipper2/c_paths64.rb +80 -0
- data/lib/clipper2/earcut/engine.rb +191 -0
- data/lib/clipper2/earcut/geometry.rb +100 -0
- data/lib/clipper2/earcut/node.rb +18 -0
- data/lib/clipper2/earcut/ring.rb +94 -0
- data/lib/clipper2/earcut.rb +18 -0
- data/lib/clipper2/errors.rb +19 -0
- data/lib/clipper2/generated.rb +62 -0
- data/lib/clipper2/native.rb +38 -0
- data/lib/clipper2/native_memory.rb +64 -0
- data/lib/clipper2/operations.rb +206 -0
- data/lib/clipper2/path.rb +171 -0
- data/lib/clipper2/path_simplifier.rb +61 -0
- data/lib/clipper2/paths.rb +130 -0
- data/lib/clipper2/quantizer.rb +48 -0
- data/lib/clipper2/triangulation.rb +103 -0
- data/lib/clipper2/version.rb +5 -0
- data/lib/clipper2.rb +34 -0
- data/licenses/CLIPPER2-BSL-1.0.txt +23 -0
- data/licenses/EARCUT-ISC.txt +15 -0
- metadata +113 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
* Author : Angus Johnson *
|
|
3
|
+
* Date : 1 November 2023 *
|
|
4
|
+
* Website : https://www.angusj.com *
|
|
5
|
+
* Copyright : Angus Johnson 2010-2023 *
|
|
6
|
+
* Purpose : Minkowski Sum and Difference *
|
|
7
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
8
|
+
*******************************************************************************/
|
|
9
|
+
|
|
10
|
+
#ifndef CLIPPER_MINKOWSKI_H
|
|
11
|
+
#define CLIPPER_MINKOWSKI_H
|
|
12
|
+
|
|
13
|
+
#include "clipper2/clipper.core.h"
|
|
14
|
+
|
|
15
|
+
namespace Clipper2Lib
|
|
16
|
+
{
|
|
17
|
+
|
|
18
|
+
namespace detail
|
|
19
|
+
{
|
|
20
|
+
inline Paths64 Minkowski(const Path64& pattern, const Path64& path, bool isSum, bool isClosed)
|
|
21
|
+
{
|
|
22
|
+
size_t delta = isClosed ? 0 : 1;
|
|
23
|
+
size_t patLen = pattern.size(), pathLen = path.size();
|
|
24
|
+
if (patLen == 0 || pathLen == 0) return Paths64();
|
|
25
|
+
Paths64 tmp;
|
|
26
|
+
tmp.reserve(pathLen);
|
|
27
|
+
|
|
28
|
+
if (isSum)
|
|
29
|
+
{
|
|
30
|
+
for (const Point64& p : path)
|
|
31
|
+
{
|
|
32
|
+
Path64 path2(pattern.size());
|
|
33
|
+
std::transform(pattern.cbegin(), pattern.cend(),
|
|
34
|
+
path2.begin(), [p](const Point64& pt2) {return p + pt2; });
|
|
35
|
+
tmp.emplace_back(std::move(path2));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
{
|
|
40
|
+
for (const Point64& p : path)
|
|
41
|
+
{
|
|
42
|
+
Path64 path2(pattern.size());
|
|
43
|
+
std::transform(pattern.cbegin(), pattern.cend(),
|
|
44
|
+
path2.begin(), [p](const Point64& pt2) {return p - pt2; });
|
|
45
|
+
tmp.emplace_back(std::move(path2));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Paths64 result;
|
|
50
|
+
result.reserve((pathLen - delta) * patLen);
|
|
51
|
+
size_t g = isClosed ? pathLen - 1 : 0;
|
|
52
|
+
for (size_t h = patLen - 1, i = delta; i < pathLen; ++i)
|
|
53
|
+
{
|
|
54
|
+
for (size_t j = 0; j < patLen; j++)
|
|
55
|
+
{
|
|
56
|
+
Path64 quad;
|
|
57
|
+
quad.reserve(4);
|
|
58
|
+
{
|
|
59
|
+
quad.emplace_back(tmp[g][h]);
|
|
60
|
+
quad.emplace_back(tmp[i][h]);
|
|
61
|
+
quad.emplace_back(tmp[i][j]);
|
|
62
|
+
quad.emplace_back(tmp[g][j]);
|
|
63
|
+
}
|
|
64
|
+
if (!IsPositive(quad))
|
|
65
|
+
std::reverse(quad.begin(), quad.end());
|
|
66
|
+
result.emplace_back(std::move(quad));
|
|
67
|
+
h = j;
|
|
68
|
+
}
|
|
69
|
+
g = i;
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
inline Paths64 Union(const Paths64& subjects, FillRule fillrule)
|
|
75
|
+
{
|
|
76
|
+
Paths64 result;
|
|
77
|
+
Clipper64 clipper;
|
|
78
|
+
clipper.AddSubject(subjects);
|
|
79
|
+
clipper.Execute(ClipType::Union, fillrule, result);
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
} // namespace internal
|
|
84
|
+
|
|
85
|
+
inline Paths64 MinkowskiSum(const Path64& pattern, const Path64& path, bool isClosed)
|
|
86
|
+
{
|
|
87
|
+
return detail::Union(detail::Minkowski(pattern, path, true, isClosed), FillRule::NonZero);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
inline PathsD MinkowskiSum(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2)
|
|
91
|
+
{
|
|
92
|
+
int error_code = 0;
|
|
93
|
+
double scale = pow(10, decimalPlaces);
|
|
94
|
+
Path64 pat64 = ScalePath<int64_t, double>(pattern, scale, error_code);
|
|
95
|
+
Path64 path64 = ScalePath<int64_t, double>(path, scale, error_code);
|
|
96
|
+
Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, true, isClosed), FillRule::NonZero);
|
|
97
|
+
return ScalePaths<double, int64_t>(tmp, 1 / scale, error_code);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
inline Paths64 MinkowskiDiff(const Path64& pattern, const Path64& path, bool isClosed)
|
|
101
|
+
{
|
|
102
|
+
return detail::Union(detail::Minkowski(pattern, path, false, isClosed), FillRule::NonZero);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
inline PathsD MinkowskiDiff(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2)
|
|
106
|
+
{
|
|
107
|
+
int error_code = 0;
|
|
108
|
+
double scale = pow(10, decimalPlaces);
|
|
109
|
+
Path64 pat64 = ScalePath<int64_t, double>(pattern, scale, error_code);
|
|
110
|
+
Path64 path64 = ScalePath<int64_t, double>(path, scale, error_code);
|
|
111
|
+
Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, false, isClosed), FillRule::NonZero);
|
|
112
|
+
return ScalePaths<double, int64_t>(tmp, 1 / scale, error_code);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
} // Clipper2Lib namespace
|
|
116
|
+
|
|
117
|
+
#endif // CLIPPER_MINKOWSKI_H
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
* Author : Angus Johnson *
|
|
3
|
+
* Date : 22 January 2025 *
|
|
4
|
+
* Website : https://www.angusj.com *
|
|
5
|
+
* Copyright : Angus Johnson 2010-2025 *
|
|
6
|
+
* Purpose : Path Offset (Inflate/Shrink) *
|
|
7
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
8
|
+
*******************************************************************************/
|
|
9
|
+
|
|
10
|
+
#ifndef CLIPPER_OFFSET_H_
|
|
11
|
+
#define CLIPPER_OFFSET_H_
|
|
12
|
+
|
|
13
|
+
#include "clipper.core.h"
|
|
14
|
+
#include "clipper.engine.h"
|
|
15
|
+
#include <optional>
|
|
16
|
+
|
|
17
|
+
namespace Clipper2Lib {
|
|
18
|
+
|
|
19
|
+
enum class JoinType { Square, Bevel, Round, Miter };
|
|
20
|
+
//Square : Joins are 'squared' at exactly the offset distance (more complex code)
|
|
21
|
+
//Bevel : Similar to Square, but the offset distance varies with angle (simple code & faster)
|
|
22
|
+
|
|
23
|
+
enum class EndType {Polygon, Joined, Butt, Square, Round};
|
|
24
|
+
//Butt : offsets both sides of a path, with square blunt ends
|
|
25
|
+
//Square : offsets both sides of a path, with square extended ends
|
|
26
|
+
//Round : offsets both sides of a path, with round extended ends
|
|
27
|
+
//Joined : offsets both sides of a path, with joined ends
|
|
28
|
+
//Polygon: offsets only one side of a closed path
|
|
29
|
+
|
|
30
|
+
typedef std::function<double(const Path64& path, const PathD& path_normals, size_t curr_idx, size_t prev_idx)> DeltaCallback64;
|
|
31
|
+
|
|
32
|
+
class ClipperOffset {
|
|
33
|
+
private:
|
|
34
|
+
|
|
35
|
+
class Group {
|
|
36
|
+
public:
|
|
37
|
+
Paths64 paths_in;
|
|
38
|
+
std::optional<size_t> lowest_path_idx{};
|
|
39
|
+
bool is_reversed = false;
|
|
40
|
+
JoinType join_type;
|
|
41
|
+
EndType end_type;
|
|
42
|
+
Group(const Paths64& _paths, JoinType _join_type, EndType _end_type);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
int error_code_ = 0;
|
|
46
|
+
double delta_ = 0.0;
|
|
47
|
+
double group_delta_ = 0.0;
|
|
48
|
+
double temp_lim_ = 0.0;
|
|
49
|
+
double steps_per_rad_ = 0.0;
|
|
50
|
+
double step_sin_ = 0.0;
|
|
51
|
+
double step_cos_ = 0.0;
|
|
52
|
+
PathD norms;
|
|
53
|
+
Path64 path_out;
|
|
54
|
+
Paths64* solution = nullptr;
|
|
55
|
+
PolyTree64* solution_tree = nullptr;
|
|
56
|
+
std::vector<Group> groups_;
|
|
57
|
+
JoinType join_type_ = JoinType::Bevel;
|
|
58
|
+
EndType end_type_ = EndType::Polygon;
|
|
59
|
+
|
|
60
|
+
double miter_limit_ = 0.0;
|
|
61
|
+
double arc_tolerance_ = 0.0;
|
|
62
|
+
bool preserve_collinear_ = false;
|
|
63
|
+
bool reverse_solution_ = false;
|
|
64
|
+
|
|
65
|
+
#ifdef USINGZ
|
|
66
|
+
ZCallback64 zCallback64_ = nullptr;
|
|
67
|
+
void ZCB(const Point64& bot1, const Point64& top1,
|
|
68
|
+
const Point64& bot2, const Point64& top2, Point64& ip);
|
|
69
|
+
#endif
|
|
70
|
+
DeltaCallback64 deltaCallback64_ = nullptr;
|
|
71
|
+
size_t CalcSolutionCapacity();
|
|
72
|
+
bool CheckReverseOrientation();
|
|
73
|
+
void DoBevel(const Path64& path, size_t j, size_t k);
|
|
74
|
+
void DoSquare(const Path64& path, size_t j, size_t k);
|
|
75
|
+
void DoMiter(const Path64& path, size_t j, size_t k, double cos_a);
|
|
76
|
+
void DoRound(const Path64& path, size_t j, size_t k, double angle);
|
|
77
|
+
void BuildNormals(const Path64& path);
|
|
78
|
+
void OffsetPolygon(Group& group, const Path64& path);
|
|
79
|
+
void OffsetOpenJoined(Group& group, const Path64& path);
|
|
80
|
+
void OffsetOpenPath(Group& group, const Path64& path);
|
|
81
|
+
void OffsetPoint(Group& group, const Path64& path, size_t j, size_t k);
|
|
82
|
+
void DoGroupOffset(Group &group);
|
|
83
|
+
void ExecuteInternal(double delta);
|
|
84
|
+
public:
|
|
85
|
+
explicit ClipperOffset(double miter_limit = 2.0,
|
|
86
|
+
double arc_tolerance = 0.0,
|
|
87
|
+
bool preserve_collinear = false,
|
|
88
|
+
bool reverse_solution = false) :
|
|
89
|
+
miter_limit_(miter_limit), arc_tolerance_(arc_tolerance),
|
|
90
|
+
preserve_collinear_(preserve_collinear),
|
|
91
|
+
reverse_solution_(reverse_solution) { }
|
|
92
|
+
|
|
93
|
+
~ClipperOffset() { Clear(); }
|
|
94
|
+
|
|
95
|
+
int ErrorCode() const { return error_code_; }
|
|
96
|
+
void AddPath(const Path64& path, JoinType jt_, EndType et_);
|
|
97
|
+
void AddPaths(const Paths64& paths, JoinType jt_, EndType et_);
|
|
98
|
+
void Clear() { groups_.clear(); norms.clear(); }
|
|
99
|
+
|
|
100
|
+
void Execute(double delta, Paths64& sols_64);
|
|
101
|
+
void Execute(double delta, PolyTree64& polytree);
|
|
102
|
+
void Execute(DeltaCallback64 delta_cb, Paths64& paths);
|
|
103
|
+
|
|
104
|
+
double MiterLimit() const { return miter_limit_; }
|
|
105
|
+
void MiterLimit(double miter_limit) { miter_limit_ = miter_limit; }
|
|
106
|
+
|
|
107
|
+
//ArcTolerance: needed for rounded offsets (See offset_triginometry2.svg)
|
|
108
|
+
double ArcTolerance() const { return arc_tolerance_; }
|
|
109
|
+
void ArcTolerance(double arc_tolerance) { arc_tolerance_ = arc_tolerance; }
|
|
110
|
+
|
|
111
|
+
bool PreserveCollinear() const { return preserve_collinear_; }
|
|
112
|
+
void PreserveCollinear(bool preserve_collinear){preserve_collinear_ = preserve_collinear;}
|
|
113
|
+
|
|
114
|
+
bool ReverseSolution() const { return reverse_solution_; }
|
|
115
|
+
void ReverseSolution(bool reverse_solution) {reverse_solution_ = reverse_solution;}
|
|
116
|
+
|
|
117
|
+
#ifdef USINGZ
|
|
118
|
+
void SetZCallback(ZCallback64 cb) { zCallback64_ = cb; }
|
|
119
|
+
#endif
|
|
120
|
+
void SetDeltaCallback(DeltaCallback64 cb) { deltaCallback64_ = cb; }
|
|
121
|
+
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
#endif /* CLIPPER_OFFSET_H_ */
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
* Author : Angus Johnson *
|
|
3
|
+
* Date : 5 July 2024 *
|
|
4
|
+
* Website : https://www.angusj.com *
|
|
5
|
+
* Copyright : Angus Johnson 2010-2024 *
|
|
6
|
+
* Purpose : FAST rectangular clipping *
|
|
7
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
8
|
+
*******************************************************************************/
|
|
9
|
+
|
|
10
|
+
#ifndef CLIPPER_RECTCLIP_H
|
|
11
|
+
#define CLIPPER_RECTCLIP_H
|
|
12
|
+
|
|
13
|
+
#include "clipper2/clipper.core.h"
|
|
14
|
+
#include <queue>
|
|
15
|
+
|
|
16
|
+
namespace Clipper2Lib
|
|
17
|
+
{
|
|
18
|
+
|
|
19
|
+
// Location: the order is important here, see StartLocsIsClockwise()
|
|
20
|
+
enum class Location { Left, Top, Right, Bottom, Inside };
|
|
21
|
+
|
|
22
|
+
class OutPt2;
|
|
23
|
+
typedef std::vector<OutPt2*> OutPt2List;
|
|
24
|
+
|
|
25
|
+
class OutPt2 {
|
|
26
|
+
public:
|
|
27
|
+
Point64 pt;
|
|
28
|
+
size_t owner_idx = 0;
|
|
29
|
+
OutPt2List* edge = nullptr;
|
|
30
|
+
OutPt2* next = nullptr;
|
|
31
|
+
OutPt2* prev = nullptr;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//------------------------------------------------------------------------------
|
|
35
|
+
// RectClip64
|
|
36
|
+
//------------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
class RectClip64 {
|
|
39
|
+
private:
|
|
40
|
+
void ExecuteInternal(const Path64& path);
|
|
41
|
+
Path64 GetPath(OutPt2*& op);
|
|
42
|
+
protected:
|
|
43
|
+
const Rect64 rect_;
|
|
44
|
+
const Path64 rect_as_path_;
|
|
45
|
+
const Point64 rect_mp_;
|
|
46
|
+
Rect64 path_bounds_;
|
|
47
|
+
std::deque<OutPt2> op_container_;
|
|
48
|
+
OutPt2List results_; // each path can be broken into multiples
|
|
49
|
+
OutPt2List edges_[8]; // clockwise and counter-clockwise
|
|
50
|
+
std::vector<Location> start_locs_;
|
|
51
|
+
void CheckEdges();
|
|
52
|
+
void TidyEdges(size_t idx, OutPt2List& cw, OutPt2List& ccw);
|
|
53
|
+
void GetNextLocation(const Path64& path,
|
|
54
|
+
Location& loc, size_t& i, size_t highI);
|
|
55
|
+
OutPt2* Add(Point64 pt, bool start_new = false);
|
|
56
|
+
void AddCorner(Location prev, Location curr);
|
|
57
|
+
void AddCorner(Location& loc, bool isClockwise);
|
|
58
|
+
public:
|
|
59
|
+
explicit RectClip64(const Rect64& rect) :
|
|
60
|
+
rect_(rect),
|
|
61
|
+
rect_as_path_(rect.AsPath()),
|
|
62
|
+
rect_mp_(rect.MidPoint()) {}
|
|
63
|
+
Paths64 Execute(const Paths64& paths);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//------------------------------------------------------------------------------
|
|
67
|
+
// RectClipLines64
|
|
68
|
+
//------------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
class RectClipLines64 : public RectClip64 {
|
|
71
|
+
private:
|
|
72
|
+
void ExecuteInternal(const Path64& path);
|
|
73
|
+
Path64 GetPath(OutPt2*& op);
|
|
74
|
+
public:
|
|
75
|
+
explicit RectClipLines64(const Rect64& rect) : RectClip64(rect) {}
|
|
76
|
+
Paths64 Execute(const Paths64& paths);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
} // Clipper2Lib namespace
|
|
80
|
+
#endif // CLIPPER_RECTCLIP_H
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*******************************************************************************
|
|
2
|
+
* Author : Angus Johnson *
|
|
3
|
+
* Date : 6 December 2025 *
|
|
4
|
+
* Release : BETA RELEASE *
|
|
5
|
+
* Website : https://www.angusj.com *
|
|
6
|
+
* Copyright : Angus Johnson 2010-2025 *
|
|
7
|
+
* Purpose : Delaunay Triangulation *
|
|
8
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
9
|
+
*******************************************************************************/
|
|
10
|
+
|
|
11
|
+
#ifndef CLIPPER_TRIANGULATION_H
|
|
12
|
+
#define CLIPPER_TRIANGULATION_H
|
|
13
|
+
|
|
14
|
+
#include <stack>
|
|
15
|
+
#include "clipper2/clipper.core.h"
|
|
16
|
+
|
|
17
|
+
namespace Clipper2Lib
|
|
18
|
+
{
|
|
19
|
+
|
|
20
|
+
enum class TriangulateResult { success, fail, no_polygons, paths_intersect };
|
|
21
|
+
|
|
22
|
+
// Triangulate - this function will not accept intesecting paths
|
|
23
|
+
TriangulateResult Triangulate(const Paths64& pp, Paths64& solution, bool useDelaunay = true);
|
|
24
|
+
TriangulateResult Triangulate(const PathsD& pp, int decPlaces, PathsD& solution, bool useDelaunay = true);
|
|
25
|
+
|
|
26
|
+
} // Clipper2Lib namespace
|
|
27
|
+
#endif // CLIPPER_TRIANGULATION_H
|