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
@@ -0,0 +1,851 @@
1
+ /*******************************************************************************
2
+ * Author : Angus Johnson *
3
+ * Date : 24 January 2025 *
4
+ * Website : https://www.angusj.com *
5
+ * Copyright : Angus Johnson 2010-2025 *
6
+ * Purpose : This module exports the Clipper2 Library (ie DLL/so) *
7
+ * License : https://www.boost.org/LICENSE_1_0.txt *
8
+ *******************************************************************************/
9
+
10
+
11
+ /*
12
+ Boolean clipping:
13
+ cliptype: NoClip=0, Intersection=1, Union=2, Difference=3, Xor=4
14
+ fillrule: EvenOdd=0, NonZero=1, Positive=2, Negative=3
15
+
16
+ Polygon offsetting (inflate/deflate):
17
+ jointype: Square=0, Bevel=1, Round=2, Miter=3
18
+ endtype: Polygon=0, Joined=1, Butt=2, Square=3, Round=4
19
+
20
+ The path structures used extensively in other parts of this library are all
21
+ based on std::vector classes. Since C++ classes can't be accessed by other
22
+ languages, these paths are exported here as very simple array structures
23
+ (either of int64_t or double) that can be parsed by just about any
24
+ programming language.
25
+
26
+ These 2D paths are defined by series of x and y coordinates together with an
27
+ optional user-defined 'z' value (see Z-values below). Hence, a vertex refers
28
+ to a single x and y coordinate (+/- a user-defined value). Data structures
29
+ have names with suffixes that indicate the array type (either int64_t or
30
+ double). For example, the data structure CPath64 contains an array of int64_t
31
+ values, whereas the data structure CPathD contains an array of double.
32
+ Where documentation omits the type suffix (eg CPath), it is referring to an
33
+ array whose data type could be either int64_t or double.
34
+
35
+ For conciseness, the following letters are used in the diagrams below:
36
+ N: Number of vertices in a given path
37
+ C: Count (ie number) of paths (or PolyPaths) in the structure
38
+ A: Number of elements in an array
39
+
40
+
41
+ CPath64 and CPathD:
42
+ These are arrays of either int64_t or double values. Apart from
43
+ the first two elements, these arrays are a series of vertices
44
+ that together define a path. The very first element contains the
45
+ number of vertices (N) in the path, while second element should
46
+ contain a 0 value.
47
+ _______________________________________________________________
48
+ | counters | vertex1 | vertex2 | ... | vertexN |
49
+ | N, 0 | x1, y1, (z1) | x2, y2, (z2) | ... | xN, yN, (zN) |
50
+ ---------------------------------------------------------------
51
+
52
+
53
+ CPaths64 and CPathsD:
54
+ These are also arrays of either int64_t or double values that
55
+ contain any number of consecutive CPath structures. However,
56
+ preceding the first path is a pair of values. The first value
57
+ contains the length of the entire array structure (A), and the
58
+ second contains the number (ie count) of contained paths (C).
59
+ Memory allocation for CPaths64 = A * sizeof(int64_t)
60
+ Memory allocation for CPathsD = A * sizeof(double)
61
+ __________________________________________
62
+ | counters | path1 | path2 | ... | pathC |
63
+ | A, C | | | ... | |
64
+ ------------------------------------------
65
+
66
+
67
+ CPolytree64 and CPolytreeD:
68
+ The entire polytree structure is an array of int64_t or double. The
69
+ first element in the array indicates the array's total length (A).
70
+ The second element indicates the number (C) of CPolyPath structures
71
+ that are the TOP LEVEL CPolyPath in the polytree, and these top
72
+ level CPolyPath immediately follow these first two array elements.
73
+ These top level CPolyPath structures may, in turn, contain nested
74
+ CPolyPath children, and these collectively make a tree structure.
75
+ _________________________________________________________
76
+ | counters | CPolyPath1 | CPolyPath2 | ... | CPolyPathC |
77
+ | A, C | | | ... | |
78
+ ---------------------------------------------------------
79
+
80
+
81
+ CPolyPath64 and CPolyPathD:
82
+ These array structures consist of a pair of counter values followed by a
83
+ series of polygon vertices and a series of nested CPolyPath children.
84
+ The first counter values indicates the number of vertices in the
85
+ polygon (N), and the second counter indicates the CPolyPath child count (C).
86
+ _____________________________________________________________________________
87
+ |cntrs |vertex1 |vertex2 |...|vertexN |child1|child2|...|childC|
88
+ |N, C |x1, y1, (z1)| x2, y2, (z2)|...|xN, yN, (zN)| | |...| |
89
+ -----------------------------------------------------------------------------
90
+
91
+
92
+ DisposeArray64 & DisposeArrayD:
93
+ All array structures are allocated in heap memory which will eventually
94
+ need to be released. However, since applications linking to these DLL
95
+ functions may use different memory managers, the only safe way to release
96
+ this memory is to use the exported DisposeArray functions.
97
+
98
+
99
+ (Optional) Z-Values:
100
+ Structures will only contain user-defined z-values when the USINGZ
101
+ pre-processor identifier is used. The library does not assign z-values
102
+ because this field is intended for users to assign custom values to vertices.
103
+ Z-values in input paths (subject and clip) will be copied to solution paths.
104
+ New vertices at path intersections will generate a callback event that allows
105
+ users to assign z-values at these new vertices. The user's callback function
106
+ must conform with the DLLZCallback definition and be registered with the
107
+ DLL via SetZCallback. To assist the user in assigning z-values, the library
108
+ passes in the callback function the new intersection point together with
109
+ the four vertices that define the two segments that are intersecting.
110
+
111
+ */
112
+ #ifndef CLIPPER2_EXPORT_H
113
+ #define CLIPPER2_EXPORT_H
114
+
115
+ #include "clipper2/clipper.core.h"
116
+ #include "clipper2/clipper.engine.h"
117
+ #include "clipper2/clipper.offset.h"
118
+ #include "clipper2/clipper.rectclip.h"
119
+ #include "clipper2/clipper.triangulation.h"
120
+ #include <cstdlib>
121
+
122
+ namespace Clipper2Lib {
123
+
124
+ typedef int64_t* CPath64;
125
+ typedef int64_t* CPaths64;
126
+ typedef double* CPathD;
127
+ typedef double* CPathsD;
128
+
129
+ typedef int64_t* CPolyPath64;
130
+ typedef int64_t* CPolyTree64;
131
+ typedef double* CPolyPathD;
132
+ typedef double* CPolyTreeD;
133
+
134
+ template <typename T>
135
+ struct CRect {
136
+ T left;
137
+ T top;
138
+ T right;
139
+ T bottom;
140
+ };
141
+
142
+ typedef CRect<int64_t> CRect64;
143
+ typedef CRect<double> CRectD;
144
+
145
+ template <typename T>
146
+ inline bool CRectIsEmpty(const CRect<T>& rect)
147
+ {
148
+ return (rect.right <= rect.left) || (rect.bottom <= rect.top);
149
+ }
150
+
151
+ template <typename T>
152
+ inline Rect<T> CRectToRect(const CRect<T>& rect)
153
+ {
154
+ Rect<T> result;
155
+ result.left = rect.left;
156
+ result.top = rect.top;
157
+ result.right = rect.right;
158
+ result.bottom = rect.bottom;
159
+ return result;
160
+ }
161
+
162
+ template <typename T1, typename T2>
163
+ inline T1 Reinterpret(T2 value) {
164
+ return *reinterpret_cast<T1*>(&value);
165
+ }
166
+
167
+
168
+ #ifdef _WIN32
169
+ #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
170
+ #else
171
+ #define EXTERN_DLL_EXPORT extern "C"
172
+ #endif
173
+
174
+
175
+ //////////////////////////////////////////////////////
176
+ // EXPORTED FUNCTION DECLARATIONS
177
+ //////////////////////////////////////////////////////
178
+
179
+ EXTERN_DLL_EXPORT const char* Version();
180
+
181
+ EXTERN_DLL_EXPORT void DisposeArray64(int64_t*& p)
182
+ {
183
+ delete[] p;
184
+ }
185
+
186
+ EXTERN_DLL_EXPORT void DisposeArrayD(double*& p)
187
+ {
188
+ delete[] p;
189
+ }
190
+
191
+ EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
192
+ uint8_t fillrule, const CPaths64 subjects,
193
+ const CPaths64 subjects_open, const CPaths64 clips,
194
+ CPaths64& solution, CPaths64& solution_open,
195
+ bool preserve_collinear = true, bool reverse_solution = false);
196
+
197
+ EXTERN_DLL_EXPORT int BooleanOp_PolyTree64(uint8_t cliptype,
198
+ uint8_t fillrule, const CPaths64 subjects,
199
+ const CPaths64 subjects_open, const CPaths64 clips,
200
+ CPolyTree64& sol_tree, CPaths64& solution_open,
201
+ bool preserve_collinear = true, bool reverse_solution = false);
202
+
203
+ EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype,
204
+ uint8_t fillrule, const CPathsD subjects,
205
+ const CPathsD subjects_open, const CPathsD clips,
206
+ CPathsD& solution, CPathsD& solution_open, int precision = 2,
207
+ bool preserve_collinear = true, bool reverse_solution = false);
208
+
209
+ EXTERN_DLL_EXPORT int BooleanOp_PolyTreeD(uint8_t cliptype,
210
+ uint8_t fillrule, const CPathsD subjects,
211
+ const CPathsD subjects_open, const CPathsD clips,
212
+ CPolyTreeD& solution, CPathsD& solution_open, int precision = 2,
213
+ bool preserve_collinear = true, bool reverse_solution = false);
214
+
215
+ EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
216
+ double delta, uint8_t jointype, uint8_t endtype,
217
+ double miter_limit = 2.0, double arc_tolerance = 0.0,
218
+ bool reverse_solution = false);
219
+
220
+ EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
221
+ double delta, uint8_t jointype, uint8_t endtype,
222
+ int precision = 2, double miter_limit = 2.0,
223
+ double arc_tolerance = 0.0, bool reverse_solution = false);
224
+
225
+ EXTERN_DLL_EXPORT CPaths64 InflatePath64(const CPath64 path,
226
+ double delta, uint8_t jointype, uint8_t endtype,
227
+ double miter_limit = 2.0, double arc_tolerance = 0.0,
228
+ bool reverse_solution = false);
229
+
230
+ EXTERN_DLL_EXPORT CPathsD InflatePathD(const CPathD path,
231
+ double delta, uint8_t jointype, uint8_t endtype,
232
+ int precision = 2, double miter_limit = 2.0,
233
+ double arc_tolerance = 0.0, bool reverse_solution = false);
234
+
235
+ // RectClip & RectClipLines:
236
+ EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect,
237
+ const CPaths64 paths);
238
+ EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect,
239
+ const CPathsD paths, int precision = 2);
240
+ EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect,
241
+ const CPaths64 paths);
242
+ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
243
+ const CPathsD paths, int precision = 2);
244
+
245
+ //////////////////////////////////////////////////////
246
+ // INTERNAL FUNCTIONS
247
+ //////////////////////////////////////////////////////
248
+
249
+ #ifdef USINGZ
250
+ ZCallback64 dllCallback64 = nullptr;
251
+ ZCallbackD dllCallbackD = nullptr;
252
+
253
+ constexpr int EXPORT_VERTEX_DIMENSIONALITY = 3;
254
+ #else
255
+ constexpr int EXPORT_VERTEX_DIMENSIONALITY = 2;
256
+ #endif
257
+
258
+ template <typename T>
259
+ static void GetPathCountAndCPathsArrayLen(const Paths<T>& paths,
260
+ size_t& cnt, size_t& array_len)
261
+ {
262
+ array_len = 2;
263
+ cnt = 0;
264
+ for (const Path<T>& path : paths)
265
+ if (path.size())
266
+ {
267
+ array_len += path.size() * EXPORT_VERTEX_DIMENSIONALITY + 2;
268
+ ++cnt;
269
+ }
270
+ }
271
+
272
+ static size_t GetPolyPathArrayLen64(const PolyPath64& pp)
273
+ {
274
+ size_t result = 2; // poly_length + child_count
275
+ result += pp.Polygon().size() * EXPORT_VERTEX_DIMENSIONALITY;
276
+ //plus nested children :)
277
+ for (size_t i = 0; i < pp.Count(); ++i)
278
+ result += GetPolyPathArrayLen64(*pp[i]);
279
+ return result;
280
+ }
281
+
282
+ static size_t GetPolyPathArrayLenD(const PolyPathD& pp)
283
+ {
284
+ size_t result = 2; // poly_length + child_count
285
+ result += pp.Polygon().size() * EXPORT_VERTEX_DIMENSIONALITY;
286
+ //plus nested children :)
287
+ for (size_t i = 0; i < pp.Count(); ++i)
288
+ result += GetPolyPathArrayLenD(*pp[i]);
289
+ return result;
290
+ }
291
+
292
+ static void GetPolytreeCountAndCStorageSize64(const PolyTree64& tree,
293
+ size_t& cnt, size_t& array_len)
294
+ {
295
+ cnt = tree.Count(); // nb: top level count only
296
+ array_len = GetPolyPathArrayLen64(tree);
297
+ }
298
+
299
+ static void GetPolytreeCountAndCStorageSizeD(const PolyTreeD& tree,
300
+ size_t& cnt, size_t& array_len)
301
+ {
302
+ cnt = tree.Count(); // nb: top level count only
303
+ array_len = GetPolyPathArrayLenD(tree);
304
+ }
305
+
306
+ template <typename T>
307
+ static T* CreateCPathsFromPathsT(const Paths<T>& paths)
308
+ {
309
+ size_t cnt = 0, array_len = 0;
310
+ GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
311
+ T* result = new T[array_len], * v = result;
312
+ *v++ = array_len;
313
+ *v++ = cnt;
314
+ for (const Path<T>& path : paths)
315
+ {
316
+ if (!path.size()) continue;
317
+ *v++ = path.size();
318
+ *v++ = 0;
319
+ for (const Point<T>& pt : path)
320
+ {
321
+ *v++ = pt.x;
322
+ *v++ = pt.y;
323
+ #ifdef USINGZ
324
+ *v++ = Reinterpret<T>(pt.z);
325
+ #endif
326
+ }
327
+ }
328
+ return result;
329
+ }
330
+
331
+ CPathsD CreateCPathsDFromPathsD(const PathsD& paths)
332
+ {
333
+ if (!paths.size()) return nullptr;
334
+ size_t cnt, array_len;
335
+ GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
336
+ CPathsD result = new double[array_len], v = result;
337
+ *v++ = (double)array_len;
338
+ *v++ = (double)cnt;
339
+ for (const PathD& path : paths)
340
+ {
341
+ if (!path.size()) continue;
342
+ *v = (double)path.size();
343
+ ++v; *v++ = 0;
344
+ for (const PointD& pt : path)
345
+ {
346
+ *v++ = pt.x;
347
+ *v++ = pt.y;
348
+ #ifdef USINGZ
349
+ * v++ = Reinterpret<double>(pt.z);
350
+ #endif
351
+ }
352
+ }
353
+ return result;
354
+ }
355
+
356
+ CPathsD CreateCPathsDFromPaths64(const Paths64& paths, double scale)
357
+ {
358
+ if (!paths.size()) return nullptr;
359
+ size_t cnt, array_len;
360
+ GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
361
+ CPathsD result = new double[array_len], v = result;
362
+ *v++ = (double)array_len;
363
+ *v++ = (double)cnt;
364
+ for (const Path64& path : paths)
365
+ {
366
+ if (!path.size()) continue;
367
+ *v = (double)path.size();
368
+ ++v; *v++ = 0;
369
+ for (const Point64& pt : path)
370
+ {
371
+ *v++ = pt.x * scale;
372
+ *v++ = pt.y * scale;
373
+ #ifdef USINGZ
374
+ *v++ = Reinterpret<double>(pt.z);
375
+ #endif
376
+ }
377
+ }
378
+ return result;
379
+ }
380
+
381
+ template <typename T>
382
+ static Path<T> ConvertCPathToPathT(T* path)
383
+ {
384
+ Path<T> result;
385
+ if (!path) return result;
386
+ T* v = path;
387
+ size_t cnt = static_cast<size_t>(*v);
388
+ v += 2; // skip 0 value
389
+ result.reserve(cnt);
390
+ for (size_t j = 0; j < cnt; ++j)
391
+ {
392
+ T x = *v++, y = *v++;
393
+ #ifdef USINGZ
394
+ z_type z = Reinterpret<z_type>(*v++);
395
+ result.emplace_back(x, y, z);
396
+ #else
397
+ result.emplace_back(x, y);
398
+ #endif
399
+ }
400
+ return result;
401
+ }
402
+
403
+ template <typename T>
404
+ static Paths<T> ConvertCPathsToPathsT(T* paths)
405
+ {
406
+ Paths<T> result;
407
+ if (!paths) return result;
408
+ T* v = paths; ++v;
409
+ size_t cnt = static_cast<size_t>(*v++);
410
+ result.reserve(cnt);
411
+ for (size_t i = 0; i < cnt; ++i)
412
+ {
413
+ size_t cnt2 = static_cast<size_t>(*v);
414
+ v += 2;
415
+ Path<T> path;
416
+ path.reserve(cnt2);
417
+ for (size_t j = 0; j < cnt2; ++j)
418
+ {
419
+ T x = *v++, y = *v++;
420
+ #ifdef USINGZ
421
+ z_type z = Reinterpret<z_type>(*v++);
422
+ path.emplace_back(x, y, z);
423
+ #else
424
+ path.emplace_back(x, y);
425
+ #endif
426
+ }
427
+ result.emplace_back(std::move(path));
428
+ }
429
+ return result;
430
+ }
431
+
432
+ static Path64 ConvertCPathDToPath64WithScale(const CPathD path, double scale)
433
+ {
434
+ Path64 result;
435
+ if (!path) return result;
436
+ double* v = path;
437
+ size_t cnt = static_cast<size_t>(*v);
438
+ v += 2; // skip 0 value
439
+ result.reserve(cnt);
440
+ for (size_t j = 0; j < cnt; ++j)
441
+ {
442
+ double x = *v++ * scale;
443
+ double y = *v++ * scale;
444
+ #ifdef USINGZ
445
+ z_type z = Reinterpret<z_type>(*v++);
446
+ result.emplace_back(x, y, z);
447
+ #else
448
+ result.emplace_back(x, y);
449
+ #endif
450
+ }
451
+ return result;
452
+ }
453
+
454
+ static Paths64 ConvertCPathsDToPaths64(const CPathsD paths, double scale)
455
+ {
456
+ Paths64 result;
457
+ if (!paths) return result;
458
+ double* v = paths;
459
+ ++v; // skip the first value (0)
460
+ size_t cnt = static_cast<size_t>(*v++);
461
+ result.reserve(cnt);
462
+ for (size_t i = 0; i < cnt; ++i)
463
+ {
464
+ size_t cnt2 = static_cast<size_t>(*v);
465
+ v += 2;
466
+ Path64 path;
467
+ path.reserve(cnt2);
468
+ for (size_t j = 0; j < cnt2; ++j)
469
+ {
470
+ double x = *v++ * scale;
471
+ double y = *v++ * scale;
472
+ #ifdef USINGZ
473
+ z_type z = Reinterpret<z_type>(*v++);
474
+ path.emplace_back(x, y, z);
475
+ #else
476
+ path.emplace_back(x, y);
477
+ #endif
478
+ }
479
+ result.emplace_back(std::move(path));
480
+ }
481
+ return result;
482
+ }
483
+
484
+ static void CreateCPolyPath64(const PolyPath64* pp, int64_t*& v)
485
+ {
486
+ *v++ = static_cast<int64_t>(pp->Polygon().size());
487
+ *v++ = static_cast<int64_t>(pp->Count());
488
+ for (const Point64& pt : pp->Polygon())
489
+ {
490
+ *v++ = pt.x;
491
+ *v++ = pt.y;
492
+ #ifdef USINGZ
493
+ * v++ = Reinterpret<int64_t>(pt.z); // raw memory copy
494
+ #endif
495
+ }
496
+ for (size_t i = 0; i < pp->Count(); ++i)
497
+ CreateCPolyPath64(pp->Child(i), v);
498
+ }
499
+
500
+ static void CreateCPolyPathD(const PolyPathD* pp, double*& v)
501
+ {
502
+ *v++ = static_cast<double>(pp->Polygon().size());
503
+ *v++ = static_cast<double>(pp->Count());
504
+ for (const PointD& pt : pp->Polygon())
505
+ {
506
+ *v++ = pt.x;
507
+ *v++ = pt.y;
508
+ #ifdef USINGZ
509
+ * v++ = Reinterpret<double>(pt.z); // raw memory copy
510
+ #endif
511
+ }
512
+ for (size_t i = 0; i < pp->Count(); ++i)
513
+ CreateCPolyPathD(pp->Child(i), v);
514
+ }
515
+
516
+ static int64_t* CreateCPolyTree64(const PolyTree64& tree)
517
+ {
518
+ size_t cnt, array_len;
519
+ GetPolytreeCountAndCStorageSize64(tree, cnt, array_len);
520
+ if (!cnt) return nullptr;
521
+ // allocate storage
522
+ int64_t* result = new int64_t[array_len];
523
+ int64_t* v = result;
524
+ *v++ = static_cast<int64_t>(array_len);
525
+ *v++ = static_cast<int64_t>(tree.Count());
526
+ for (size_t i = 0; i < tree.Count(); ++i)
527
+ CreateCPolyPath64(tree.Child(i), v);
528
+ return result;
529
+ }
530
+
531
+ static double* CreateCPolyTreeD(const PolyTreeD& tree)
532
+ {
533
+ double scale = std::log10(tree.Scale());
534
+ size_t cnt, array_len;
535
+ GetPolytreeCountAndCStorageSizeD(tree, cnt, array_len);
536
+ if (!cnt) return nullptr;
537
+ // allocate storage
538
+ double* result = new double[array_len];
539
+ double* v = result;
540
+ *v++ = static_cast<double>(array_len);
541
+ *v++ = static_cast<double>(tree.Count());
542
+ for (size_t i = 0; i < tree.Count(); ++i)
543
+ CreateCPolyPathD(tree.Child(i), v);
544
+ return result;
545
+ }
546
+
547
+ //////////////////////////////////////////////////////
548
+ // EXPORTED FUNCTION DEFINITIONS
549
+ //////////////////////////////////////////////////////
550
+
551
+ EXTERN_DLL_EXPORT const char* Version()
552
+ {
553
+ return CLIPPER2_VERSION;
554
+ }
555
+
556
+ EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
557
+ uint8_t fillrule, const CPaths64 subjects,
558
+ const CPaths64 subjects_open, const CPaths64 clips,
559
+ CPaths64& solution, CPaths64& solution_open,
560
+ bool preserve_collinear, bool reverse_solution)
561
+ {
562
+ if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
563
+ if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
564
+
565
+ Paths64 sub, sub_open, clp, sol, sol_open;
566
+ sub = ConvertCPathsToPathsT(subjects);
567
+ sub_open = ConvertCPathsToPathsT(subjects_open);
568
+ clp = ConvertCPathsToPathsT(clips);
569
+
570
+ Clipper64 clipper;
571
+ clipper.PreserveCollinear(preserve_collinear);
572
+ clipper.ReverseSolution(reverse_solution);
573
+ #ifdef USINGZ
574
+ if (dllCallback64)
575
+ clipper.SetZCallback(dllCallback64);
576
+ #endif
577
+ if (sub.size() > 0) clipper.AddSubject(sub);
578
+ if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
579
+ if (clp.size() > 0) clipper.AddClip(clp);
580
+ if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open))
581
+ return -1; // clipping bug - should never happen :)
582
+ solution = CreateCPathsFromPathsT(sol);
583
+ solution_open = CreateCPathsFromPathsT(sol_open);
584
+ return 0; //success !!
585
+ }
586
+
587
+ EXTERN_DLL_EXPORT int BooleanOp_PolyTree64(uint8_t cliptype,
588
+ uint8_t fillrule, const CPaths64 subjects,
589
+ const CPaths64 subjects_open, const CPaths64 clips,
590
+ CPolyTree64& sol_tree, CPaths64& solution_open,
591
+ bool preserve_collinear, bool reverse_solution)
592
+ {
593
+ if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
594
+ if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
595
+ Paths64 sub, sub_open, clp, sol_open;
596
+ sub = ConvertCPathsToPathsT(subjects);
597
+ sub_open = ConvertCPathsToPathsT(subjects_open);
598
+ clp = ConvertCPathsToPathsT(clips);
599
+
600
+ PolyTree64 tree;
601
+ Clipper64 clipper;
602
+ clipper.PreserveCollinear(preserve_collinear);
603
+ clipper.ReverseSolution(reverse_solution);
604
+ #ifdef USINGZ
605
+ if (dllCallback64)
606
+ clipper.SetZCallback(dllCallback64);
607
+ #endif
608
+ if (sub.size() > 0) clipper.AddSubject(sub);
609
+ if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
610
+ if (clp.size() > 0) clipper.AddClip(clp);
611
+ if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), tree, sol_open))
612
+ return -1; // clipping bug - should never happen :)
613
+
614
+ sol_tree = CreateCPolyTree64(tree);
615
+ solution_open = CreateCPathsFromPathsT(sol_open);
616
+ return 0; //success !!
617
+ }
618
+
619
+ EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype,
620
+ uint8_t fillrule, const CPathsD subjects,
621
+ const CPathsD subjects_open, const CPathsD clips,
622
+ CPathsD& solution, CPathsD& solution_open, int precision,
623
+ bool preserve_collinear, bool reverse_solution)
624
+ {
625
+ if (precision < -8 || precision > 8) return -5;
626
+ if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
627
+ if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
628
+ //const double scale = std::pow(10, precision);
629
+
630
+ PathsD sub, sub_open, clp, sol, sol_open;
631
+ sub = ConvertCPathsToPathsT(subjects);
632
+ sub_open = ConvertCPathsToPathsT(subjects_open);
633
+ clp = ConvertCPathsToPathsT(clips);
634
+
635
+ ClipperD clipper(precision);
636
+ clipper.PreserveCollinear(preserve_collinear);
637
+ clipper.ReverseSolution(reverse_solution);
638
+ #ifdef USINGZ
639
+ if (dllCallbackD)
640
+ clipper.SetZCallback(dllCallbackD);
641
+ #endif
642
+ if (sub.size() > 0) clipper.AddSubject(sub);
643
+ if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
644
+ if (clp.size() > 0) clipper.AddClip(clp);
645
+ if (!clipper.Execute(ClipType(cliptype),
646
+ FillRule(fillrule), sol, sol_open)) return -1;
647
+ solution = CreateCPathsDFromPathsD(sol);
648
+ solution_open = CreateCPathsDFromPathsD(sol_open);
649
+ return 0;
650
+ }
651
+
652
+ EXTERN_DLL_EXPORT int BooleanOp_PolyTreeD(uint8_t cliptype,
653
+ uint8_t fillrule, const CPathsD subjects,
654
+ const CPathsD subjects_open, const CPathsD clips,
655
+ CPolyTreeD& solution, CPathsD& solution_open, int precision,
656
+ bool preserve_collinear, bool reverse_solution)
657
+ {
658
+ if (precision < -8 || precision > 8) return -5;
659
+ if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
660
+ if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
661
+ //double scale = std::pow(10, precision);
662
+
663
+ int err = 0;
664
+ PathsD sub, sub_open, clp, sol_open;
665
+ sub = ConvertCPathsToPathsT(subjects);
666
+ sub_open = ConvertCPathsToPathsT(subjects_open);
667
+ clp = ConvertCPathsToPathsT(clips);
668
+
669
+ PolyTreeD tree;
670
+ ClipperD clipper(precision);
671
+ clipper.PreserveCollinear(preserve_collinear);
672
+ clipper.ReverseSolution(reverse_solution);
673
+ #ifdef USINGZ
674
+ if (dllCallbackD)
675
+ clipper.SetZCallback(dllCallbackD);
676
+ #endif
677
+ if (sub.size() > 0) clipper.AddSubject(sub);
678
+ if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
679
+ if (clp.size() > 0) clipper.AddClip(clp);
680
+ if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), tree, sol_open))
681
+ return -1; // clipping bug - should never happen :)
682
+
683
+ solution = CreateCPolyTreeD(tree);
684
+ solution_open = CreateCPathsDFromPathsD(sol_open);
685
+ return 0; //success !!
686
+ }
687
+
688
+ EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
689
+ double delta, uint8_t jointype, uint8_t endtype, double miter_limit,
690
+ double arc_tolerance, bool reverse_solution)
691
+ {
692
+ Paths64 pp;
693
+ pp = ConvertCPathsToPathsT(paths);
694
+ ClipperOffset clip_offset( miter_limit,
695
+ arc_tolerance, reverse_solution);
696
+ clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype));
697
+ Paths64 result;
698
+ clip_offset.Execute(delta, result);
699
+ return CreateCPathsFromPathsT(result);
700
+ }
701
+
702
+ EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
703
+ double delta, uint8_t jointype, uint8_t endtype,
704
+ int precision, double miter_limit,
705
+ double arc_tolerance, bool reverse_solution)
706
+ {
707
+ if (precision < -8 || precision > 8 || !paths) return nullptr;
708
+
709
+ const double scale = std::pow(10, precision);
710
+ ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution);
711
+ Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
712
+ clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype));
713
+ Paths64 result;
714
+ clip_offset.Execute(delta * scale, result);
715
+ return CreateCPathsDFromPaths64(result, 1 / scale);
716
+ }
717
+
718
+
719
+ EXTERN_DLL_EXPORT CPaths64 InflatePath64(const CPath64 path,
720
+ double delta, uint8_t jointype, uint8_t endtype, double miter_limit,
721
+ double arc_tolerance, bool reverse_solution)
722
+ {
723
+ Path64 pp;
724
+ pp = ConvertCPathToPathT(path);
725
+ ClipperOffset clip_offset(miter_limit,
726
+ arc_tolerance, reverse_solution);
727
+ clip_offset.AddPath(pp, JoinType(jointype), EndType(endtype));
728
+ Paths64 result;
729
+ clip_offset.Execute(delta, result);
730
+ return CreateCPathsFromPathsT(result);
731
+ }
732
+
733
+ EXTERN_DLL_EXPORT CPathsD InflatePathD(const CPathD path,
734
+ double delta, uint8_t jointype, uint8_t endtype,
735
+ int precision, double miter_limit,
736
+ double arc_tolerance, bool reverse_solution)
737
+ {
738
+ if (precision < -8 || precision > 8 || !path) return nullptr;
739
+
740
+ const double scale = std::pow(10, precision);
741
+ ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution);
742
+ Path64 pp = ConvertCPathDToPath64WithScale(path, scale);
743
+ clip_offset.AddPath(pp, JoinType(jointype), EndType(endtype));
744
+ Paths64 result;
745
+ clip_offset.Execute(delta * scale, result);
746
+
747
+ return CreateCPathsDFromPaths64(result, 1 / scale);
748
+ }
749
+
750
+ EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, const CPaths64 paths)
751
+ {
752
+ if (CRectIsEmpty(rect) || !paths) return nullptr;
753
+ Rect64 r64 = CRectToRect(rect);
754
+ class RectClip64 rc(r64);
755
+ Paths64 pp = ConvertCPathsToPathsT(paths);
756
+ Paths64 result = rc.Execute(pp);
757
+ return CreateCPathsFromPathsT(result);
758
+ }
759
+
760
+ EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect, const CPathsD paths, int precision)
761
+ {
762
+ if (CRectIsEmpty(rect) || !paths) return nullptr;
763
+ if (precision < -8 || precision > 8) return nullptr;
764
+ const double scale = std::pow(10, precision);
765
+
766
+ RectD r = CRectToRect(rect);
767
+ Rect64 rec = ScaleRect<int64_t, double>(r, scale);
768
+ Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
769
+ class RectClip64 rc(rec);
770
+ Paths64 result = rc.Execute(pp);
771
+
772
+ return CreateCPathsDFromPaths64(result, 1 / scale);
773
+ }
774
+
775
+ EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect,
776
+ const CPaths64 paths)
777
+ {
778
+ if (CRectIsEmpty(rect) || !paths) return nullptr;
779
+ Rect64 r = CRectToRect(rect);
780
+ class RectClipLines64 rcl (r);
781
+ Paths64 pp = ConvertCPathsToPathsT(paths);
782
+ Paths64 result = rcl.Execute(pp);
783
+ return CreateCPathsFromPathsT(result);
784
+ }
785
+
786
+ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
787
+ const CPathsD paths, int precision)
788
+ {
789
+ if (CRectIsEmpty(rect) || !paths) return nullptr;
790
+ if (precision < -8 || precision > 8) return nullptr;
791
+
792
+ const double scale = std::pow(10, precision);
793
+ Rect64 r = ScaleRect<int64_t, double>(CRectToRect(rect), scale);
794
+ class RectClipLines64 rcl(r);
795
+ Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
796
+ Paths64 result = rcl.Execute(pp);
797
+ return CreateCPathsDFromPaths64(result, 1 / scale);
798
+ }
799
+
800
+ EXTERN_DLL_EXPORT CPaths64 MinkowskiSum64(const CPath64& cpattern, const CPath64& cpath, bool is_closed)
801
+ {
802
+ Path64 path = ConvertCPathToPathT(cpath);
803
+ Path64 pattern = ConvertCPathToPathT(cpattern);
804
+ Paths64 solution = MinkowskiSum(pattern, path, is_closed);
805
+ return CreateCPathsFromPathsT(solution);
806
+ }
807
+
808
+ EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath64& cpath, bool is_closed)
809
+ {
810
+ Path64 path = ConvertCPathToPathT(cpath);
811
+ Path64 pattern = ConvertCPathToPathT(cpattern);
812
+ Paths64 solution = MinkowskiDiff(pattern, path, is_closed);
813
+ return CreateCPathsFromPathsT(solution);
814
+ }
815
+
816
+ EXTERN_DLL_EXPORT CPaths64 Triangulate64(const CPaths64 paths, bool use_delaunay)
817
+ {
818
+ Paths64 pp = ConvertCPathsToPathsT(paths);
819
+ Paths64 sol;
820
+ if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
821
+ return CreateCPathsFromPathsT(sol);
822
+ }
823
+
824
+ EXTERN_DLL_EXPORT CPathsD TriangulateD(const CPathsD paths, int decimal_precison, bool use_delaunay)
825
+ {
826
+ if (decimal_precison < -8 || decimal_precison > 8) return nullptr;
827
+ const double scale = std::pow(10, decimal_precison);
828
+ Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
829
+ Paths64 sol;
830
+ if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
831
+ return CreateCPathsDFromPaths64(sol, 1 / scale);
832
+ }
833
+
834
+ #ifdef USINGZ
835
+ typedef void (*DLLZCallback64)(const Point64& e1bot, const Point64& e1top, const Point64& e2bot, const Point64& e2top, Point64& pt);
836
+ typedef void (*DLLZCallbackD)(const PointD& e1bot, const PointD& e1top, const PointD& e2bot, const PointD& e2top, PointD& pt);
837
+
838
+ EXTERN_DLL_EXPORT void SetZCallback64(DLLZCallback64 callback)
839
+ {
840
+ dllCallback64 = callback;
841
+ }
842
+
843
+ EXTERN_DLL_EXPORT void SetZCallbackD(DLLZCallbackD callback)
844
+ {
845
+ dllCallbackD = callback;
846
+ }
847
+
848
+ #endif
849
+
850
+ }
851
+ #endif // CLIPPER2_EXPORT_H