clipper2-ts 1.5.4-3.9a869ba
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.
- package/LICENSE +24 -0
- package/README.md +67 -0
- package/dist/Clipper.d.ts +114 -0
- package/dist/Clipper.d.ts.map +1 -0
- package/dist/Clipper.js +1134 -0
- package/dist/Clipper.js.map +1 -0
- package/dist/Core.d.ts +150 -0
- package/dist/Core.d.ts.map +1 -0
- package/dist/Core.js +645 -0
- package/dist/Core.js.map +1 -0
- package/dist/Engine.d.ts +337 -0
- package/dist/Engine.d.ts.map +1 -0
- package/dist/Engine.js +2972 -0
- package/dist/Engine.js.map +1 -0
- package/dist/Minkowski.d.ts +16 -0
- package/dist/Minkowski.d.ts.map +1 -0
- package/dist/Minkowski.js +131 -0
- package/dist/Minkowski.js.map +1 -0
- package/dist/Offset.d.ts +85 -0
- package/dist/Offset.d.ts.map +1 -0
- package/dist/Offset.js +649 -0
- package/dist/Offset.js.map +1 -0
- package/dist/RectClip.d.ts +80 -0
- package/dist/RectClip.d.ts.map +1 -0
- package/dist/RectClip.js +1009 -0
- package/dist/RectClip.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
- package/src/Clipper.ts +1106 -0
- package/src/Core.ts +683 -0
- package/src/Engine.ts +3116 -0
- package/src/Minkowski.ts +153 -0
- package/src/Offset.ts +711 -0
- package/src/RectClip.ts +1028 -0
- package/src/index.ts +146 -0
package/dist/Clipper.js
ADDED
|
@@ -0,0 +1,1134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*******************************************************************************
|
|
3
|
+
* Author : Angus Johnson *
|
|
4
|
+
* Date : 5 March 2025 *
|
|
5
|
+
* Website : https://www.angusj.com *
|
|
6
|
+
* Copyright : Angus Johnson 2010-2025 *
|
|
7
|
+
* Purpose : This module contains simple functions that will likely cover *
|
|
8
|
+
* most polygon boolean and offsetting needs, while also avoiding *
|
|
9
|
+
* the inherent complexities of the other modules. *
|
|
10
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
11
|
+
*******************************************************************************/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.Clipper = void 0;
|
|
14
|
+
const Core_1 = require("./Core");
|
|
15
|
+
const Engine_1 = require("./Engine");
|
|
16
|
+
const Offset_1 = require("./Offset");
|
|
17
|
+
const RectClip_1 = require("./RectClip");
|
|
18
|
+
const Minkowski_1 = require("./Minkowski");
|
|
19
|
+
var Clipper;
|
|
20
|
+
(function (Clipper) {
|
|
21
|
+
// Constants
|
|
22
|
+
Clipper.invalidRect64 = Core_1.InvalidRect64;
|
|
23
|
+
Clipper.invalidRectD = Core_1.InvalidRectD;
|
|
24
|
+
// Boolean operations
|
|
25
|
+
function intersect(subject, clip, fillRule) {
|
|
26
|
+
return booleanOp(Core_1.ClipType.Intersection, subject, clip, fillRule);
|
|
27
|
+
}
|
|
28
|
+
Clipper.intersect = intersect;
|
|
29
|
+
function intersectD(subject, clip, fillRule, precision = 2) {
|
|
30
|
+
return booleanOpD(Core_1.ClipType.Intersection, subject, clip, fillRule, precision);
|
|
31
|
+
}
|
|
32
|
+
Clipper.intersectD = intersectD;
|
|
33
|
+
function union(subject, clipOrFillRule, fillRule) {
|
|
34
|
+
if (typeof clipOrFillRule === 'number') {
|
|
35
|
+
// First overload: union(subject, fillRule)
|
|
36
|
+
return booleanOp(Core_1.ClipType.Union, subject, null, clipOrFillRule);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Second overload: union(subject, clip, fillRule)
|
|
40
|
+
return booleanOp(Core_1.ClipType.Union, subject, clipOrFillRule, fillRule);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
Clipper.union = union;
|
|
44
|
+
function unionD(subject, clipOrFillRule, fillRuleOrPrecision, precision) {
|
|
45
|
+
if (typeof clipOrFillRule === 'number') {
|
|
46
|
+
// First overload: unionD(subject, fillRule)
|
|
47
|
+
return booleanOpD(Core_1.ClipType.Union, subject, null, clipOrFillRule);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Second overload: unionD(subject, clip, fillRule, precision)
|
|
51
|
+
return booleanOpD(Core_1.ClipType.Union, subject, clipOrFillRule, fillRuleOrPrecision, precision || 2);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
Clipper.unionD = unionD;
|
|
55
|
+
function difference(subject, clip, fillRule) {
|
|
56
|
+
return booleanOp(Core_1.ClipType.Difference, subject, clip, fillRule);
|
|
57
|
+
}
|
|
58
|
+
Clipper.difference = difference;
|
|
59
|
+
function differenceD(subject, clip, fillRule, precision = 2) {
|
|
60
|
+
return booleanOpD(Core_1.ClipType.Difference, subject, clip, fillRule, precision);
|
|
61
|
+
}
|
|
62
|
+
Clipper.differenceD = differenceD;
|
|
63
|
+
function xor(subject, clip, fillRule) {
|
|
64
|
+
return booleanOp(Core_1.ClipType.Xor, subject, clip, fillRule);
|
|
65
|
+
}
|
|
66
|
+
Clipper.xor = xor;
|
|
67
|
+
function xorD(subject, clip, fillRule, precision = 2) {
|
|
68
|
+
return booleanOpD(Core_1.ClipType.Xor, subject, clip, fillRule, precision);
|
|
69
|
+
}
|
|
70
|
+
Clipper.xorD = xorD;
|
|
71
|
+
function booleanOp(clipType, subject, clip, fillRule) {
|
|
72
|
+
const solution = [];
|
|
73
|
+
if (subject === null)
|
|
74
|
+
return solution;
|
|
75
|
+
const c = new Engine_1.Clipper64();
|
|
76
|
+
c.addPaths(subject, Core_1.PathType.Subject);
|
|
77
|
+
if (clip !== null) {
|
|
78
|
+
c.addPaths(clip, Core_1.PathType.Clip);
|
|
79
|
+
}
|
|
80
|
+
c.execute(clipType, fillRule, solution);
|
|
81
|
+
return solution;
|
|
82
|
+
}
|
|
83
|
+
Clipper.booleanOp = booleanOp;
|
|
84
|
+
function booleanOpWithPolyTree(clipType, subject, clip, polytree, fillRule) {
|
|
85
|
+
if (subject === null)
|
|
86
|
+
return;
|
|
87
|
+
const c = new Engine_1.Clipper64();
|
|
88
|
+
c.addPaths(subject, Core_1.PathType.Subject);
|
|
89
|
+
if (clip !== null) {
|
|
90
|
+
c.addPaths(clip, Core_1.PathType.Clip);
|
|
91
|
+
}
|
|
92
|
+
c.execute(clipType, fillRule, polytree);
|
|
93
|
+
}
|
|
94
|
+
Clipper.booleanOpWithPolyTree = booleanOpWithPolyTree;
|
|
95
|
+
function booleanOpD(clipType, subject, clip, fillRule, precision = 2) {
|
|
96
|
+
const solution = [];
|
|
97
|
+
const c = new Engine_1.ClipperD(precision);
|
|
98
|
+
c.addSubjectPaths(subject);
|
|
99
|
+
if (clip !== null) {
|
|
100
|
+
c.addClipPaths(clip);
|
|
101
|
+
}
|
|
102
|
+
c.execute(clipType, fillRule, solution);
|
|
103
|
+
return solution;
|
|
104
|
+
}
|
|
105
|
+
Clipper.booleanOpD = booleanOpD;
|
|
106
|
+
function booleanOpDWithPolyTree(clipType, subject, clip, polytree, fillRule, precision = 2) {
|
|
107
|
+
if (subject === null)
|
|
108
|
+
return;
|
|
109
|
+
const c = new Engine_1.ClipperD(precision);
|
|
110
|
+
c.addSubjectPaths(subject);
|
|
111
|
+
if (clip !== null) {
|
|
112
|
+
c.addClipPaths(clip);
|
|
113
|
+
}
|
|
114
|
+
c.execute(clipType, fillRule, polytree);
|
|
115
|
+
}
|
|
116
|
+
Clipper.booleanOpDWithPolyTree = booleanOpDWithPolyTree;
|
|
117
|
+
function inflatePaths(paths, delta, joinType, endType, miterLimit = 2.0, arcTolerance = 0.0) {
|
|
118
|
+
const co = new Offset_1.ClipperOffset(miterLimit, arcTolerance);
|
|
119
|
+
co.addPaths(paths, joinType, endType);
|
|
120
|
+
const solution = [];
|
|
121
|
+
co.execute(delta, solution);
|
|
122
|
+
return solution;
|
|
123
|
+
}
|
|
124
|
+
Clipper.inflatePaths = inflatePaths;
|
|
125
|
+
function inflatePathsD(paths, delta, joinType, endType, miterLimit = 2.0, precision = 2, arcTolerance = 0.0) {
|
|
126
|
+
Core_1.InternalClipper.checkPrecision(precision);
|
|
127
|
+
const scale = Math.pow(10, precision);
|
|
128
|
+
const tmp = scalePaths64(paths, scale);
|
|
129
|
+
const co = new Offset_1.ClipperOffset(miterLimit, scale * arcTolerance);
|
|
130
|
+
co.addPaths(tmp, joinType, endType);
|
|
131
|
+
const solution = [];
|
|
132
|
+
co.execute(delta * scale, solution); // reuse solution to receive (scaled) solution
|
|
133
|
+
return scalePathsD(solution, 1 / scale);
|
|
134
|
+
}
|
|
135
|
+
Clipper.inflatePathsD = inflatePathsD;
|
|
136
|
+
function rectClip(rect, pathsOrPath, precision) {
|
|
137
|
+
if ('left' in rect && typeof rect.left === 'number' && Number.isInteger(rect.left)) {
|
|
138
|
+
// Rect64 case
|
|
139
|
+
const rect64 = rect;
|
|
140
|
+
if (Core_1.Rect64Utils.isEmpty(rect64))
|
|
141
|
+
return [];
|
|
142
|
+
if (Array.isArray(pathsOrPath[0])) {
|
|
143
|
+
// Paths64
|
|
144
|
+
const paths = pathsOrPath;
|
|
145
|
+
if (paths.length === 0)
|
|
146
|
+
return [];
|
|
147
|
+
const rc = new RectClip_1.RectClip64(rect64);
|
|
148
|
+
return rc.execute(paths);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Path64
|
|
152
|
+
const path = pathsOrPath;
|
|
153
|
+
if (path.length === 0)
|
|
154
|
+
return [];
|
|
155
|
+
const tmp = [path];
|
|
156
|
+
return rectClip(rect64, tmp);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// RectD case
|
|
161
|
+
const rectD = rect;
|
|
162
|
+
const prec = precision || 2;
|
|
163
|
+
Core_1.InternalClipper.checkPrecision(prec);
|
|
164
|
+
if (Core_1.RectDUtils.isEmpty(rectD))
|
|
165
|
+
return [];
|
|
166
|
+
const scale = Math.pow(10, prec);
|
|
167
|
+
const r = scaleRect(rectD, scale);
|
|
168
|
+
if (Array.isArray(pathsOrPath[0])) {
|
|
169
|
+
// PathsD
|
|
170
|
+
const paths = pathsOrPath;
|
|
171
|
+
if (paths.length === 0)
|
|
172
|
+
return [];
|
|
173
|
+
const tmpPath = scalePaths64(paths, scale);
|
|
174
|
+
const rc = new RectClip_1.RectClip64(r);
|
|
175
|
+
const result = rc.execute(tmpPath);
|
|
176
|
+
return scalePathsD(result, 1 / scale);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// PathD
|
|
180
|
+
const path = pathsOrPath;
|
|
181
|
+
if (path.length === 0)
|
|
182
|
+
return [];
|
|
183
|
+
const tmp = [path];
|
|
184
|
+
return rectClip(rectD, tmp, prec);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
Clipper.rectClip = rectClip;
|
|
189
|
+
function rectClipLines(rect, pathsOrPath, precision) {
|
|
190
|
+
if ('left' in rect && typeof rect.left === 'number' && Number.isInteger(rect.left)) {
|
|
191
|
+
// Rect64 case
|
|
192
|
+
const rect64 = rect;
|
|
193
|
+
if (Core_1.Rect64Utils.isEmpty(rect64))
|
|
194
|
+
return [];
|
|
195
|
+
if (Array.isArray(pathsOrPath[0])) {
|
|
196
|
+
// Paths64
|
|
197
|
+
const paths = pathsOrPath;
|
|
198
|
+
if (paths.length === 0)
|
|
199
|
+
return [];
|
|
200
|
+
const rc = new RectClip_1.RectClipLines64(rect64);
|
|
201
|
+
return rc.execute(paths);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Path64
|
|
205
|
+
const path = pathsOrPath;
|
|
206
|
+
if (path.length === 0)
|
|
207
|
+
return [];
|
|
208
|
+
const tmp = [path];
|
|
209
|
+
return rectClipLines(rect64, tmp);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// RectD case
|
|
214
|
+
const rectD = rect;
|
|
215
|
+
const prec = precision || 2;
|
|
216
|
+
Core_1.InternalClipper.checkPrecision(prec);
|
|
217
|
+
if (Core_1.RectDUtils.isEmpty(rectD))
|
|
218
|
+
return [];
|
|
219
|
+
const scale = Math.pow(10, prec);
|
|
220
|
+
const r = scaleRect(rectD, scale);
|
|
221
|
+
if (Array.isArray(pathsOrPath[0])) {
|
|
222
|
+
// PathsD
|
|
223
|
+
const paths = pathsOrPath;
|
|
224
|
+
if (paths.length === 0)
|
|
225
|
+
return [];
|
|
226
|
+
const tmpPath = scalePaths64(paths, scale);
|
|
227
|
+
const rc = new RectClip_1.RectClipLines64(r);
|
|
228
|
+
const result = rc.execute(tmpPath);
|
|
229
|
+
return scalePathsD(result, 1 / scale);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// PathD
|
|
233
|
+
const path = pathsOrPath;
|
|
234
|
+
if (path.length === 0)
|
|
235
|
+
return [];
|
|
236
|
+
const tmp = [path];
|
|
237
|
+
return rectClipLines(rectD, tmp, prec);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
Clipper.rectClipLines = rectClipLines;
|
|
242
|
+
function minkowskiSum(pattern, path, isClosed) {
|
|
243
|
+
return Minkowski_1.Minkowski.sum(pattern, path, isClosed);
|
|
244
|
+
}
|
|
245
|
+
Clipper.minkowskiSum = minkowskiSum;
|
|
246
|
+
function minkowskiSumD(pattern, path, isClosed) {
|
|
247
|
+
return Minkowski_1.Minkowski.sumD(pattern, path, isClosed);
|
|
248
|
+
}
|
|
249
|
+
Clipper.minkowskiSumD = minkowskiSumD;
|
|
250
|
+
function minkowskiDiff(pattern, path, isClosed) {
|
|
251
|
+
return Minkowski_1.Minkowski.diff(pattern, path, isClosed);
|
|
252
|
+
}
|
|
253
|
+
Clipper.minkowskiDiff = minkowskiDiff;
|
|
254
|
+
function minkowskiDiffD(pattern, path, isClosed) {
|
|
255
|
+
return Minkowski_1.Minkowski.diffD(pattern, path, isClosed);
|
|
256
|
+
}
|
|
257
|
+
Clipper.minkowskiDiffD = minkowskiDiffD;
|
|
258
|
+
function area(path) {
|
|
259
|
+
// https://en.wikipedia.org/wiki/Shoelace_formula
|
|
260
|
+
let a = 0.0;
|
|
261
|
+
const cnt = path.length;
|
|
262
|
+
if (cnt < 3)
|
|
263
|
+
return 0.0;
|
|
264
|
+
let prevPt = path[cnt - 1];
|
|
265
|
+
for (const pt of path) {
|
|
266
|
+
a += (prevPt.y + pt.y) * (prevPt.x - pt.x);
|
|
267
|
+
prevPt = pt;
|
|
268
|
+
}
|
|
269
|
+
return a * 0.5;
|
|
270
|
+
}
|
|
271
|
+
Clipper.area = area;
|
|
272
|
+
function areaPaths(paths) {
|
|
273
|
+
let a = 0.0;
|
|
274
|
+
for (const path of paths) {
|
|
275
|
+
a += area(path);
|
|
276
|
+
}
|
|
277
|
+
return a;
|
|
278
|
+
}
|
|
279
|
+
Clipper.areaPaths = areaPaths;
|
|
280
|
+
function areaD(path) {
|
|
281
|
+
let a = 0.0;
|
|
282
|
+
const cnt = path.length;
|
|
283
|
+
if (cnt < 3)
|
|
284
|
+
return 0.0;
|
|
285
|
+
let prevPt = path[cnt - 1];
|
|
286
|
+
for (const pt of path) {
|
|
287
|
+
a += (prevPt.y + pt.y) * (prevPt.x - pt.x);
|
|
288
|
+
prevPt = pt;
|
|
289
|
+
}
|
|
290
|
+
return a * 0.5;
|
|
291
|
+
}
|
|
292
|
+
Clipper.areaD = areaD;
|
|
293
|
+
function areaPathsD(paths) {
|
|
294
|
+
let a = 0.0;
|
|
295
|
+
for (const path of paths) {
|
|
296
|
+
a += areaD(path);
|
|
297
|
+
}
|
|
298
|
+
return a;
|
|
299
|
+
}
|
|
300
|
+
Clipper.areaPathsD = areaPathsD;
|
|
301
|
+
function isPositive(poly) {
|
|
302
|
+
return area(poly) >= 0;
|
|
303
|
+
}
|
|
304
|
+
Clipper.isPositive = isPositive;
|
|
305
|
+
function isPositiveD(poly) {
|
|
306
|
+
return areaD(poly) >= 0;
|
|
307
|
+
}
|
|
308
|
+
Clipper.isPositiveD = isPositiveD;
|
|
309
|
+
function path64ToString(path) {
|
|
310
|
+
let result = "";
|
|
311
|
+
for (const pt of path) {
|
|
312
|
+
result += Core_1.Point64Utils.toString(pt);
|
|
313
|
+
}
|
|
314
|
+
return result + '\n';
|
|
315
|
+
}
|
|
316
|
+
Clipper.path64ToString = path64ToString;
|
|
317
|
+
function paths64ToString(paths) {
|
|
318
|
+
let result = "";
|
|
319
|
+
for (const path of paths) {
|
|
320
|
+
result += path64ToString(path);
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
Clipper.paths64ToString = paths64ToString;
|
|
325
|
+
function pathDToString(path, precision = 2) {
|
|
326
|
+
let result = "";
|
|
327
|
+
for (const pt of path) {
|
|
328
|
+
result += Core_1.PointDUtils.toString(pt, precision);
|
|
329
|
+
}
|
|
330
|
+
return result + '\n';
|
|
331
|
+
}
|
|
332
|
+
Clipper.pathDToString = pathDToString;
|
|
333
|
+
function pathsDToString(paths, precision = 2) {
|
|
334
|
+
let result = "";
|
|
335
|
+
for (const path of paths) {
|
|
336
|
+
result += pathDToString(path, precision);
|
|
337
|
+
}
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
Clipper.pathsDToString = pathsDToString;
|
|
341
|
+
function offsetPath(path, dx, dy) {
|
|
342
|
+
const result = [];
|
|
343
|
+
for (const pt of path) {
|
|
344
|
+
result.push({ x: pt.x + dx, y: pt.y + dy });
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
Clipper.offsetPath = offsetPath;
|
|
349
|
+
function scalePoint64(pt, scale) {
|
|
350
|
+
return {
|
|
351
|
+
x: Math.round(pt.x * scale),
|
|
352
|
+
y: Math.round(pt.y * scale)
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
Clipper.scalePoint64 = scalePoint64;
|
|
356
|
+
function scalePointD(pt, scale) {
|
|
357
|
+
return {
|
|
358
|
+
x: pt.x * scale,
|
|
359
|
+
y: pt.y * scale
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
Clipper.scalePointD = scalePointD;
|
|
363
|
+
function scaleRect(rec, scale) {
|
|
364
|
+
return {
|
|
365
|
+
left: Math.round(rec.left * scale),
|
|
366
|
+
top: Math.round(rec.top * scale),
|
|
367
|
+
right: Math.round(rec.right * scale),
|
|
368
|
+
bottom: Math.round(rec.bottom * scale)
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
Clipper.scaleRect = scaleRect;
|
|
372
|
+
function scalePath(path, scale) {
|
|
373
|
+
if (Core_1.InternalClipper.isAlmostZero(scale - 1))
|
|
374
|
+
return path;
|
|
375
|
+
const result = [];
|
|
376
|
+
for (const pt of path) {
|
|
377
|
+
result.push({
|
|
378
|
+
x: Math.round(pt.x * scale),
|
|
379
|
+
y: Math.round(pt.y * scale)
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
383
|
+
}
|
|
384
|
+
Clipper.scalePath = scalePath;
|
|
385
|
+
function scalePaths(paths, scale) {
|
|
386
|
+
if (Core_1.InternalClipper.isAlmostZero(scale - 1))
|
|
387
|
+
return paths;
|
|
388
|
+
const result = [];
|
|
389
|
+
for (const path of paths) {
|
|
390
|
+
result.push(scalePath(path, scale));
|
|
391
|
+
}
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
Clipper.scalePaths = scalePaths;
|
|
395
|
+
function scalePathD(path, scale) {
|
|
396
|
+
if (Core_1.InternalClipper.isAlmostZero(scale - 1))
|
|
397
|
+
return path;
|
|
398
|
+
const result = [];
|
|
399
|
+
for (const pt of path) {
|
|
400
|
+
result.push(Core_1.PointDUtils.scale(pt, scale));
|
|
401
|
+
}
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
Clipper.scalePathD = scalePathD;
|
|
405
|
+
function scalePathsD(paths, scale) {
|
|
406
|
+
if (Core_1.InternalClipper.isAlmostZero(scale - 1))
|
|
407
|
+
return paths;
|
|
408
|
+
const result = [];
|
|
409
|
+
for (const path of paths) {
|
|
410
|
+
result.push(scalePathD(path, scale));
|
|
411
|
+
}
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
Clipper.scalePathsD = scalePathsD;
|
|
415
|
+
// Unlike ScalePath, both ScalePath64 & ScalePathD also involve type conversion
|
|
416
|
+
function scalePath64(path, scale) {
|
|
417
|
+
const result = [];
|
|
418
|
+
for (const pt of path) {
|
|
419
|
+
result.push({
|
|
420
|
+
x: Math.round(pt.x * scale),
|
|
421
|
+
y: Math.round(pt.y * scale)
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
Clipper.scalePath64 = scalePath64;
|
|
427
|
+
function scalePaths64(paths, scale) {
|
|
428
|
+
const result = [];
|
|
429
|
+
for (const path of paths) {
|
|
430
|
+
result.push(scalePath64(path, scale));
|
|
431
|
+
}
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
Clipper.scalePaths64 = scalePaths64;
|
|
435
|
+
function scalePathDFromInt(path, scale) {
|
|
436
|
+
const result = [];
|
|
437
|
+
for (const pt of path) {
|
|
438
|
+
result.push({
|
|
439
|
+
x: pt.x * scale,
|
|
440
|
+
y: pt.y * scale
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
445
|
+
Clipper.scalePathDFromInt = scalePathDFromInt;
|
|
446
|
+
function scalePathsDFromInt(paths, scale) {
|
|
447
|
+
const result = [];
|
|
448
|
+
for (const path of paths) {
|
|
449
|
+
result.push(scalePathDFromInt(path, scale));
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
Clipper.scalePathsDFromInt = scalePathsDFromInt;
|
|
454
|
+
// The static functions Path64 and PathD convert path types without scaling
|
|
455
|
+
function path64FromD(path) {
|
|
456
|
+
const result = [];
|
|
457
|
+
for (const pt of path) {
|
|
458
|
+
result.push(Core_1.Point64Utils.fromPointD(pt));
|
|
459
|
+
}
|
|
460
|
+
return result;
|
|
461
|
+
}
|
|
462
|
+
Clipper.path64FromD = path64FromD;
|
|
463
|
+
function paths64FromD(paths) {
|
|
464
|
+
const result = [];
|
|
465
|
+
for (const path of paths) {
|
|
466
|
+
result.push(path64FromD(path));
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
470
|
+
Clipper.paths64FromD = paths64FromD;
|
|
471
|
+
function pathsD(paths) {
|
|
472
|
+
const result = [];
|
|
473
|
+
for (const path of paths) {
|
|
474
|
+
result.push(pathD(path));
|
|
475
|
+
}
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
Clipper.pathsD = pathsD;
|
|
479
|
+
function pathD(path) {
|
|
480
|
+
const result = [];
|
|
481
|
+
for (const pt of path) {
|
|
482
|
+
result.push(Core_1.PointDUtils.fromPoint64(pt));
|
|
483
|
+
}
|
|
484
|
+
return result;
|
|
485
|
+
}
|
|
486
|
+
Clipper.pathD = pathD;
|
|
487
|
+
function translatePath(path, dx, dy) {
|
|
488
|
+
const result = [];
|
|
489
|
+
for (const pt of path) {
|
|
490
|
+
result.push({ x: pt.x + dx, y: pt.y + dy });
|
|
491
|
+
}
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
Clipper.translatePath = translatePath;
|
|
495
|
+
function translatePaths(paths, dx, dy) {
|
|
496
|
+
const result = [];
|
|
497
|
+
for (const path of paths) {
|
|
498
|
+
result.push(offsetPath(path, dx, dy));
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
}
|
|
502
|
+
Clipper.translatePaths = translatePaths;
|
|
503
|
+
function translatePathD(path, dx, dy) {
|
|
504
|
+
const result = [];
|
|
505
|
+
for (const pt of path) {
|
|
506
|
+
result.push({ x: pt.x + dx, y: pt.y + dy });
|
|
507
|
+
}
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
Clipper.translatePathD = translatePathD;
|
|
511
|
+
function translatePathsD(paths, dx, dy) {
|
|
512
|
+
const result = [];
|
|
513
|
+
for (const path of paths) {
|
|
514
|
+
result.push(translatePathD(path, dx, dy));
|
|
515
|
+
}
|
|
516
|
+
return result;
|
|
517
|
+
}
|
|
518
|
+
Clipper.translatePathsD = translatePathsD;
|
|
519
|
+
function reversePath(path) {
|
|
520
|
+
return [...path].reverse();
|
|
521
|
+
}
|
|
522
|
+
Clipper.reversePath = reversePath;
|
|
523
|
+
function reversePathD(path) {
|
|
524
|
+
return [...path].reverse();
|
|
525
|
+
}
|
|
526
|
+
Clipper.reversePathD = reversePathD;
|
|
527
|
+
function reversePaths(paths) {
|
|
528
|
+
const result = [];
|
|
529
|
+
for (const path of paths) {
|
|
530
|
+
result.push(reversePath(path));
|
|
531
|
+
}
|
|
532
|
+
return result;
|
|
533
|
+
}
|
|
534
|
+
Clipper.reversePaths = reversePaths;
|
|
535
|
+
function reversePathsD(paths) {
|
|
536
|
+
const result = [];
|
|
537
|
+
for (const path of paths) {
|
|
538
|
+
result.push(reversePathD(path));
|
|
539
|
+
}
|
|
540
|
+
return result;
|
|
541
|
+
}
|
|
542
|
+
Clipper.reversePathsD = reversePathsD;
|
|
543
|
+
function getBounds(path) {
|
|
544
|
+
return Core_1.InternalClipper.getBounds(path);
|
|
545
|
+
}
|
|
546
|
+
Clipper.getBounds = getBounds;
|
|
547
|
+
function getBoundsPaths(paths) {
|
|
548
|
+
const result = Core_1.Rect64Utils.createInvalid();
|
|
549
|
+
for (const path of paths) {
|
|
550
|
+
for (const pt of path) {
|
|
551
|
+
if (pt.x < result.left)
|
|
552
|
+
result.left = pt.x;
|
|
553
|
+
if (pt.x > result.right)
|
|
554
|
+
result.right = pt.x;
|
|
555
|
+
if (pt.y < result.top)
|
|
556
|
+
result.top = pt.y;
|
|
557
|
+
if (pt.y > result.bottom)
|
|
558
|
+
result.bottom = pt.y;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return result.left === Number.MAX_SAFE_INTEGER ? { left: 0, top: 0, right: 0, bottom: 0 } : result;
|
|
562
|
+
}
|
|
563
|
+
Clipper.getBoundsPaths = getBoundsPaths;
|
|
564
|
+
function getBoundsD(path) {
|
|
565
|
+
const result = Core_1.RectDUtils.createInvalid();
|
|
566
|
+
for (const pt of path) {
|
|
567
|
+
if (pt.x < result.left)
|
|
568
|
+
result.left = pt.x;
|
|
569
|
+
if (pt.x > result.right)
|
|
570
|
+
result.right = pt.x;
|
|
571
|
+
if (pt.y < result.top)
|
|
572
|
+
result.top = pt.y;
|
|
573
|
+
if (pt.y > result.bottom)
|
|
574
|
+
result.bottom = pt.y;
|
|
575
|
+
}
|
|
576
|
+
return Math.abs(result.left - Number.MAX_VALUE) < Core_1.InternalClipper.floatingPointTolerance ?
|
|
577
|
+
{ left: 0, top: 0, right: 0, bottom: 0 } : result;
|
|
578
|
+
}
|
|
579
|
+
Clipper.getBoundsD = getBoundsD;
|
|
580
|
+
function getBoundsPathsD(paths) {
|
|
581
|
+
const result = Core_1.RectDUtils.createInvalid();
|
|
582
|
+
for (const path of paths) {
|
|
583
|
+
for (const pt of path) {
|
|
584
|
+
if (pt.x < result.left)
|
|
585
|
+
result.left = pt.x;
|
|
586
|
+
if (pt.x > result.right)
|
|
587
|
+
result.right = pt.x;
|
|
588
|
+
if (pt.y < result.top)
|
|
589
|
+
result.top = pt.y;
|
|
590
|
+
if (pt.y > result.bottom)
|
|
591
|
+
result.bottom = pt.y;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return Math.abs(result.left - Number.MAX_VALUE) < Core_1.InternalClipper.floatingPointTolerance ?
|
|
595
|
+
{ left: 0, top: 0, right: 0, bottom: 0 } : result;
|
|
596
|
+
}
|
|
597
|
+
Clipper.getBoundsPathsD = getBoundsPathsD;
|
|
598
|
+
function makePath(arr) {
|
|
599
|
+
const len = Math.floor(arr.length / 2);
|
|
600
|
+
const p = [];
|
|
601
|
+
for (let i = 0; i < len; i++) {
|
|
602
|
+
p.push({ x: arr[i * 2], y: arr[i * 2 + 1] });
|
|
603
|
+
}
|
|
604
|
+
return p;
|
|
605
|
+
}
|
|
606
|
+
Clipper.makePath = makePath;
|
|
607
|
+
function makePathD(arr) {
|
|
608
|
+
const len = Math.floor(arr.length / 2);
|
|
609
|
+
const p = [];
|
|
610
|
+
for (let i = 0; i < len; i++) {
|
|
611
|
+
p.push({ x: arr[i * 2], y: arr[i * 2 + 1] });
|
|
612
|
+
}
|
|
613
|
+
return p;
|
|
614
|
+
}
|
|
615
|
+
Clipper.makePathD = makePathD;
|
|
616
|
+
function sqr(val) {
|
|
617
|
+
return val * val;
|
|
618
|
+
}
|
|
619
|
+
Clipper.sqr = sqr;
|
|
620
|
+
function distanceSqr(pt1, pt2) {
|
|
621
|
+
return sqr(pt1.x - pt2.x) + sqr(pt1.y - pt2.y);
|
|
622
|
+
}
|
|
623
|
+
Clipper.distanceSqr = distanceSqr;
|
|
624
|
+
function midPoint(pt1, pt2) {
|
|
625
|
+
return { x: Math.round((pt1.x + pt2.x) / 2), y: Math.round((pt1.y + pt2.y) / 2) };
|
|
626
|
+
}
|
|
627
|
+
Clipper.midPoint = midPoint;
|
|
628
|
+
function midPointD(pt1, pt2) {
|
|
629
|
+
return { x: (pt1.x + pt2.x) / 2, y: (pt1.y + pt2.y) / 2 };
|
|
630
|
+
}
|
|
631
|
+
Clipper.midPointD = midPointD;
|
|
632
|
+
function inflateRect(rec, dx, dy) {
|
|
633
|
+
rec.left -= dx;
|
|
634
|
+
rec.right += dx;
|
|
635
|
+
rec.top -= dy;
|
|
636
|
+
rec.bottom += dy;
|
|
637
|
+
}
|
|
638
|
+
Clipper.inflateRect = inflateRect;
|
|
639
|
+
function inflateRectD(rec, dx, dy) {
|
|
640
|
+
rec.left -= dx;
|
|
641
|
+
rec.right += dx;
|
|
642
|
+
rec.top -= dy;
|
|
643
|
+
rec.bottom += dy;
|
|
644
|
+
}
|
|
645
|
+
Clipper.inflateRectD = inflateRectD;
|
|
646
|
+
function pointsNearEqual(pt1, pt2, distanceSqrd) {
|
|
647
|
+
return sqr(pt1.x - pt2.x) + sqr(pt1.y - pt2.y) < distanceSqrd;
|
|
648
|
+
}
|
|
649
|
+
Clipper.pointsNearEqual = pointsNearEqual;
|
|
650
|
+
function stripNearDuplicates(path, minEdgeLenSqrd, isClosedPath) {
|
|
651
|
+
const cnt = path.length;
|
|
652
|
+
const result = [];
|
|
653
|
+
if (cnt === 0)
|
|
654
|
+
return result;
|
|
655
|
+
let lastPt = path[0];
|
|
656
|
+
result.push(lastPt);
|
|
657
|
+
for (let i = 1; i < cnt; i++) {
|
|
658
|
+
if (!pointsNearEqual(lastPt, path[i], minEdgeLenSqrd)) {
|
|
659
|
+
lastPt = path[i];
|
|
660
|
+
result.push(lastPt);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
if (isClosedPath && pointsNearEqual(lastPt, result[0], minEdgeLenSqrd)) {
|
|
664
|
+
result.pop();
|
|
665
|
+
}
|
|
666
|
+
return result;
|
|
667
|
+
}
|
|
668
|
+
Clipper.stripNearDuplicates = stripNearDuplicates;
|
|
669
|
+
function stripDuplicates(path, isClosedPath) {
|
|
670
|
+
const cnt = path.length;
|
|
671
|
+
const result = [];
|
|
672
|
+
if (cnt === 0)
|
|
673
|
+
return result;
|
|
674
|
+
let lastPt = path[0];
|
|
675
|
+
result.push(lastPt);
|
|
676
|
+
for (let i = 1; i < cnt; i++) {
|
|
677
|
+
if (!Core_1.Point64Utils.equals(lastPt, path[i])) {
|
|
678
|
+
lastPt = path[i];
|
|
679
|
+
result.push(lastPt);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (isClosedPath && Core_1.Point64Utils.equals(lastPt, result[0])) {
|
|
683
|
+
result.pop();
|
|
684
|
+
}
|
|
685
|
+
return result;
|
|
686
|
+
}
|
|
687
|
+
Clipper.stripDuplicates = stripDuplicates;
|
|
688
|
+
function addPolyNodeToPaths(polyPath, paths) {
|
|
689
|
+
if (polyPath.poly && polyPath.poly.length > 0) {
|
|
690
|
+
paths.push(polyPath.poly);
|
|
691
|
+
}
|
|
692
|
+
for (let i = 0; i < polyPath.count; i++) {
|
|
693
|
+
addPolyNodeToPaths(polyPath.child(i), paths);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function polyTreeToPaths64(polyTree) {
|
|
697
|
+
const result = [];
|
|
698
|
+
for (let i = 0; i < polyTree.count; i++) {
|
|
699
|
+
addPolyNodeToPaths(polyTree.child(i), result);
|
|
700
|
+
}
|
|
701
|
+
return result;
|
|
702
|
+
}
|
|
703
|
+
Clipper.polyTreeToPaths64 = polyTreeToPaths64;
|
|
704
|
+
function addPolyNodeToPathsD(polyPath, paths) {
|
|
705
|
+
if (polyPath.poly && polyPath.poly.length > 0) {
|
|
706
|
+
paths.push(polyPath.poly);
|
|
707
|
+
}
|
|
708
|
+
for (let i = 0; i < polyPath.count; i++) {
|
|
709
|
+
addPolyNodeToPathsD(polyPath.child(i), paths);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
Clipper.addPolyNodeToPathsD = addPolyNodeToPathsD;
|
|
713
|
+
function polyTreeToPathsD(polyTree) {
|
|
714
|
+
const result = [];
|
|
715
|
+
for (let i = 0; i < polyTree.count; i++) {
|
|
716
|
+
addPolyNodeToPathsD(polyTree.child(i), result);
|
|
717
|
+
}
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
Clipper.polyTreeToPathsD = polyTreeToPathsD;
|
|
721
|
+
function perpendicDistFromLineSqrd(pt, line1, line2) {
|
|
722
|
+
const a = pt.x - line1.x;
|
|
723
|
+
const b = pt.y - line1.y;
|
|
724
|
+
const c = line2.x - line1.x;
|
|
725
|
+
const d = line2.y - line1.y;
|
|
726
|
+
if (c === 0 && d === 0)
|
|
727
|
+
return 0;
|
|
728
|
+
return sqr(a * d - c * b) / (c * c + d * d);
|
|
729
|
+
}
|
|
730
|
+
Clipper.perpendicDistFromLineSqrd = perpendicDistFromLineSqrd;
|
|
731
|
+
function perpendicDistFromLineSqrd64(pt, line1, line2) {
|
|
732
|
+
const a = pt.x - line1.x;
|
|
733
|
+
const b = pt.y - line1.y;
|
|
734
|
+
const c = line2.x - line1.x;
|
|
735
|
+
const d = line2.y - line1.y;
|
|
736
|
+
if (c === 0 && d === 0)
|
|
737
|
+
return 0;
|
|
738
|
+
return sqr(a * d - c * b) / (c * c + d * d);
|
|
739
|
+
}
|
|
740
|
+
Clipper.perpendicDistFromLineSqrd64 = perpendicDistFromLineSqrd64;
|
|
741
|
+
function rdp(path, begin, end, epsSqrd, flags) {
|
|
742
|
+
while (true) {
|
|
743
|
+
let idx = 0;
|
|
744
|
+
let maxD = 0;
|
|
745
|
+
while (end > begin && Core_1.Point64Utils.equals(path[begin], path[end]))
|
|
746
|
+
flags[end--] = false;
|
|
747
|
+
for (let i = begin + 1; i < end; ++i) {
|
|
748
|
+
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
|
|
749
|
+
const d = perpendicDistFromLineSqrd64(path[i], path[begin], path[end]);
|
|
750
|
+
if (d <= maxD)
|
|
751
|
+
continue;
|
|
752
|
+
maxD = d;
|
|
753
|
+
idx = i;
|
|
754
|
+
}
|
|
755
|
+
if (maxD <= epsSqrd)
|
|
756
|
+
return;
|
|
757
|
+
flags[idx] = true;
|
|
758
|
+
if (idx > begin + 1)
|
|
759
|
+
rdp(path, begin, idx, epsSqrd, flags);
|
|
760
|
+
if (idx < end - 1) {
|
|
761
|
+
begin = idx;
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
function ramerDouglasPeucker(path, epsilon) {
|
|
768
|
+
const len = path.length;
|
|
769
|
+
if (len < 5)
|
|
770
|
+
return path;
|
|
771
|
+
const flags = new Array(len).fill(false);
|
|
772
|
+
flags[0] = true;
|
|
773
|
+
flags[len - 1] = true;
|
|
774
|
+
rdp(path, 0, len - 1, sqr(epsilon), flags);
|
|
775
|
+
const result = [];
|
|
776
|
+
for (let i = 0; i < len; ++i) {
|
|
777
|
+
if (flags[i])
|
|
778
|
+
result.push(path[i]);
|
|
779
|
+
}
|
|
780
|
+
return result;
|
|
781
|
+
}
|
|
782
|
+
Clipper.ramerDouglasPeucker = ramerDouglasPeucker;
|
|
783
|
+
function ramerDouglasPeuckerPaths(paths, epsilon) {
|
|
784
|
+
const result = [];
|
|
785
|
+
for (const path of paths) {
|
|
786
|
+
result.push(ramerDouglasPeucker(path, epsilon));
|
|
787
|
+
}
|
|
788
|
+
return result;
|
|
789
|
+
}
|
|
790
|
+
Clipper.ramerDouglasPeuckerPaths = ramerDouglasPeuckerPaths;
|
|
791
|
+
function rdpD(path, begin, end, epsSqrd, flags) {
|
|
792
|
+
while (true) {
|
|
793
|
+
let idx = 0;
|
|
794
|
+
let maxD = 0;
|
|
795
|
+
while (end > begin && Core_1.PointDUtils.equals(path[begin], path[end]))
|
|
796
|
+
flags[end--] = false;
|
|
797
|
+
for (let i = begin + 1; i < end; ++i) {
|
|
798
|
+
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
|
|
799
|
+
const d = perpendicDistFromLineSqrd(path[i], path[begin], path[end]);
|
|
800
|
+
if (d <= maxD)
|
|
801
|
+
continue;
|
|
802
|
+
maxD = d;
|
|
803
|
+
idx = i;
|
|
804
|
+
}
|
|
805
|
+
if (maxD <= epsSqrd)
|
|
806
|
+
return;
|
|
807
|
+
flags[idx] = true;
|
|
808
|
+
if (idx > begin + 1)
|
|
809
|
+
rdpD(path, begin, idx, epsSqrd, flags);
|
|
810
|
+
if (idx < end - 1) {
|
|
811
|
+
begin = idx;
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
function ramerDouglasPeuckerD(path, epsilon) {
|
|
818
|
+
const len = path.length;
|
|
819
|
+
if (len < 5)
|
|
820
|
+
return path;
|
|
821
|
+
const flags = new Array(len).fill(false);
|
|
822
|
+
flags[0] = true;
|
|
823
|
+
flags[len - 1] = true;
|
|
824
|
+
rdpD(path, 0, len - 1, sqr(epsilon), flags);
|
|
825
|
+
const result = [];
|
|
826
|
+
for (let i = 0; i < len; ++i) {
|
|
827
|
+
if (flags[i])
|
|
828
|
+
result.push(path[i]);
|
|
829
|
+
}
|
|
830
|
+
return result;
|
|
831
|
+
}
|
|
832
|
+
Clipper.ramerDouglasPeuckerD = ramerDouglasPeuckerD;
|
|
833
|
+
function ramerDouglasPeuckerPathsD(paths, epsilon) {
|
|
834
|
+
const result = [];
|
|
835
|
+
for (const path of paths) {
|
|
836
|
+
result.push(ramerDouglasPeuckerD(path, epsilon));
|
|
837
|
+
}
|
|
838
|
+
return result;
|
|
839
|
+
}
|
|
840
|
+
Clipper.ramerDouglasPeuckerPathsD = ramerDouglasPeuckerPathsD;
|
|
841
|
+
function getNext(current, high, flags) {
|
|
842
|
+
++current;
|
|
843
|
+
while (current <= high && flags[current])
|
|
844
|
+
++current;
|
|
845
|
+
if (current <= high)
|
|
846
|
+
return current;
|
|
847
|
+
current = 0;
|
|
848
|
+
while (flags[current])
|
|
849
|
+
++current;
|
|
850
|
+
return current;
|
|
851
|
+
}
|
|
852
|
+
function getPrior(current, high, flags) {
|
|
853
|
+
if (current === 0)
|
|
854
|
+
current = high;
|
|
855
|
+
else
|
|
856
|
+
--current;
|
|
857
|
+
while (current > 0 && flags[current])
|
|
858
|
+
--current;
|
|
859
|
+
if (!flags[current])
|
|
860
|
+
return current;
|
|
861
|
+
current = high;
|
|
862
|
+
while (flags[current])
|
|
863
|
+
--current;
|
|
864
|
+
return current;
|
|
865
|
+
}
|
|
866
|
+
function simplifyPath(path, epsilon, isClosedPath = true) {
|
|
867
|
+
const len = path.length;
|
|
868
|
+
const high = len - 1;
|
|
869
|
+
const epsSqr = sqr(epsilon);
|
|
870
|
+
if (len < 4)
|
|
871
|
+
return path;
|
|
872
|
+
const flags = new Array(len).fill(false);
|
|
873
|
+
const dsq = new Array(len).fill(0);
|
|
874
|
+
let curr = 0;
|
|
875
|
+
if (isClosedPath) {
|
|
876
|
+
dsq[0] = perpendicDistFromLineSqrd64(path[0], path[high], path[1]);
|
|
877
|
+
dsq[high] = perpendicDistFromLineSqrd64(path[high], path[0], path[high - 1]);
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
dsq[0] = Number.MAX_VALUE;
|
|
881
|
+
dsq[high] = Number.MAX_VALUE;
|
|
882
|
+
}
|
|
883
|
+
for (let i = 1; i < high; ++i) {
|
|
884
|
+
dsq[i] = perpendicDistFromLineSqrd64(path[i], path[i - 1], path[i + 1]);
|
|
885
|
+
}
|
|
886
|
+
while (true) {
|
|
887
|
+
if (dsq[curr] > epsSqr) {
|
|
888
|
+
const start = curr;
|
|
889
|
+
do {
|
|
890
|
+
curr = getNext(curr, high, flags);
|
|
891
|
+
} while (curr !== start && dsq[curr] > epsSqr);
|
|
892
|
+
if (curr === start)
|
|
893
|
+
break;
|
|
894
|
+
}
|
|
895
|
+
const prev = getPrior(curr, high, flags);
|
|
896
|
+
const next = getNext(curr, high, flags);
|
|
897
|
+
if (next === prev)
|
|
898
|
+
break;
|
|
899
|
+
let prior2;
|
|
900
|
+
if (dsq[next] < dsq[curr]) {
|
|
901
|
+
prior2 = prev;
|
|
902
|
+
const newPrev = curr;
|
|
903
|
+
curr = next;
|
|
904
|
+
const newNext = getNext(next, high, flags);
|
|
905
|
+
flags[curr] = true;
|
|
906
|
+
curr = newNext;
|
|
907
|
+
const nextNext = getNext(newNext, high, flags);
|
|
908
|
+
if (isClosedPath || ((curr !== high) && (curr !== 0))) {
|
|
909
|
+
dsq[curr] = perpendicDistFromLineSqrd64(path[curr], path[newPrev], path[nextNext]);
|
|
910
|
+
}
|
|
911
|
+
if (isClosedPath || ((newPrev !== 0) && (newPrev !== high))) {
|
|
912
|
+
dsq[newPrev] = perpendicDistFromLineSqrd64(path[newPrev], path[prior2], path[curr]);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
prior2 = getPrior(prev, high, flags);
|
|
917
|
+
flags[curr] = true;
|
|
918
|
+
curr = next;
|
|
919
|
+
const nextNext = getNext(next, high, flags);
|
|
920
|
+
if (isClosedPath || ((curr !== high) && (curr !== 0))) {
|
|
921
|
+
dsq[curr] = perpendicDistFromLineSqrd64(path[curr], path[prev], path[nextNext]);
|
|
922
|
+
}
|
|
923
|
+
if (isClosedPath || ((prev !== 0) && (prev !== high))) {
|
|
924
|
+
dsq[prev] = perpendicDistFromLineSqrd64(path[prev], path[prior2], path[curr]);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
const result = [];
|
|
929
|
+
for (let i = 0; i < len; i++) {
|
|
930
|
+
if (!flags[i])
|
|
931
|
+
result.push(path[i]);
|
|
932
|
+
}
|
|
933
|
+
return result;
|
|
934
|
+
}
|
|
935
|
+
Clipper.simplifyPath = simplifyPath;
|
|
936
|
+
function simplifyPaths(paths, epsilon, isClosedPaths = true) {
|
|
937
|
+
const result = [];
|
|
938
|
+
for (const path of paths) {
|
|
939
|
+
result.push(simplifyPath(path, epsilon, isClosedPaths));
|
|
940
|
+
}
|
|
941
|
+
return result;
|
|
942
|
+
}
|
|
943
|
+
Clipper.simplifyPaths = simplifyPaths;
|
|
944
|
+
function simplifyPathD(path, epsilon, isClosedPath = true) {
|
|
945
|
+
const len = path.length;
|
|
946
|
+
const high = len - 1;
|
|
947
|
+
const epsSqr = sqr(epsilon);
|
|
948
|
+
if (len < 4)
|
|
949
|
+
return path;
|
|
950
|
+
const flags = new Array(len).fill(false);
|
|
951
|
+
const dsq = new Array(len).fill(0);
|
|
952
|
+
let curr = 0;
|
|
953
|
+
if (isClosedPath) {
|
|
954
|
+
dsq[0] = perpendicDistFromLineSqrd(path[0], path[high], path[1]);
|
|
955
|
+
dsq[high] = perpendicDistFromLineSqrd(path[high], path[0], path[high - 1]);
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
dsq[0] = Number.MAX_VALUE;
|
|
959
|
+
dsq[high] = Number.MAX_VALUE;
|
|
960
|
+
}
|
|
961
|
+
for (let i = 1; i < high; ++i) {
|
|
962
|
+
dsq[i] = perpendicDistFromLineSqrd(path[i], path[i - 1], path[i + 1]);
|
|
963
|
+
}
|
|
964
|
+
while (true) {
|
|
965
|
+
if (dsq[curr] > epsSqr) {
|
|
966
|
+
const start = curr;
|
|
967
|
+
do {
|
|
968
|
+
curr = getNext(curr, high, flags);
|
|
969
|
+
} while (curr !== start && dsq[curr] > epsSqr);
|
|
970
|
+
if (curr === start)
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
const prev = getPrior(curr, high, flags);
|
|
974
|
+
const next = getNext(curr, high, flags);
|
|
975
|
+
if (next === prev)
|
|
976
|
+
break;
|
|
977
|
+
let prior2;
|
|
978
|
+
if (dsq[next] < dsq[curr]) {
|
|
979
|
+
prior2 = prev;
|
|
980
|
+
const newPrev = curr;
|
|
981
|
+
curr = next;
|
|
982
|
+
const newNext = getNext(next, high, flags);
|
|
983
|
+
flags[curr] = true;
|
|
984
|
+
curr = newNext;
|
|
985
|
+
const nextNext = getNext(newNext, high, flags);
|
|
986
|
+
if (isClosedPath || ((curr !== high) && (curr !== 0))) {
|
|
987
|
+
dsq[curr] = perpendicDistFromLineSqrd(path[curr], path[newPrev], path[nextNext]);
|
|
988
|
+
}
|
|
989
|
+
if (isClosedPath || ((newPrev !== 0) && (newPrev !== high))) {
|
|
990
|
+
dsq[newPrev] = perpendicDistFromLineSqrd(path[newPrev], path[prior2], path[curr]);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
prior2 = getPrior(prev, high, flags);
|
|
995
|
+
flags[curr] = true;
|
|
996
|
+
curr = next;
|
|
997
|
+
const nextNext = getNext(next, high, flags);
|
|
998
|
+
if (isClosedPath || ((curr !== high) && (curr !== 0))) {
|
|
999
|
+
dsq[curr] = perpendicDistFromLineSqrd(path[curr], path[prev], path[nextNext]);
|
|
1000
|
+
}
|
|
1001
|
+
if (isClosedPath || ((prev !== 0) && (prev !== high))) {
|
|
1002
|
+
dsq[prev] = perpendicDistFromLineSqrd(path[prev], path[prior2], path[curr]);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
const result = [];
|
|
1007
|
+
for (let i = 0; i < len; i++) {
|
|
1008
|
+
if (!flags[i])
|
|
1009
|
+
result.push(path[i]);
|
|
1010
|
+
}
|
|
1011
|
+
return result;
|
|
1012
|
+
}
|
|
1013
|
+
Clipper.simplifyPathD = simplifyPathD;
|
|
1014
|
+
function simplifyPathsD(paths, epsilon, isClosedPath = true) {
|
|
1015
|
+
const result = [];
|
|
1016
|
+
for (const path of paths) {
|
|
1017
|
+
result.push(simplifyPathD(path, epsilon, isClosedPath));
|
|
1018
|
+
}
|
|
1019
|
+
return result;
|
|
1020
|
+
}
|
|
1021
|
+
Clipper.simplifyPathsD = simplifyPathsD;
|
|
1022
|
+
function trimCollinear(path, isOpen = false) {
|
|
1023
|
+
let len = path.length;
|
|
1024
|
+
let i = 0;
|
|
1025
|
+
if (!isOpen) {
|
|
1026
|
+
while (i < len - 1 && Core_1.InternalClipper.isCollinear(path[len - 1], path[i], path[i + 1]))
|
|
1027
|
+
i++;
|
|
1028
|
+
while (i < len - 1 && Core_1.InternalClipper.isCollinear(path[len - 2], path[len - 1], path[i]))
|
|
1029
|
+
len--;
|
|
1030
|
+
}
|
|
1031
|
+
if (len - i < 3) {
|
|
1032
|
+
if (!isOpen || len < 2 || Core_1.Point64Utils.equals(path[0], path[1])) {
|
|
1033
|
+
return [];
|
|
1034
|
+
}
|
|
1035
|
+
return path;
|
|
1036
|
+
}
|
|
1037
|
+
const result = [];
|
|
1038
|
+
let last = path[i];
|
|
1039
|
+
result.push(last);
|
|
1040
|
+
for (i++; i < len - 1; i++) {
|
|
1041
|
+
if (Core_1.InternalClipper.isCollinear(last, path[i], path[i + 1]))
|
|
1042
|
+
continue;
|
|
1043
|
+
last = path[i];
|
|
1044
|
+
result.push(last);
|
|
1045
|
+
}
|
|
1046
|
+
if (isOpen) {
|
|
1047
|
+
result.push(path[len - 1]);
|
|
1048
|
+
}
|
|
1049
|
+
else if (!Core_1.InternalClipper.isCollinear(last, path[len - 1], result[0])) {
|
|
1050
|
+
result.push(path[len - 1]);
|
|
1051
|
+
}
|
|
1052
|
+
else {
|
|
1053
|
+
while (result.length > 2 && Core_1.InternalClipper.isCollinear(result[result.length - 1], result[result.length - 2], result[0])) {
|
|
1054
|
+
result.pop();
|
|
1055
|
+
}
|
|
1056
|
+
if (result.length < 3) {
|
|
1057
|
+
result.length = 0;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
return result;
|
|
1061
|
+
}
|
|
1062
|
+
Clipper.trimCollinear = trimCollinear;
|
|
1063
|
+
function trimCollinearD(path, precision, isOpen = false) {
|
|
1064
|
+
Core_1.InternalClipper.checkPrecision(precision);
|
|
1065
|
+
const scale = Math.pow(10, precision);
|
|
1066
|
+
let p = scalePath64(path, scale);
|
|
1067
|
+
p = trimCollinear(p, isOpen);
|
|
1068
|
+
return scalePathDFromInt(p, 1 / scale);
|
|
1069
|
+
}
|
|
1070
|
+
Clipper.trimCollinearD = trimCollinearD;
|
|
1071
|
+
function pointInPolygon(pt, polygon) {
|
|
1072
|
+
return Core_1.InternalClipper.pointInPolygon(pt, polygon);
|
|
1073
|
+
}
|
|
1074
|
+
Clipper.pointInPolygon = pointInPolygon;
|
|
1075
|
+
function pointInPolygonD(pt, polygon, precision = 2) {
|
|
1076
|
+
Core_1.InternalClipper.checkPrecision(precision);
|
|
1077
|
+
const scale = Math.pow(10, precision);
|
|
1078
|
+
const p = Core_1.Point64Utils.fromPointD(Core_1.PointDUtils.scale(pt, scale));
|
|
1079
|
+
const pathScaled = scalePath64(polygon, scale);
|
|
1080
|
+
return Core_1.InternalClipper.pointInPolygon(p, pathScaled);
|
|
1081
|
+
}
|
|
1082
|
+
Clipper.pointInPolygonD = pointInPolygonD;
|
|
1083
|
+
function ellipse(center, radiusX, radiusY = 0, steps = 0) {
|
|
1084
|
+
if (radiusX <= 0)
|
|
1085
|
+
return [];
|
|
1086
|
+
if (radiusY <= 0)
|
|
1087
|
+
radiusY = radiusX;
|
|
1088
|
+
if (steps <= 2) {
|
|
1089
|
+
steps = Math.ceil(Math.PI * Math.sqrt((radiusX + radiusY) / 2));
|
|
1090
|
+
}
|
|
1091
|
+
const si = Math.sin(2 * Math.PI / steps);
|
|
1092
|
+
const co = Math.cos(2 * Math.PI / steps);
|
|
1093
|
+
let dx = co;
|
|
1094
|
+
let dy = si;
|
|
1095
|
+
const result = [{ x: Math.round(center.x + radiusX), y: center.y }];
|
|
1096
|
+
for (let i = 1; i < steps; ++i) {
|
|
1097
|
+
result.push({
|
|
1098
|
+
x: Math.round(center.x + radiusX * dx),
|
|
1099
|
+
y: Math.round(center.y + radiusY * dy)
|
|
1100
|
+
});
|
|
1101
|
+
const x = dx * co - dy * si;
|
|
1102
|
+
dy = dy * co + dx * si;
|
|
1103
|
+
dx = x;
|
|
1104
|
+
}
|
|
1105
|
+
return result;
|
|
1106
|
+
}
|
|
1107
|
+
Clipper.ellipse = ellipse;
|
|
1108
|
+
function ellipseD(center, radiusX, radiusY = 0, steps = 0) {
|
|
1109
|
+
if (radiusX <= 0)
|
|
1110
|
+
return [];
|
|
1111
|
+
if (radiusY <= 0)
|
|
1112
|
+
radiusY = radiusX;
|
|
1113
|
+
if (steps <= 2) {
|
|
1114
|
+
steps = Math.ceil(Math.PI * Math.sqrt((radiusX + radiusY) / 2));
|
|
1115
|
+
}
|
|
1116
|
+
const si = Math.sin(2 * Math.PI / steps);
|
|
1117
|
+
const co = Math.cos(2 * Math.PI / steps);
|
|
1118
|
+
let dx = co;
|
|
1119
|
+
let dy = si;
|
|
1120
|
+
const result = [{ x: center.x + radiusX, y: center.y }];
|
|
1121
|
+
for (let i = 1; i < steps; ++i) {
|
|
1122
|
+
result.push({
|
|
1123
|
+
x: center.x + radiusX * dx,
|
|
1124
|
+
y: center.y + radiusY * dy
|
|
1125
|
+
});
|
|
1126
|
+
const x = dx * co - dy * si;
|
|
1127
|
+
dy = dy * co + dx * si;
|
|
1128
|
+
dx = x;
|
|
1129
|
+
}
|
|
1130
|
+
return result;
|
|
1131
|
+
}
|
|
1132
|
+
Clipper.ellipseD = ellipseD;
|
|
1133
|
+
})(Clipper || (exports.Clipper = Clipper = {}));
|
|
1134
|
+
//# sourceMappingURL=Clipper.js.map
|