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/Core.js
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*******************************************************************************
|
|
3
|
+
* Author : Angus Johnson *
|
|
4
|
+
* Date : 12 October 2025 *
|
|
5
|
+
* Website : https://www.angusj.com *
|
|
6
|
+
* Copyright : Angus Johnson 2010-2025 *
|
|
7
|
+
* Purpose : Core structures and functions for the Clipper Library *
|
|
8
|
+
* License : https://www.boost.org/LICENSE_1_0.txt *
|
|
9
|
+
*******************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.InvalidRectD = exports.InvalidRect64 = exports.PathsUtils = exports.PathUtils = exports.RectDUtils = exports.Rect64Utils = exports.PointDUtils = exports.Point64Utils = exports.InternalClipper = exports.PointInPolygonResult = exports.FillRule = exports.PathType = exports.ClipType = void 0;
|
|
12
|
+
// Note: all clipping operations except for Difference are commutative.
|
|
13
|
+
var ClipType;
|
|
14
|
+
(function (ClipType) {
|
|
15
|
+
ClipType[ClipType["NoClip"] = 0] = "NoClip";
|
|
16
|
+
ClipType[ClipType["Intersection"] = 1] = "Intersection";
|
|
17
|
+
ClipType[ClipType["Union"] = 2] = "Union";
|
|
18
|
+
ClipType[ClipType["Difference"] = 3] = "Difference";
|
|
19
|
+
ClipType[ClipType["Xor"] = 4] = "Xor";
|
|
20
|
+
})(ClipType || (exports.ClipType = ClipType = {}));
|
|
21
|
+
var PathType;
|
|
22
|
+
(function (PathType) {
|
|
23
|
+
PathType[PathType["Subject"] = 0] = "Subject";
|
|
24
|
+
PathType[PathType["Clip"] = 1] = "Clip";
|
|
25
|
+
})(PathType || (exports.PathType = PathType = {}));
|
|
26
|
+
// By far the most widely used filling rules for polygons are EvenOdd
|
|
27
|
+
// and NonZero, sometimes called Alternate and Winding respectively.
|
|
28
|
+
// https://en.wikipedia.org/wiki/Nonzero-rule
|
|
29
|
+
var FillRule;
|
|
30
|
+
(function (FillRule) {
|
|
31
|
+
FillRule[FillRule["EvenOdd"] = 0] = "EvenOdd";
|
|
32
|
+
FillRule[FillRule["NonZero"] = 1] = "NonZero";
|
|
33
|
+
FillRule[FillRule["Positive"] = 2] = "Positive";
|
|
34
|
+
FillRule[FillRule["Negative"] = 3] = "Negative";
|
|
35
|
+
})(FillRule || (exports.FillRule = FillRule = {}));
|
|
36
|
+
// PointInPolygon
|
|
37
|
+
var PointInPolygonResult;
|
|
38
|
+
(function (PointInPolygonResult) {
|
|
39
|
+
PointInPolygonResult[PointInPolygonResult["IsOn"] = 0] = "IsOn";
|
|
40
|
+
PointInPolygonResult[PointInPolygonResult["IsInside"] = 1] = "IsInside";
|
|
41
|
+
PointInPolygonResult[PointInPolygonResult["IsOutside"] = 2] = "IsOutside";
|
|
42
|
+
})(PointInPolygonResult || (exports.PointInPolygonResult = PointInPolygonResult = {}));
|
|
43
|
+
var InternalClipper;
|
|
44
|
+
(function (InternalClipper) {
|
|
45
|
+
InternalClipper.MaxInt64 = 9223372036854775807n;
|
|
46
|
+
InternalClipper.MaxCoord = Number(InternalClipper.MaxInt64 / 4n);
|
|
47
|
+
InternalClipper.max_coord = InternalClipper.MaxCoord;
|
|
48
|
+
InternalClipper.min_coord = -InternalClipper.MaxCoord;
|
|
49
|
+
InternalClipper.Invalid64 = Number(InternalClipper.MaxInt64);
|
|
50
|
+
InternalClipper.floatingPointTolerance = 1E-12;
|
|
51
|
+
InternalClipper.defaultMinimumEdgeLength = 0.1;
|
|
52
|
+
function crossProduct(pt1, pt2, pt3) {
|
|
53
|
+
// typecast to avoid potential int overflow
|
|
54
|
+
return ((pt2.x - pt1.x) * (pt3.y - pt2.y) -
|
|
55
|
+
(pt2.y - pt1.y) * (pt3.x - pt2.x));
|
|
56
|
+
}
|
|
57
|
+
InternalClipper.crossProduct = crossProduct;
|
|
58
|
+
function crossProductSign(pt1, pt2, pt3) {
|
|
59
|
+
const a = pt2.x - pt1.x;
|
|
60
|
+
const b = pt3.y - pt2.y;
|
|
61
|
+
const c = pt2.y - pt1.y;
|
|
62
|
+
const d = pt3.x - pt2.x;
|
|
63
|
+
const ab = multiplyUInt64(Math.abs(a), Math.abs(b));
|
|
64
|
+
const cd = multiplyUInt64(Math.abs(c), Math.abs(d));
|
|
65
|
+
const signAB = triSign(a) * triSign(b);
|
|
66
|
+
const signCD = triSign(c) * triSign(d);
|
|
67
|
+
if (signAB === signCD) {
|
|
68
|
+
let result;
|
|
69
|
+
if (ab.hi64 === cd.hi64) {
|
|
70
|
+
if (ab.lo64 === cd.lo64)
|
|
71
|
+
return 0;
|
|
72
|
+
result = (ab.lo64 > cd.lo64) ? 1 : -1;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
result = (ab.hi64 > cd.hi64) ? 1 : -1;
|
|
76
|
+
}
|
|
77
|
+
return (signAB > 0) ? result : -result;
|
|
78
|
+
}
|
|
79
|
+
return (signAB > signCD) ? 1 : -1;
|
|
80
|
+
}
|
|
81
|
+
InternalClipper.crossProductSign = crossProductSign;
|
|
82
|
+
function checkPrecision(precision) {
|
|
83
|
+
if (precision < -8 || precision > 8) {
|
|
84
|
+
throw new Error("Error: Precision is out of range.");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
InternalClipper.checkPrecision = checkPrecision;
|
|
88
|
+
function isAlmostZero(value) {
|
|
89
|
+
return Math.abs(value) <= InternalClipper.floatingPointTolerance;
|
|
90
|
+
}
|
|
91
|
+
InternalClipper.isAlmostZero = isAlmostZero;
|
|
92
|
+
function triSign(x) {
|
|
93
|
+
return (x < 0) ? -1 : (x > 0) ? 1 : 0;
|
|
94
|
+
}
|
|
95
|
+
InternalClipper.triSign = triSign;
|
|
96
|
+
function multiplyUInt64(a, b) {
|
|
97
|
+
// Convert to BigInt for accurate 64-bit multiplication
|
|
98
|
+
const aBig = BigInt(a >>> 0); // Ensure unsigned
|
|
99
|
+
const bBig = BigInt(b >>> 0);
|
|
100
|
+
const x1 = (aBig & 0xffffffffn) * (bBig & 0xffffffffn);
|
|
101
|
+
const x2 = (aBig >> 32n) * (bBig & 0xffffffffn) + (x1 >> 32n);
|
|
102
|
+
const x3 = (aBig & 0xffffffffn) * (bBig >> 32n) + (x2 & 0xffffffffn);
|
|
103
|
+
const lobits = (x3 & 0xffffffffn) << 32n | (x1 & 0xffffffffn);
|
|
104
|
+
const hibits = (aBig >> 32n) * (bBig >> 32n) + (x2 >> 32n) + (x3 >> 32n);
|
|
105
|
+
return {
|
|
106
|
+
lo64: Number(lobits & 0xffffffffffffffffn),
|
|
107
|
+
hi64: Number(hibits & 0xffffffffffffffffn)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
InternalClipper.multiplyUInt64 = multiplyUInt64;
|
|
111
|
+
// returns true if (and only if) a * b == c * d
|
|
112
|
+
function productsAreEqual(a, b, c, d) {
|
|
113
|
+
// nb: unsigned values will be needed for CalcOverflowCarry()
|
|
114
|
+
const absA = Math.abs(a);
|
|
115
|
+
const absB = Math.abs(b);
|
|
116
|
+
const absC = Math.abs(c);
|
|
117
|
+
const absD = Math.abs(d);
|
|
118
|
+
// fast path for typical coordinates: 46341^2 < 2^31 (safe for JS number multiplication)
|
|
119
|
+
if (absA < 46341 && absB < 46341 && absC < 46341 && absD < 46341) {
|
|
120
|
+
return a * b === c * d;
|
|
121
|
+
}
|
|
122
|
+
const mulAb = multiplyUInt64(absA, absB);
|
|
123
|
+
const mulCd = multiplyUInt64(absC, absD);
|
|
124
|
+
// nb: it's important to differentiate 0 values here from other values
|
|
125
|
+
const signAb = triSign(a) * triSign(b);
|
|
126
|
+
const signCd = triSign(c) * triSign(d);
|
|
127
|
+
return mulAb.lo64 === mulCd.lo64 && mulAb.hi64 === mulCd.hi64 && signAb === signCd;
|
|
128
|
+
}
|
|
129
|
+
InternalClipper.productsAreEqual = productsAreEqual;
|
|
130
|
+
function isCollinear(pt1, sharedPt, pt2) {
|
|
131
|
+
const a = sharedPt.x - pt1.x;
|
|
132
|
+
const b = pt2.y - sharedPt.y;
|
|
133
|
+
const c = sharedPt.y - pt1.y;
|
|
134
|
+
const d = pt2.x - sharedPt.x;
|
|
135
|
+
// When checking for collinearity with very large coordinate values
|
|
136
|
+
// then ProductsAreEqual is more accurate than using CrossProduct.
|
|
137
|
+
return productsAreEqual(a, b, c, d);
|
|
138
|
+
}
|
|
139
|
+
InternalClipper.isCollinear = isCollinear;
|
|
140
|
+
function dotProduct(pt1, pt2, pt3) {
|
|
141
|
+
// typecast to avoid potential int overflow
|
|
142
|
+
return ((pt2.x - pt1.x) * (pt3.x - pt2.x) +
|
|
143
|
+
(pt2.y - pt1.y) * (pt3.y - pt2.y));
|
|
144
|
+
}
|
|
145
|
+
InternalClipper.dotProduct = dotProduct;
|
|
146
|
+
function crossProductD(vec1, vec2) {
|
|
147
|
+
return (vec1.y * vec2.x - vec2.y * vec1.x);
|
|
148
|
+
}
|
|
149
|
+
InternalClipper.crossProductD = crossProductD;
|
|
150
|
+
function dotProductD(vec1, vec2) {
|
|
151
|
+
return (vec1.x * vec2.x + vec1.y * vec2.y);
|
|
152
|
+
}
|
|
153
|
+
InternalClipper.dotProductD = dotProductD;
|
|
154
|
+
// Banker's rounding (round half to even) to match C# MidpointRounding.ToEven
|
|
155
|
+
function roundToEven(value) {
|
|
156
|
+
// Use the built-in behavior that's closer to C# MidpointRounding.ToEven
|
|
157
|
+
// JavaScript's Math.round actually implements "round half away from zero"
|
|
158
|
+
// but for most practical cases, the difference is minimal
|
|
159
|
+
const floor = Math.floor(value);
|
|
160
|
+
const diff = value - floor;
|
|
161
|
+
if (Math.abs(diff - 0.5) < 1e-10) {
|
|
162
|
+
// Exactly halfway - round to even
|
|
163
|
+
return floor % 2 === 0 ? floor : floor + 1;
|
|
164
|
+
}
|
|
165
|
+
return Math.round(value);
|
|
166
|
+
}
|
|
167
|
+
InternalClipper.roundToEven = roundToEven;
|
|
168
|
+
function checkCastInt64(val) {
|
|
169
|
+
if ((val >= InternalClipper.max_coord) || (val <= InternalClipper.min_coord))
|
|
170
|
+
return InternalClipper.Invalid64;
|
|
171
|
+
return Math.round(val);
|
|
172
|
+
}
|
|
173
|
+
InternalClipper.checkCastInt64 = checkCastInt64;
|
|
174
|
+
// GetLineIntersectPt - a 'true' result is non-parallel. The 'ip' will also
|
|
175
|
+
// be constrained to seg1. However, it's possible that 'ip' won't be inside
|
|
176
|
+
// seg2, even when 'ip' hasn't been constrained (ie 'ip' is inside seg1).
|
|
177
|
+
function getLineIntersectPt(ln1a, ln1b, ln2a, ln2b) {
|
|
178
|
+
const dy1 = (ln1b.y - ln1a.y);
|
|
179
|
+
const dx1 = (ln1b.x - ln1a.x);
|
|
180
|
+
const dy2 = (ln2b.y - ln2a.y);
|
|
181
|
+
const dx2 = (ln2b.x - ln2a.x);
|
|
182
|
+
const det = dy1 * dx2 - dy2 * dx1;
|
|
183
|
+
if (det === 0.0) {
|
|
184
|
+
return { intersects: false, point: { x: 0, y: 0 } };
|
|
185
|
+
}
|
|
186
|
+
const t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
|
|
187
|
+
let ip;
|
|
188
|
+
if (t <= 0.0) {
|
|
189
|
+
ip = { x: ln1a.x, y: ln1a.y }; // Create a copy to avoid mutating original
|
|
190
|
+
}
|
|
191
|
+
else if (t >= 1.0) {
|
|
192
|
+
ip = { x: ln1b.x, y: ln1b.y }; // Create a copy to avoid mutating original
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// avoid using constructor (and rounding too) as they affect performance
|
|
196
|
+
// Use Math.trunc to match C# (long) cast behavior which truncates towards zero
|
|
197
|
+
const rawX = ln1a.x + t * dx1;
|
|
198
|
+
const rawY = ln1a.y + t * dy1;
|
|
199
|
+
ip = {
|
|
200
|
+
x: Math.trunc(rawX),
|
|
201
|
+
y: Math.trunc(rawY)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return { intersects: true, point: ip };
|
|
205
|
+
}
|
|
206
|
+
InternalClipper.getLineIntersectPt = getLineIntersectPt;
|
|
207
|
+
function getLineIntersectPtD(ln1a, ln1b, ln2a, ln2b) {
|
|
208
|
+
const dy1 = ln1b.y - ln1a.y;
|
|
209
|
+
const dx1 = ln1b.x - ln1a.x;
|
|
210
|
+
const dy2 = ln2b.y - ln2a.y;
|
|
211
|
+
const dx2 = ln2b.x - ln2a.x;
|
|
212
|
+
const det = dy1 * dx2 - dy2 * dx1;
|
|
213
|
+
if (det === 0.0) {
|
|
214
|
+
return { success: false, ip: { x: 0, y: 0 } };
|
|
215
|
+
}
|
|
216
|
+
const t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
|
|
217
|
+
let ip;
|
|
218
|
+
if (t <= 0.0) {
|
|
219
|
+
ip = { ...ln1a };
|
|
220
|
+
}
|
|
221
|
+
else if (t >= 1.0) {
|
|
222
|
+
ip = { ...ln1b };
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
ip = {
|
|
226
|
+
x: ln1a.x + t * dx1,
|
|
227
|
+
y: ln1a.y + t * dy1
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return { success: true, ip };
|
|
231
|
+
}
|
|
232
|
+
InternalClipper.getLineIntersectPtD = getLineIntersectPtD;
|
|
233
|
+
function segsIntersect(seg1a, seg1b, seg2a, seg2b, inclusive = false) {
|
|
234
|
+
if (!inclusive) {
|
|
235
|
+
// Match C# fast path - use cross product multiplication
|
|
236
|
+
// This avoids floating point equality checks (safer than === 0)
|
|
237
|
+
return (crossProduct(seg1a, seg2a, seg2b) *
|
|
238
|
+
crossProduct(seg1b, seg2a, seg2b) < 0) &&
|
|
239
|
+
(crossProduct(seg2a, seg1a, seg1b) *
|
|
240
|
+
crossProduct(seg2b, seg1a, seg1b) < 0);
|
|
241
|
+
}
|
|
242
|
+
// Inclusive case - match C# implementation
|
|
243
|
+
const res1 = crossProduct(seg1a, seg2a, seg2b);
|
|
244
|
+
const res2 = crossProduct(seg1b, seg2a, seg2b);
|
|
245
|
+
if (res1 * res2 > 0)
|
|
246
|
+
return false;
|
|
247
|
+
const res3 = crossProduct(seg2a, seg1a, seg1b);
|
|
248
|
+
const res4 = crossProduct(seg2b, seg1a, seg1b);
|
|
249
|
+
if (res3 * res4 > 0)
|
|
250
|
+
return false;
|
|
251
|
+
// ensure NOT collinear
|
|
252
|
+
return (res1 !== 0 || res2 !== 0 || res3 !== 0 || res4 !== 0);
|
|
253
|
+
}
|
|
254
|
+
InternalClipper.segsIntersect = segsIntersect;
|
|
255
|
+
function getBounds(path) {
|
|
256
|
+
if (path.length === 0)
|
|
257
|
+
return { left: 0, top: 0, right: 0, bottom: 0 };
|
|
258
|
+
const result = {
|
|
259
|
+
left: Number.MAX_SAFE_INTEGER,
|
|
260
|
+
top: Number.MAX_SAFE_INTEGER,
|
|
261
|
+
right: Number.MIN_SAFE_INTEGER,
|
|
262
|
+
bottom: Number.MIN_SAFE_INTEGER
|
|
263
|
+
};
|
|
264
|
+
for (const pt of path) {
|
|
265
|
+
if (pt.x < result.left)
|
|
266
|
+
result.left = pt.x;
|
|
267
|
+
if (pt.x > result.right)
|
|
268
|
+
result.right = pt.x;
|
|
269
|
+
if (pt.y < result.top)
|
|
270
|
+
result.top = pt.y;
|
|
271
|
+
if (pt.y > result.bottom)
|
|
272
|
+
result.bottom = pt.y;
|
|
273
|
+
}
|
|
274
|
+
return result.left === Number.MAX_SAFE_INTEGER ?
|
|
275
|
+
{ left: 0, top: 0, right: 0, bottom: 0 } : result;
|
|
276
|
+
}
|
|
277
|
+
InternalClipper.getBounds = getBounds;
|
|
278
|
+
function getClosestPtOnSegment(offPt, seg1, seg2) {
|
|
279
|
+
if (seg1.x === seg2.x && seg1.y === seg2.y)
|
|
280
|
+
return { x: seg1.x, y: seg1.y }; // Return copy, not reference
|
|
281
|
+
const dx = (seg2.x - seg1.x);
|
|
282
|
+
const dy = (seg2.y - seg1.y);
|
|
283
|
+
const q = ((offPt.x - seg1.x) * dx + (offPt.y - seg1.y) * dy) / ((dx * dx) + (dy * dy));
|
|
284
|
+
const qClamped = q < 0 ? 0 : (q > 1 ? 1 : q);
|
|
285
|
+
return {
|
|
286
|
+
// use Math.round to match the C# MidpointRounding.ToEven behavior
|
|
287
|
+
x: Math.round(seg1.x + qClamped * dx),
|
|
288
|
+
y: Math.round(seg1.y + qClamped * dy)
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
InternalClipper.getClosestPtOnSegment = getClosestPtOnSegment;
|
|
292
|
+
function pointInPolygon(pt, polygon) {
|
|
293
|
+
const len = polygon.length;
|
|
294
|
+
let start = 0;
|
|
295
|
+
if (len < 3)
|
|
296
|
+
return PointInPolygonResult.IsOutside;
|
|
297
|
+
while (start < len && polygon[start].y === pt.y)
|
|
298
|
+
start++;
|
|
299
|
+
if (start === len)
|
|
300
|
+
return PointInPolygonResult.IsOutside;
|
|
301
|
+
let isAbove = polygon[start].y < pt.y;
|
|
302
|
+
const startingAbove = isAbove;
|
|
303
|
+
let val = 0;
|
|
304
|
+
let i = start + 1;
|
|
305
|
+
let end = len;
|
|
306
|
+
while (true) {
|
|
307
|
+
if (i === end) {
|
|
308
|
+
if (end === 0 || start === 0)
|
|
309
|
+
break;
|
|
310
|
+
end = start;
|
|
311
|
+
i = 0;
|
|
312
|
+
}
|
|
313
|
+
if (isAbove) {
|
|
314
|
+
while (i < end && polygon[i].y < pt.y)
|
|
315
|
+
i++;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
while (i < end && polygon[i].y > pt.y)
|
|
319
|
+
i++;
|
|
320
|
+
}
|
|
321
|
+
if (i === end)
|
|
322
|
+
continue;
|
|
323
|
+
const curr = polygon[i];
|
|
324
|
+
const prev = i > 0 ? polygon[i - 1] : polygon[len - 1];
|
|
325
|
+
if (curr.y === pt.y) {
|
|
326
|
+
if (curr.x === pt.x || (curr.y === prev.y &&
|
|
327
|
+
((pt.x < prev.x) !== (pt.x < curr.x)))) {
|
|
328
|
+
return PointInPolygonResult.IsOn;
|
|
329
|
+
}
|
|
330
|
+
i++;
|
|
331
|
+
if (i === start)
|
|
332
|
+
break;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (pt.x < curr.x && pt.x < prev.x) {
|
|
336
|
+
// we're only interested in edges crossing on the left
|
|
337
|
+
}
|
|
338
|
+
else if (pt.x > prev.x && pt.x > curr.x) {
|
|
339
|
+
val = 1 - val; // toggle val
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const cps = crossProductSign(prev, curr, pt);
|
|
343
|
+
if (cps === 0)
|
|
344
|
+
return PointInPolygonResult.IsOn;
|
|
345
|
+
if ((cps < 0) === isAbove)
|
|
346
|
+
val = 1 - val;
|
|
347
|
+
}
|
|
348
|
+
isAbove = !isAbove;
|
|
349
|
+
i++;
|
|
350
|
+
}
|
|
351
|
+
if (isAbove === startingAbove) {
|
|
352
|
+
return val === 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
|
|
353
|
+
}
|
|
354
|
+
if (i === len)
|
|
355
|
+
i = 0;
|
|
356
|
+
const cps = i === 0 ?
|
|
357
|
+
crossProductSign(polygon[len - 1], polygon[0], pt) :
|
|
358
|
+
crossProductSign(polygon[i - 1], polygon[i], pt);
|
|
359
|
+
if (cps === 0)
|
|
360
|
+
return PointInPolygonResult.IsOn;
|
|
361
|
+
if ((cps < 0) === isAbove)
|
|
362
|
+
val = 1 - val;
|
|
363
|
+
return val === 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
|
|
364
|
+
}
|
|
365
|
+
InternalClipper.pointInPolygon = pointInPolygon;
|
|
366
|
+
function path2ContainsPath1(path1, path2) {
|
|
367
|
+
// we need to make some accommodation for rounding errors
|
|
368
|
+
// so we won't jump if the first vertex is found outside
|
|
369
|
+
let pip = PointInPolygonResult.IsOn;
|
|
370
|
+
for (const pt of path1) {
|
|
371
|
+
switch (pointInPolygon(pt, path2)) {
|
|
372
|
+
case PointInPolygonResult.IsOutside:
|
|
373
|
+
if (pip === PointInPolygonResult.IsOutside)
|
|
374
|
+
return false;
|
|
375
|
+
pip = PointInPolygonResult.IsOutside;
|
|
376
|
+
break;
|
|
377
|
+
case PointInPolygonResult.IsInside:
|
|
378
|
+
if (pip === PointInPolygonResult.IsInside)
|
|
379
|
+
return true;
|
|
380
|
+
pip = PointInPolygonResult.IsInside;
|
|
381
|
+
break;
|
|
382
|
+
default:
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// since path1's location is still equivocal, check its midpoint
|
|
387
|
+
const mp = getBounds(path1);
|
|
388
|
+
const midPt = {
|
|
389
|
+
x: Math.round((mp.left + mp.right) / 2),
|
|
390
|
+
y: Math.round((mp.top + mp.bottom) / 2)
|
|
391
|
+
};
|
|
392
|
+
return pointInPolygon(midPt, path2) !== PointInPolygonResult.IsOutside;
|
|
393
|
+
}
|
|
394
|
+
InternalClipper.path2ContainsPath1 = path2ContainsPath1;
|
|
395
|
+
})(InternalClipper || (exports.InternalClipper = InternalClipper = {}));
|
|
396
|
+
// Point64 utility functions
|
|
397
|
+
var Point64Utils;
|
|
398
|
+
(function (Point64Utils) {
|
|
399
|
+
function create(x = 0, y = 0) {
|
|
400
|
+
return { x: Math.round(x), y: Math.round(y) };
|
|
401
|
+
}
|
|
402
|
+
Point64Utils.create = create;
|
|
403
|
+
function fromPointD(pt) {
|
|
404
|
+
return { x: Math.round(pt.x), y: Math.round(pt.y) };
|
|
405
|
+
}
|
|
406
|
+
Point64Utils.fromPointD = fromPointD;
|
|
407
|
+
function scale(pt, scale) {
|
|
408
|
+
return {
|
|
409
|
+
x: Math.round(pt.x * scale),
|
|
410
|
+
y: Math.round(pt.y * scale)
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
Point64Utils.scale = scale;
|
|
414
|
+
function equals(a, b) {
|
|
415
|
+
return a.x === b.x && a.y === b.y;
|
|
416
|
+
}
|
|
417
|
+
Point64Utils.equals = equals;
|
|
418
|
+
function add(a, b) {
|
|
419
|
+
return { x: a.x + b.x, y: a.y + b.y };
|
|
420
|
+
}
|
|
421
|
+
Point64Utils.add = add;
|
|
422
|
+
function subtract(a, b) {
|
|
423
|
+
return { x: a.x - b.x, y: a.y - b.y };
|
|
424
|
+
}
|
|
425
|
+
Point64Utils.subtract = subtract;
|
|
426
|
+
function toString(pt) {
|
|
427
|
+
return `${pt.x},${pt.y} `;
|
|
428
|
+
}
|
|
429
|
+
Point64Utils.toString = toString;
|
|
430
|
+
})(Point64Utils || (exports.Point64Utils = Point64Utils = {}));
|
|
431
|
+
// PointD utility functions
|
|
432
|
+
var PointDUtils;
|
|
433
|
+
(function (PointDUtils) {
|
|
434
|
+
function create(x = 0, y = 0) {
|
|
435
|
+
return { x, y };
|
|
436
|
+
}
|
|
437
|
+
PointDUtils.create = create;
|
|
438
|
+
function fromPoint64(pt) {
|
|
439
|
+
return { x: pt.x, y: pt.y };
|
|
440
|
+
}
|
|
441
|
+
PointDUtils.fromPoint64 = fromPoint64;
|
|
442
|
+
function scale(pt, scale) {
|
|
443
|
+
return { x: pt.x * scale, y: pt.y * scale };
|
|
444
|
+
}
|
|
445
|
+
PointDUtils.scale = scale;
|
|
446
|
+
function equals(a, b) {
|
|
447
|
+
return InternalClipper.isAlmostZero(a.x - b.x) &&
|
|
448
|
+
InternalClipper.isAlmostZero(a.y - b.y);
|
|
449
|
+
}
|
|
450
|
+
PointDUtils.equals = equals;
|
|
451
|
+
function negate(pt) {
|
|
452
|
+
pt.x = -pt.x;
|
|
453
|
+
pt.y = -pt.y;
|
|
454
|
+
}
|
|
455
|
+
PointDUtils.negate = negate;
|
|
456
|
+
function toString(pt, precision = 2) {
|
|
457
|
+
return `${pt.x.toFixed(precision)},${pt.y.toFixed(precision)}`;
|
|
458
|
+
}
|
|
459
|
+
PointDUtils.toString = toString;
|
|
460
|
+
})(PointDUtils || (exports.PointDUtils = PointDUtils = {}));
|
|
461
|
+
// Rect64 utility functions
|
|
462
|
+
var Rect64Utils;
|
|
463
|
+
(function (Rect64Utils) {
|
|
464
|
+
function create(l = 0, t = 0, r = 0, b = 0) {
|
|
465
|
+
return { left: l, top: t, right: r, bottom: b };
|
|
466
|
+
}
|
|
467
|
+
Rect64Utils.create = create;
|
|
468
|
+
function createInvalid() {
|
|
469
|
+
return {
|
|
470
|
+
left: Number.MAX_SAFE_INTEGER,
|
|
471
|
+
top: Number.MAX_SAFE_INTEGER,
|
|
472
|
+
right: Number.MIN_SAFE_INTEGER,
|
|
473
|
+
bottom: Number.MIN_SAFE_INTEGER
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
Rect64Utils.createInvalid = createInvalid;
|
|
477
|
+
function width(rect) {
|
|
478
|
+
return rect.right - rect.left;
|
|
479
|
+
}
|
|
480
|
+
Rect64Utils.width = width;
|
|
481
|
+
function height(rect) {
|
|
482
|
+
return rect.bottom - rect.top;
|
|
483
|
+
}
|
|
484
|
+
Rect64Utils.height = height;
|
|
485
|
+
function isEmpty(rect) {
|
|
486
|
+
return rect.bottom <= rect.top || rect.right <= rect.left;
|
|
487
|
+
}
|
|
488
|
+
Rect64Utils.isEmpty = isEmpty;
|
|
489
|
+
function isValid(rect) {
|
|
490
|
+
return rect.left < Number.MAX_SAFE_INTEGER;
|
|
491
|
+
}
|
|
492
|
+
Rect64Utils.isValid = isValid;
|
|
493
|
+
function midPoint(rect) {
|
|
494
|
+
return {
|
|
495
|
+
x: Math.round((rect.left + rect.right) / 2),
|
|
496
|
+
y: Math.round((rect.top + rect.bottom) / 2)
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
Rect64Utils.midPoint = midPoint;
|
|
500
|
+
function contains(rect, pt) {
|
|
501
|
+
return pt.x > rect.left && pt.x < rect.right &&
|
|
502
|
+
pt.y > rect.top && pt.y < rect.bottom;
|
|
503
|
+
}
|
|
504
|
+
Rect64Utils.contains = contains;
|
|
505
|
+
function containsRect(rect, rec) {
|
|
506
|
+
return rec.left >= rect.left && rec.right <= rect.right &&
|
|
507
|
+
rec.top >= rect.top && rec.bottom <= rect.bottom;
|
|
508
|
+
}
|
|
509
|
+
Rect64Utils.containsRect = containsRect;
|
|
510
|
+
function intersects(rect, rec) {
|
|
511
|
+
return (Math.max(rect.left, rec.left) <= Math.min(rect.right, rec.right)) &&
|
|
512
|
+
(Math.max(rect.top, rec.top) <= Math.min(rect.bottom, rec.bottom));
|
|
513
|
+
}
|
|
514
|
+
Rect64Utils.intersects = intersects;
|
|
515
|
+
function asPath(rect) {
|
|
516
|
+
return [
|
|
517
|
+
{ x: rect.left, y: rect.top },
|
|
518
|
+
{ x: rect.right, y: rect.top },
|
|
519
|
+
{ x: rect.right, y: rect.bottom },
|
|
520
|
+
{ x: rect.left, y: rect.bottom }
|
|
521
|
+
];
|
|
522
|
+
}
|
|
523
|
+
Rect64Utils.asPath = asPath;
|
|
524
|
+
})(Rect64Utils || (exports.Rect64Utils = Rect64Utils = {}));
|
|
525
|
+
// RectD utility functions
|
|
526
|
+
var RectDUtils;
|
|
527
|
+
(function (RectDUtils) {
|
|
528
|
+
function create(l = 0, t = 0, r = 0, b = 0) {
|
|
529
|
+
return { left: l, top: t, right: r, bottom: b };
|
|
530
|
+
}
|
|
531
|
+
RectDUtils.create = create;
|
|
532
|
+
function createInvalid() {
|
|
533
|
+
return {
|
|
534
|
+
left: Number.MAX_VALUE,
|
|
535
|
+
top: Number.MAX_VALUE,
|
|
536
|
+
right: -Number.MAX_VALUE,
|
|
537
|
+
bottom: -Number.MAX_VALUE
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
RectDUtils.createInvalid = createInvalid;
|
|
541
|
+
function width(rect) {
|
|
542
|
+
return rect.right - rect.left;
|
|
543
|
+
}
|
|
544
|
+
RectDUtils.width = width;
|
|
545
|
+
function height(rect) {
|
|
546
|
+
return rect.bottom - rect.top;
|
|
547
|
+
}
|
|
548
|
+
RectDUtils.height = height;
|
|
549
|
+
function isEmpty(rect) {
|
|
550
|
+
return rect.bottom <= rect.top || rect.right <= rect.left;
|
|
551
|
+
}
|
|
552
|
+
RectDUtils.isEmpty = isEmpty;
|
|
553
|
+
function midPoint(rect) {
|
|
554
|
+
return {
|
|
555
|
+
x: (rect.left + rect.right) / 2,
|
|
556
|
+
y: (rect.top + rect.bottom) / 2
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
RectDUtils.midPoint = midPoint;
|
|
560
|
+
function contains(rect, pt) {
|
|
561
|
+
return pt.x > rect.left && pt.x < rect.right &&
|
|
562
|
+
pt.y > rect.top && pt.y < rect.bottom;
|
|
563
|
+
}
|
|
564
|
+
RectDUtils.contains = contains;
|
|
565
|
+
function containsRect(rect, rec) {
|
|
566
|
+
return rec.left >= rect.left && rec.right <= rect.right &&
|
|
567
|
+
rec.top >= rect.top && rec.bottom <= rect.bottom;
|
|
568
|
+
}
|
|
569
|
+
RectDUtils.containsRect = containsRect;
|
|
570
|
+
function intersects(rect, rec) {
|
|
571
|
+
return (Math.max(rect.left, rec.left) < Math.min(rect.right, rec.right)) &&
|
|
572
|
+
(Math.max(rect.top, rec.top) < Math.min(rect.bottom, rec.bottom));
|
|
573
|
+
}
|
|
574
|
+
RectDUtils.intersects = intersects;
|
|
575
|
+
function asPath(rect) {
|
|
576
|
+
return [
|
|
577
|
+
{ x: rect.left, y: rect.top },
|
|
578
|
+
{ x: rect.right, y: rect.top },
|
|
579
|
+
{ x: rect.right, y: rect.bottom },
|
|
580
|
+
{ x: rect.left, y: rect.bottom }
|
|
581
|
+
];
|
|
582
|
+
}
|
|
583
|
+
RectDUtils.asPath = asPath;
|
|
584
|
+
})(RectDUtils || (exports.RectDUtils = RectDUtils = {}));
|
|
585
|
+
// Path utility functions
|
|
586
|
+
var PathUtils;
|
|
587
|
+
(function (PathUtils) {
|
|
588
|
+
function toString64(path) {
|
|
589
|
+
let result = "";
|
|
590
|
+
for (const pt of path) {
|
|
591
|
+
result += Point64Utils.toString(pt);
|
|
592
|
+
}
|
|
593
|
+
return result + '\n';
|
|
594
|
+
}
|
|
595
|
+
PathUtils.toString64 = toString64;
|
|
596
|
+
function toStringD(path, precision = 2) {
|
|
597
|
+
let result = "";
|
|
598
|
+
for (const pt of path) {
|
|
599
|
+
result += PointDUtils.toString(pt, precision) + ", ";
|
|
600
|
+
}
|
|
601
|
+
if (result !== "")
|
|
602
|
+
result = result.slice(0, -2);
|
|
603
|
+
return result;
|
|
604
|
+
}
|
|
605
|
+
PathUtils.toStringD = toStringD;
|
|
606
|
+
function reverse64(path) {
|
|
607
|
+
return [...path].reverse();
|
|
608
|
+
}
|
|
609
|
+
PathUtils.reverse64 = reverse64;
|
|
610
|
+
function reverseD(path) {
|
|
611
|
+
return [...path].reverse();
|
|
612
|
+
}
|
|
613
|
+
PathUtils.reverseD = reverseD;
|
|
614
|
+
})(PathUtils || (exports.PathUtils = PathUtils = {}));
|
|
615
|
+
var PathsUtils;
|
|
616
|
+
(function (PathsUtils) {
|
|
617
|
+
function toString64(paths) {
|
|
618
|
+
let result = "";
|
|
619
|
+
for (const path of paths) {
|
|
620
|
+
result += PathUtils.toString64(path);
|
|
621
|
+
}
|
|
622
|
+
return result;
|
|
623
|
+
}
|
|
624
|
+
PathsUtils.toString64 = toString64;
|
|
625
|
+
function toStringD(paths, precision = 2) {
|
|
626
|
+
let result = "";
|
|
627
|
+
for (const path of paths) {
|
|
628
|
+
result += PathUtils.toStringD(path, precision) + "\n";
|
|
629
|
+
}
|
|
630
|
+
return result;
|
|
631
|
+
}
|
|
632
|
+
PathsUtils.toStringD = toStringD;
|
|
633
|
+
function reverse64(paths) {
|
|
634
|
+
return paths.map(path => PathUtils.reverse64(path));
|
|
635
|
+
}
|
|
636
|
+
PathsUtils.reverse64 = reverse64;
|
|
637
|
+
function reverseD(paths) {
|
|
638
|
+
return paths.map(path => PathUtils.reverseD(path));
|
|
639
|
+
}
|
|
640
|
+
PathsUtils.reverseD = reverseD;
|
|
641
|
+
})(PathsUtils || (exports.PathsUtils = PathsUtils = {}));
|
|
642
|
+
// Constants
|
|
643
|
+
exports.InvalidRect64 = Rect64Utils.createInvalid();
|
|
644
|
+
exports.InvalidRectD = RectDUtils.createInvalid();
|
|
645
|
+
//# sourceMappingURL=Core.js.map
|