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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +165 -0
  4. data/examples/larb_transform.rb +17 -0
  5. data/examples/rugl_mesh.rb +33 -0
  6. data/examples/svg_boolean.rb +28 -0
  7. data/ext/clipper2/CMakeLists.txt +27 -0
  8. data/ext/clipper2/clipper2_native.cpp +2 -0
  9. data/ext/clipper2/extconf.rb +27 -0
  10. data/ext/clipper2/generate_bindings.rb +73 -0
  11. data/ext/clipper2/memory_check.cpp +48 -0
  12. data/ext/clipper2/vendor/LICENSE +23 -0
  13. data/ext/clipper2/vendor/UPSTREAM.md +11 -0
  14. data/ext/clipper2/vendor/include/clipper2/clipper.core.h +1159 -0
  15. data/ext/clipper2/vendor/include/clipper2/clipper.engine.h +635 -0
  16. data/ext/clipper2/vendor/include/clipper2/clipper.export.h +851 -0
  17. data/ext/clipper2/vendor/include/clipper2/clipper.h +796 -0
  18. data/ext/clipper2/vendor/include/clipper2/clipper.minkowski.h +117 -0
  19. data/ext/clipper2/vendor/include/clipper2/clipper.offset.h +125 -0
  20. data/ext/clipper2/vendor/include/clipper2/clipper.rectclip.h +80 -0
  21. data/ext/clipper2/vendor/include/clipper2/clipper.triangulation.h +27 -0
  22. data/ext/clipper2/vendor/include/clipper2/clipper.version.h +6 -0
  23. data/ext/clipper2/vendor/src/clipper.engine.cpp +3152 -0
  24. data/ext/clipper2/vendor/src/clipper.offset.cpp +661 -0
  25. data/ext/clipper2/vendor/src/clipper.rectclip.cpp +1027 -0
  26. data/ext/clipper2/vendor/src/clipper.triangulation.cpp +1221 -0
  27. data/lib/clipper2/api.rb +45 -0
  28. data/lib/clipper2/c_paths64.rb +80 -0
  29. data/lib/clipper2/earcut/engine.rb +191 -0
  30. data/lib/clipper2/earcut/geometry.rb +100 -0
  31. data/lib/clipper2/earcut/node.rb +18 -0
  32. data/lib/clipper2/earcut/ring.rb +94 -0
  33. data/lib/clipper2/earcut.rb +18 -0
  34. data/lib/clipper2/errors.rb +19 -0
  35. data/lib/clipper2/generated.rb +62 -0
  36. data/lib/clipper2/native.rb +38 -0
  37. data/lib/clipper2/native_memory.rb +64 -0
  38. data/lib/clipper2/operations.rb +206 -0
  39. data/lib/clipper2/path.rb +171 -0
  40. data/lib/clipper2/path_simplifier.rb +61 -0
  41. data/lib/clipper2/paths.rb +130 -0
  42. data/lib/clipper2/quantizer.rb +48 -0
  43. data/lib/clipper2/triangulation.rb +103 -0
  44. data/lib/clipper2/version.rb +5 -0
  45. data/lib/clipper2.rb +34 -0
  46. data/licenses/CLIPPER2-BSL-1.0.txt +23 -0
  47. data/licenses/EARCUT-ISC.txt +15 -0
  48. metadata +113 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e8e374bfe4ee5209b63a97203c8c675d132609b35b008b2ec829241cf7f94063
4
+ data.tar.gz: 7634829ff829a134af6885b75490629c3b8d1ea64301cefcce1a2055560d45fb
5
+ SHA512:
6
+ metadata.gz: 1864bb0788c3417a00e52e4cb4b7fd7d7b11b3aebf708760ec09852cc2796e0b9328fd983ef7b42be8314f7feb1e85ef67bee41176e38c74d7784255ece21a15
7
+ data.tar.gz: 3dd05a3210852de65e99bdf0f64da9e0e6f38dd7d1cbd07b1f47aa0f16ebd6d220eaf929870a547d4e3e6365cecb5f9ee0406f97b8ad602e4562d803b68340da
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Clipper2
2
+
3
+ Clipper2 brings robust 2D polygon clipping and offsetting to Ruby. It wraps Angus Johnson's
4
+ [Clipper2](https://github.com/AngusJohnson/Clipper2) C export API with FFI and keeps all native
5
+ geometry on a quantized signed-integer grid.
6
+
7
+ The gem supports union, intersection, difference, XOR, open paths, polygon and line offsets,
8
+ rectangle clipping, Minkowski sums, point containment, path simplification, and dependency-free
9
+ Earcut triangulation into GPU-ready buffers.
10
+
11
+ ## Installation
12
+
13
+ Add the gem to your bundle:
14
+
15
+ ```bash
16
+ bundle add clipper2
17
+ ```
18
+
19
+ Or install it directly:
20
+
21
+ ```bash
22
+ gem install clipper2
23
+ ```
24
+
25
+ Platform gems contain a precompiled shared library. When a platform gem is unavailable, the
26
+ source gem builds the pinned Clipper2 C++17 sources with Ruby's standard extension toolchain and
27
+ therefore requires a C++ compiler and `make`. CMake is used by maintainers to build platform gems.
28
+
29
+ ## Coordinate model
30
+
31
+ Ruby callers use ordinary numeric coordinates. `Path` quantizes them to signed 64-bit integers
32
+ using a scale and restores floats when enumerated:
33
+
34
+ ```ruby
35
+ require "clipper2"
36
+
37
+ Clipper2.default_scale = 1_000 # 0.001 coordinate-unit precision
38
+
39
+ path = Clipper2::Path[[0, 0], [10, 0], [10, 10], [0, 10]]
40
+ path.to_a # => [[0.0, 0.0], [10.0, 0.0], [10.0, 10.0], [0.0, 10.0]]
41
+ path.area # => 100.0 (signed; positive is counter-clockwise)
42
+ path.orientation # => :ccw
43
+ path.bounds # => [0.0, 0.0, 10.0, 10.0]
44
+ ```
45
+
46
+ Every `Paths` collection owns one scale. Operations between different scales raise
47
+ `Clipper2::ScaleError`; coordinates that cannot be represented safely raise
48
+ `Clipper2::RangeError`. Choose a scale that gives the precision you need without making
49
+ `coordinate * scale` unnecessarily large.
50
+
51
+ ## Boolean operations
52
+
53
+ All convenience methods accept a `Path`, `Paths`, one raw point array, or an array of raw paths,
54
+ and return `Clipper2::Paths`:
55
+
56
+ ```ruby
57
+ a = Clipper2::Path[[0, 0], [10, 0], [10, 10], [0, 10]]
58
+ b = Clipper2::Path[[5, 0], [15, 0], [15, 10], [5, 10]]
59
+
60
+ Clipper2.union(a, b)
61
+ Clipper2.intersect(a, b, fill_rule: :non_zero)
62
+ Clipper2.difference(a, b)
63
+ Clipper2.xor(a, b)
64
+ ```
65
+
66
+ Fill rules are `:even_odd`, `:non_zero`, `:positive`, and `:negative`. Clipper2 intentionally
67
+ handles self-intersecting input according to the selected fill rule.
68
+
69
+ For open subject paths, use the general API. It returns closed and open solutions separately:
70
+
71
+ ```ruby
72
+ line = Clipper2::Path[[-5, 5], [15, 5]]
73
+ closed, open = Clipper2.boolean(:intersection, [], a, subject_open: line)
74
+ ```
75
+
76
+ ## Offsets and clipping
77
+
78
+ ```ruby
79
+ grown = Clipper2.inflate(a, 2.5, join: :round, end_type: :polygon)
80
+ shrunk = Clipper2.inflate(a, -1.0)
81
+
82
+ open_line = Clipper2::Path[[0, 0], [10, 0]]
83
+ stroke = Clipper2.inflate(open_line, 3.0, join: :round, end_type: :round)
84
+
85
+ inside = Clipper2.rect_clip(grown, [0, 0, 12, 12])
86
+ line_segments = Clipper2.rect_clip_lines(open_line, [2, -1, 8, 1])
87
+ ```
88
+
89
+ Join types are `:square`, `:bevel`, `:round`, and `:miter`. End types are `:polygon`, `:joined`,
90
+ `:butt`, `:square`, and `:round`. `arc_tolerance` defaults to `0.25` public coordinate units and
91
+ is scaled automatically.
92
+
93
+ Minkowski sums and differences use the same integer path representation:
94
+
95
+ ```ruby
96
+ pattern = Clipper2::Path[[0, 0], [1, 0], [1, 1], [0, 1]]
97
+ Clipper2.minkowski_sum(pattern, a)
98
+ Clipper2.minkowski_difference(pattern, a)
99
+ ```
100
+
101
+ ## Path utilities
102
+
103
+ ```ruby
104
+ path.contains?([5, 5]) # boundary points are included
105
+ path.reverse
106
+ path.simplify(0.05)
107
+ path.to_packed # little-endian float32 x/y pairs
108
+ ```
109
+
110
+ `Paths#simplify` applies the same tolerance to each member.
111
+
112
+ ## Packed triangulation
113
+
114
+ `Clipper2.triangulate` uses the bundled pure Ruby Earcut implementation. Counter-clockwise rings
115
+ are outer contours and clockwise rings contained by an outer contour are holes:
116
+
117
+ ```ruby
118
+ outer = Clipper2::Path[[0, 0], [10, 0], [10, 10], [0, 10]]
119
+ hole = Clipper2::Path[[2, 2], [2, 8], [8, 8], [8, 2]] # clockwise
120
+
121
+ mesh = Clipper2.triangulate(Clipper2::Paths[outer, hole])
122
+ mesh.indices # little-endian packed u32 triangle indices
123
+ mesh.vertices # little-endian packed float32 x/y vertices
124
+ mesh.index_count
125
+ mesh.vertex_count
126
+
127
+ indices, vertices = mesh # array destructuring is also supported
128
+ ```
129
+
130
+ Every emitted triangle is counter-clockwise in a y-up coordinate system. The two packed strings
131
+ can be uploaded directly by renderers that accept raw buffers. See
132
+ [`examples/rugl_mesh.rb`](examples/rugl_mesh.rb) and
133
+ [`examples/larb_transform.rb`](examples/larb_transform.rb).
134
+
135
+ ## Empty input and errors
136
+
137
+ Empty inputs return empty `Paths` or an empty `Triangulation`. Invalid options and rectangles
138
+ raise `ArgumentError`; scale, range, codec, triangulation, and native failures use subclasses of
139
+ `Clipper2::Error`.
140
+
141
+ Native arrays are always copied once into Ruby and released through Clipper2's matching
142
+ `DisposeArray64` export.
143
+
144
+ ## Development
145
+
146
+ Ruby 3.2 or newer, CMake, and a C++17 compiler are required.
147
+
148
+ ```bash
149
+ bundle install
150
+ bundle exec rake # generated-binding check, native build, and specs
151
+ bundle exec rake native:build # native library only
152
+ bundle exec rake native:gem # platform gem in pkg/
153
+ bundle exec rake build # source gem in pkg/
154
+ ```
155
+
156
+ `ext/clipper2/generate_bindings.rb` derives enum values and export names from the vendored headers.
157
+ Run `bundle exec rake bindings:generate` after updating Clipper2 and commit the generated Ruby file.
158
+
159
+ The SVG boolean demo is available at [`examples/svg_boolean.rb`](examples/svg_boolean.rb).
160
+
161
+ ## Licenses
162
+
163
+ The Ruby wrapper is MIT licensed. Vendored Clipper2 2.0.1 is distributed under the Boost Software
164
+ License 1.0, and the Ruby Earcut port carries Mapbox's ISC license. The corresponding notices are
165
+ included in `LICENSE.txt`, `licenses/CLIPPER2-BSL-1.0.txt`, and `licenses/EARCUT-ISC.txt`.
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "clipper2"
4
+ require "larb"
5
+
6
+ vectors = [
7
+ Larb::Vec2.new(0, 0),
8
+ Larb::Vec2.new(10, 0),
9
+ Larb::Vec2.new(10, 10),
10
+ Larb::Vec2.new(0, 10)
11
+ ]
12
+
13
+ path = Clipper2::Path.new(vectors.map(&:to_a))
14
+ outline = Clipper2.inflate(path, 1.5, join: :round)
15
+ larb_paths = outline.map { |ring| ring.map { |x, y| Larb::Vec2.new(x, y) } }
16
+
17
+ puts "#{larb_paths.sum(&:length)} transformed outline vertices"
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "clipper2"
4
+ require "rugl"
5
+
6
+ polygon = Clipper2::Path[[-0.8, -0.7], [0.8, -0.7], [0.35, 0.0], [0.8, 0.7], [-0.8, 0.7]]
7
+ mesh = Clipper2.triangulate(polygon)
8
+
9
+ rugl = Rugl.create(width: 800, height: 600, title: "Clipper2 packed mesh")
10
+ positions = rugl.buffer(data: mesh.vertices, type: :float)
11
+ elements = rugl.elements(data: mesh.indices.unpack("L<*"), type: :uint32, primitive: :triangles)
12
+
13
+ draw = rugl.command(
14
+ vert: <<~GLSL,
15
+ #version 410 core
16
+ layout(location = 0) in vec2 position;
17
+ void main() { gl_Position = vec4(position, 0.0, 1.0); }
18
+ GLSL
19
+ frag: <<~GLSL,
20
+ #version 410 core
21
+ out vec4 color;
22
+ void main() { color = vec4(0.15, 0.7, 0.55, 1.0); }
23
+ GLSL
24
+ attributes: { position: positions },
25
+ elements: elements
26
+ )
27
+
28
+ rugl.frame do
29
+ rugl.clear(color: [0.03, 0.04, 0.08, 1.0])
30
+ draw.call
31
+ end
32
+
33
+ rugl.destroy
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "clipper2"
4
+
5
+ subject = Clipper2::Path[[20, 20], [180, 20], [180, 140], [20, 140]]
6
+ clip = Clipper2::Path[[80, 0], [220, 80], [80, 160]]
7
+ result = Clipper2.difference(subject, clip)
8
+
9
+ polygon = lambda do |path, attributes|
10
+ points = path.map { |x, y| "#{x},#{y}" }.join(" ")
11
+ %(<polygon points="#{points}" #{attributes} />)
12
+ end
13
+
14
+ layers = []
15
+ layers << polygon.call(subject, 'fill="#4f46e5" fill-opacity="0.18" stroke="#4f46e5"')
16
+ layers << polygon.call(clip, 'fill="#e11d48" fill-opacity="0.18" stroke="#e11d48"')
17
+ result.each { |path| layers << polygon.call(path, 'fill="#059669" fill-opacity="0.55" stroke="#047857"') }
18
+
19
+ svg = <<~SVG
20
+ <svg xmlns="http://www.w3.org/2000/svg" width="240" height="180" viewBox="0 0 240 180">
21
+ <rect width="100%" height="100%" fill="white" />
22
+ #{layers.join("\n ")}
23
+ </svg>
24
+ SVG
25
+
26
+ output = ARGV.fetch(0, "clipper2-boolean.svg")
27
+ File.write(output, svg)
28
+ puts "wrote #{output}"
@@ -0,0 +1,27 @@
1
+ cmake_minimum_required(VERSION 3.15)
2
+ project(clipper2_native LANGUAGES CXX)
3
+
4
+ set(VENDOR_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor")
5
+ set(CLIPPER2_SOURCES
6
+ "${VENDOR_DIR}/src/clipper.engine.cpp"
7
+ "${VENDOR_DIR}/src/clipper.offset.cpp"
8
+ "${VENDOR_DIR}/src/clipper.rectclip.cpp"
9
+ "${VENDOR_DIR}/src/clipper.triangulation.cpp"
10
+ )
11
+
12
+ add_library(clipper2_native MODULE clipper2_native.cpp ${CLIPPER2_SOURCES})
13
+ target_compile_features(clipper2_native PRIVATE cxx_std_17)
14
+ target_include_directories(clipper2_native PRIVATE "${VENDOR_DIR}/include")
15
+ set_target_properties(clipper2_native PROPERTIES PREFIX "")
16
+
17
+ set(RUBY_EXTENSION_SUFFIX "" CACHE STRING "Ruby-loadable library suffix including the leading dot")
18
+ if(RUBY_EXTENSION_SUFFIX)
19
+ set_target_properties(clipper2_native PROPERTIES SUFFIX "${RUBY_EXTENSION_SUFFIX}")
20
+ endif()
21
+
22
+ option(CLIPPER2_BUILD_MEMORY_CHECK "Build the native allocation disposal check" OFF)
23
+ if(CLIPPER2_BUILD_MEMORY_CHECK)
24
+ add_executable(clipper2_memory_check memory_check.cpp ${CLIPPER2_SOURCES})
25
+ target_compile_features(clipper2_memory_check PRIVATE cxx_std_17)
26
+ target_include_directories(clipper2_memory_check PRIVATE "${VENDOR_DIR}/include")
27
+ endif()
@@ -0,0 +1,2 @@
1
+ #include <clipper2/clipper.h>
2
+ #include <clipper2/clipper.export.h>
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ vendor = File.expand_path("vendor", __dir__)
6
+ headers = File.join(vendor, "include")
7
+ sources = File.join(vendor, "src")
8
+
9
+ abort "Clipper2 vendored headers are missing" unless File.file?(File.join(headers, "clipper2", "clipper.export.h"))
10
+
11
+ $CPPFLAGS = "-I#{headers.shellescape} #{$CPPFLAGS}"
12
+ $VPATH << sources
13
+ $srcs = %w[
14
+ clipper2_native.cpp
15
+ clipper.engine.cpp
16
+ clipper.offset.cpp
17
+ clipper.rectclip.cpp
18
+ clipper.triangulation.cpp
19
+ ]
20
+
21
+ if /mswin|msvc/ =~ RUBY_PLATFORM
22
+ $CXXFLAGS = "/std:c++17 /EHsc /utf-8 #{$CXXFLAGS}"
23
+ else
24
+ $CXXFLAGS = "-std=c++17 #{$CXXFLAGS}"
25
+ end
26
+
27
+ create_makefile("clipper2/clipper2_native")
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ ROOT = File.expand_path("../..", __dir__)
4
+ HEADERS = File.join(__dir__, "vendor", "include", "clipper2")
5
+ OUTPUT = File.join(ROOT, "lib", "clipper2", "generated.rb")
6
+
7
+ ENUMS = {
8
+ "CLIP_TYPES" => ["clipper.engine.h", "ClipType"],
9
+ "FILL_RULES" => ["clipper.core.h", "FillRule"],
10
+ "JOIN_TYPES" => ["clipper.offset.h", "JoinType"],
11
+ "END_TYPES" => ["clipper.offset.h", "EndType"]
12
+ }.freeze
13
+
14
+ def snake_case(name)
15
+ name.gsub(/([a-z\d])([A-Z])/, "\\1_\\2").downcase
16
+ end
17
+
18
+ def parse_enum(file_name, enum_name)
19
+ source = File.read(File.join(HEADERS, file_name))
20
+ body = source.match(/enum\s+class\s+#{Regexp.escape(enum_name)}(?:\s*:\s*[^\{]+)?\s*\{([^}]+)\}/m)&.[](1)
21
+ abort "Unable to find #{enum_name} in #{file_name}" unless body
22
+
23
+ next_value = 0
24
+ body.split(",").to_h do |entry|
25
+ name, explicit_value = entry.gsub(%r{//.*}, "").strip.split("=", 2).map(&:strip)
26
+ next_value = Integer(explicit_value, 0) if explicit_value
27
+ pair = [snake_case(name).to_sym, next_value]
28
+ next_value += 1
29
+ pair
30
+ end
31
+ end
32
+
33
+ def parse_exports
34
+ source = File.read(File.join(HEADERS, "clipper.export.h"))
35
+ source.scan(/EXTERN_DLL_EXPORT\s+[^;\{]+?\b(\w+)\s*\(/m).flatten.uniq.sort - ["__declspec"]
36
+ end
37
+
38
+ def parse_version
39
+ source = File.read(File.join(HEADERS, "clipper.version.h"))
40
+ source.match(/CLIPPER2_VERSION\s*=\s*"([^"]+)"/)&.[](1) || abort("Unable to find Clipper2 version")
41
+ end
42
+
43
+ def render
44
+ constants = ENUMS.map do |constant, (file_name, enum_name)|
45
+ values = parse_enum(file_name, enum_name).map { |name, value| " #{name.inspect} => #{value}" }.join(",\n")
46
+ " #{constant} = {\n#{values}\n }.freeze"
47
+ end.join("\n\n")
48
+ exports = parse_exports.map { |name| " :#{name}" }.join(",\n")
49
+
50
+ <<~RUBY
51
+ # frozen_string_literal: true
52
+
53
+ # Generated by ext/clipper2/generate_bindings.rb. Do not edit by hand.
54
+ module Clipper2
55
+ module Generated
56
+ UPSTREAM_VERSION = #{parse_version.inspect}
57
+
58
+ #{constants}
59
+
60
+ NATIVE_EXPORTS = [
61
+ #{exports}
62
+ ].freeze
63
+ end
64
+ end
65
+ RUBY
66
+ end
67
+
68
+ generated = render
69
+ if ARGV.include?("--check")
70
+ abort "#{OUTPUT} is out of date; run #{__FILE__}" unless File.file?(OUTPUT) && File.read(OUTPUT) == generated
71
+ else
72
+ File.write(OUTPUT, generated)
73
+ end
@@ -0,0 +1,48 @@
1
+ #include "clipper2/clipper.h"
2
+ #include "clipper2/clipper.export.h"
3
+
4
+ #include <cstdint>
5
+
6
+ namespace {
7
+
8
+ constexpr std::uint8_t kUnion = 2;
9
+ constexpr std::uint8_t kNonZero = 1;
10
+ constexpr std::uint8_t kRound = 2;
11
+ constexpr std::uint8_t kPolygon = 0;
12
+
13
+ std::int64_t subject[] = {
14
+ 12, 1, 4, 0,
15
+ 0, 0, 100, 0, 100, 100, 0, 100,
16
+ };
17
+
18
+ std::int64_t clip[] = {
19
+ 12, 1, 4, 0,
20
+ 50, -20, 120, -20, 120, 80, 50, 80,
21
+ };
22
+
23
+ } // namespace
24
+
25
+ int main() {
26
+ using namespace Clipper2Lib;
27
+
28
+ constexpr int kIterations = 500;
29
+ const CRect64 rectangle{0, 0, 100, 100};
30
+
31
+ for (int iteration = 0; iteration < kIterations; ++iteration) {
32
+ CPaths64 closed = nullptr;
33
+ CPaths64 open = nullptr;
34
+ if (BooleanOp64(kUnion, kNonZero, subject, nullptr, clip, closed, open) != 0) {
35
+ return 1;
36
+ }
37
+
38
+ CPaths64 inflated = InflatePaths64(closed, 3.0, kRound, kPolygon);
39
+ CPaths64 clipped = RectClip64(rectangle, inflated);
40
+
41
+ DisposeArray64(clipped);
42
+ DisposeArray64(inflated);
43
+ DisposeArray64(open);
44
+ DisposeArray64(closed);
45
+ }
46
+
47
+ return 0;
48
+ }
@@ -0,0 +1,23 @@
1
+ Boost Software License - Version 1.0 - August 17th, 2003
2
+
3
+ Permission is hereby granted, free of charge, to any person or organization
4
+ obtaining a copy of the software and accompanying documentation covered by
5
+ this license (the "Software") to use, reproduce, display, distribute,
6
+ execute, and transmit the Software, and to prepare derivative works of the
7
+ Software, and to permit third-parties to whom the Software is furnished to
8
+ do so, all subject to the following:
9
+
10
+ The copyright notices in the Software and this entire statement, including
11
+ the above license grant, this restriction and the following disclaimer,
12
+ must be included in all copies of the Software, in whole or in part, and
13
+ all derivative works of the Software, unless such copies or derivative
14
+ works are solely in the form of machine-executable object code generated by
15
+ a source language processor.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ # Vendored Clipper2
2
+
3
+ - Upstream: https://github.com/AngusJohnson/Clipper2
4
+ - Version: 2.0.1
5
+ - Commit: `f9c5eb6e14a59f6f5d65fbfb3564519a561cf4fd`
6
+ - License: Boost Software License 1.0 (see `LICENSE`)
7
+
8
+ Only `CPP/Clipper2Lib/include/clipper2` and `CPP/Clipper2Lib/src` are vendored. The exported C API
9
+ is compiled once by `clipper2_native.cpp`. That translation unit includes `clipper.h` before
10
+ `clipper.export.h` because the upstream export header uses Minkowski declarations without including
11
+ them itself.