@escapace/minimum-perimeter-triangle 0.1.0 → 0.2.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.
package/package.json CHANGED
@@ -1,41 +1,41 @@
1
1
  {
2
2
  "name": "@escapace/minimum-perimeter-triangle",
3
3
  "description": "",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "author": "escapace <opensource@escapace.com>",
6
6
  "bugs": "https://github.com/escapace/minimum-perimeter-triangle/issues",
7
7
  "devDependencies": {
8
8
  "@commitlint/cli": "17.4.4",
9
9
  "@commitlint/config-conventional": "17.4.4",
10
10
  "@ls-lint/ls-lint": "1.11.2",
11
- "@types/chai": "^4.3.4",
12
- "@types/mocha": "^10.0.1",
13
- "@types/node": "18.14.2",
14
- "@typescript-eslint/eslint-plugin": "5.54.0",
15
- "@typescript-eslint/parser": "5.54.0",
11
+ "@types/chai": "4.3.4",
12
+ "@types/mocha": "10.0.1",
13
+ "@types/node": "18.15.3",
14
+ "@typescript-eslint/eslint-plugin": "5.55.0",
15
+ "@typescript-eslint/parser": "5.55.0",
16
16
  "arg": "5.0.2",
17
17
  "c8": "7.13.0",
18
- "chai": "^4.3.7",
18
+ "chai": "4.3.7",
19
19
  "changelogithub": "0.12.7",
20
- "esbuild": "0.17.10",
21
- "eslint": "8.35.0",
22
- "eslint-config-escapace": "3.16.1",
23
- "eslint-config-prettier": "8.6.0",
20
+ "esbuild": "0.17.12",
21
+ "eslint": "8.36.0",
22
+ "eslint-config-escapace": "3.16.2",
23
+ "eslint-config-prettier": "8.7.0",
24
24
  "eslint-plugin-editorconfig": "4.0.2",
25
25
  "eslint-plugin-no-null": "1.0.2",
26
- "execa": "7.0.0",
26
+ "execa": "7.1.1",
27
27
  "fast-glob": "3.2.12",
28
28
  "fs-extra": "11.1.0",
29
29
  "husky": "8.0.3",
30
30
  "is-ci": "3.0.1",
31
- "lint-staged": "13.1.2",
32
- "mocha": "^10.2.0",
31
+ "lint-staged": "13.2.0",
32
+ "mocha": "10.2.0",
33
33
  "prettier": "2.8.4",
34
- "prettier-config-escapace": "1.0.4",
34
+ "prettier-config-escapace": "1.0.5",
35
35
  "semver": "7.3.8",
36
36
  "syncpack": "9.8.4",
37
- "ts-node": "^10.9.1",
38
- "typescript": "4.9.5"
37
+ "ts-node": "10.9.1",
38
+ "typescript": "5.0.2"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">= 18.2.0",
@@ -44,17 +44,15 @@
44
44
  "exports": {
45
45
  ".": {
46
46
  "import": "./lib/esm/index.mjs",
47
- "require": "./lib/cjs/index.cjs"
47
+ "types": "./lib/types/index.d.ts"
48
48
  }
49
49
  },
50
50
  "files": [
51
- "lib/cjs",
52
51
  "lib/esm",
53
52
  "lib/types"
54
53
  ],
55
54
  "homepage": "https://github.com/escapace/minimum-perimeter-triangle",
56
55
  "license": "MPL-2.0",
57
- "main": "lib/cjs/index.cjs",
58
56
  "module": "lib/esm/index.mjs",
59
57
  "private": false,
60
58
  "publishConfig": {
package/lib/cjs/index.cjs DELETED
@@ -1,590 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- lineTangentToHull: () => lineTangentToHull,
24
- minTriangle: () => minTriangle,
25
- minTriangleWithBase: () => minTriangleWithBase
26
- });
27
- module.exports = __toCommonJS(src_exports);
28
-
29
- // src/line.ts
30
- var Line = class {
31
- start;
32
- end;
33
- delta;
34
- constructor(start, end) {
35
- this.start = start;
36
- this.end = end;
37
- this.delta = end.minus(start);
38
- }
39
- /**
40
- * Length of a line is the length between its two defining points
41
- */
42
- get length() {
43
- return this.delta.norm;
44
- }
45
- evaluate(t) {
46
- return this.start.plus(this.delta.times(t));
47
- }
48
- distanceToPoint(p) {
49
- return Math.abs(p.cross(this.delta) - this.start.cross(this.end)) / this.delta.norm;
50
- }
51
- pointOnSide(p, err = 0) {
52
- const num = this.start.cross(this.end) - p.cross(this.delta);
53
- if (num === 0 || Math.abs(num) / this.delta.norm < err) {
54
- return 0 /* Top */;
55
- }
56
- return num > 0 ? 1 /* Left */ : -1 /* Right */;
57
- }
58
- pointOnTop(p, err) {
59
- return this.pointOnSide(p, err) === 0 /* Top */;
60
- }
61
- overlaps(that, err) {
62
- return this.pointOnTop(that.start, err) && this.pointOnTop(that.end, err);
63
- }
64
- /**
65
- * If alpha is less than deviationFromZeroAngle, the 2 lines are
66
- * considered parallel.
67
- * _______________________________
68
- * alpha (/
69
- * /
70
- * /
71
- * /
72
- */
73
- parallel(that, deviationFromZeroAngle) {
74
- const d = Math.abs(this.delta.cross(that.delta));
75
- return d === 0 || d < this.length * this.length * Math.sin(deviationFromZeroAngle);
76
- }
77
- intersectionParameter(that, err) {
78
- const d = this.delta.cross(that.delta);
79
- if (d === 0 || Math.abs(d) < err) {
80
- return null;
81
- }
82
- const dStart = this.start.minus(that.start);
83
- return that.delta.cross(dStart) / d;
84
- }
85
- closestPointParam(p) {
86
- return this.delta.dot(p.minus(this.start)) / this.delta.normSquared;
87
- }
88
- closestPoint(p) {
89
- return this.evaluate(this.closestPointParam(p));
90
- }
91
- intersectionPoint(that, err) {
92
- const t = this.intersectionParameter(that, err);
93
- return t === null ? null : this.evaluate(t);
94
- }
95
- };
96
-
97
- // src/vec2.ts
98
- var Vec2 = class {
99
- _x;
100
- _y;
101
- _normSquared;
102
- _norm;
103
- _normalized;
104
- constructor(x, y) {
105
- this._x = x;
106
- this._y = y;
107
- }
108
- times(s) {
109
- return new Vec2(this._x * s, this._y * s);
110
- }
111
- over(s) {
112
- return new Vec2(this._x / s, this._y / s);
113
- }
114
- get x() {
115
- return this._x;
116
- }
117
- get y() {
118
- return this._y;
119
- }
120
- plus(that) {
121
- return new Vec2(this._x + that._x, this._y + that._y);
122
- }
123
- minus(that) {
124
- return new Vec2(this._x - that._x, this._y - that._y);
125
- }
126
- get normSquared() {
127
- return this._normSquared === void 0 ? this._normSquared = this.dot(this) : this._normSquared;
128
- }
129
- get norm() {
130
- return this._norm === void 0 ? this._norm = Math.sqrt(this.normSquared) : this._norm;
131
- }
132
- get normalized() {
133
- return this._normalized === void 0 ? this._normalized = this.over(this.norm) : this._normalized;
134
- }
135
- dot(that) {
136
- return this._x * that._x + this._y * that._y;
137
- }
138
- cross(that) {
139
- return this._x * that._y - this._y * that._x;
140
- }
141
- equals(that, err) {
142
- if (err === 0) {
143
- return this.x === that.x && this.y === that.y;
144
- }
145
- return this.minus(that).normSquared < err * err;
146
- }
147
- normal() {
148
- return new Vec2(this._y, -this._x);
149
- }
150
- toString() {
151
- return `(${this.x}, ${this.y})`;
152
- }
153
- };
154
-
155
- // src/inscribe.ts
156
- var Wedge = class {
157
- leftArm;
158
- rightArm;
159
- isDegenerate;
160
- constructor(leftArm, rightArm, isDegenerate = false) {
161
- this.leftArm = leftArm;
162
- this.rightArm = rightArm;
163
- this.isDegenerate = isDegenerate;
164
- }
165
- static new(leftArm, rightArm, err) {
166
- if (leftArm === null || rightArm === null) {
167
- return null;
168
- }
169
- if (err !== 0 && leftArm.overlaps(rightArm, err)) {
170
- return null;
171
- }
172
- const deviationFromZeroAngle = 0.1 / (leftArm.length * rightArm.length);
173
- if (leftArm.parallel(rightArm, deviationFromZeroAngle)) {
174
- const middle = new Line(leftArm.evaluate(0.5), rightArm.evaluate(0.5));
175
- const p = middle.evaluate(0.5);
176
- const sideLeft = leftArm.pointOnSide(p, err);
177
- const sideRight = rightArm.pointOnSide(p, err);
178
- if (sideLeft === 0 /* Top */ || sideRight === 0 /* Top */) {
179
- throw new Error();
180
- }
181
- return sideLeft !== sideRight ? new Wedge(leftArm, rightArm, true) : new Wedge(leftArm, new Line(rightArm.end, rightArm.start));
182
- }
183
- const tLA = leftArm.intersectionParameter(rightArm, 0);
184
- const tRA = rightArm.intersectionParameter(leftArm, 0);
185
- if (tLA === 0.5 || tRA === 0.5) {
186
- return null;
187
- }
188
- const W = leftArm.evaluate(tLA);
189
- const eLA = tLA < 1 - tLA ? leftArm.end : leftArm.start;
190
- const eRA = tRA < 1 - tRA ? rightArm.end : rightArm.start;
191
- return new Wedge(new Line(W, eLA), new Line(W, eRA));
192
- }
193
- formTriangle(line, err) {
194
- const thin = this.leftArm.parallel(line, 0.1 / (this.leftArm.length * line.length)) || this.rightArm.parallel(line, 0.1 / (this.rightArm.length * line.length));
195
- if (thin) {
196
- return false;
197
- }
198
- const A = line.intersectionPoint(this.leftArm, 0);
199
- const B = line.intersectionPoint(this.rightArm, 0);
200
- if (this.isDegenerate) {
201
- return !A.equals(B, err);
202
- }
203
- const C = this.leftArm.intersectionPoint(this.rightArm, 0);
204
- return !C.equals(A, err) && !C.equals(B, err) && !A.equals(B, err) && !new Line(A, B).pointOnTop(C, err);
205
- }
206
- looselyContains(p, err) {
207
- const pLeft = this.leftArm.pointOnSide(p, err);
208
- const pRight = this.rightArm.pointOnSide(p, err);
209
- if (pLeft === 0 /* Top */ || pRight === 0 /* Top */) {
210
- return true;
211
- }
212
- if (pLeft === pRight) {
213
- return false;
214
- }
215
- return this.isDegenerate ? (
216
- // degenerate + different sides => true
217
- true
218
- ) : (
219
- // 2. (Because the arms intersect)
220
- // Projection params of the point onto the arms must be larger than 0
221
- this.leftArm.closestPointParam(p) >= 0 && this.rightArm.closestPointParam(p) >= 0
222
- );
223
- }
224
- strictlyContains(p, err) {
225
- const pLeft = this.leftArm.pointOnSide(p, err);
226
- const pRight = this.rightArm.pointOnSide(p, err);
227
- if (pLeft === 0 /* Top */ || pRight === 0 /* Top */) {
228
- return false;
229
- }
230
- if (pLeft === pRight) {
231
- return false;
232
- }
233
- return this.isDegenerate ? (
234
- // degenerate + different sides => true
235
- true
236
- ) : (
237
- // 2. (Because the arms intersect)
238
- // Projection params of the point onto the arms must be larger than 0
239
- this.leftArm.closestPointParam(p) >= 0 && this.rightArm.closestPointParam(p) >= 0
240
- );
241
- }
242
- // While fitting circles into a wedge
243
- // There are four distinct cases:
244
- // 1. Wedge is degenerate and additional element is a point
245
- // 2. Wedge is degenerate and additional element is a line
246
- // 3. Wedge is non-degenerate and additional element is a point
247
- // 4. Wedge is non-degenerate and additional element is a line
248
- // according to these assumptions, the following methods are named
249
- fit_Dp(p, err) {
250
- if (!this.strictlyContains(p, err)) {
251
- return null;
252
- }
253
- const A = this.rightArm.closestPoint(p);
254
- const Ap = this.leftArm.closestPoint(A);
255
- const I = A.plus(Ap).over(2);
256
- const r = A.minus(Ap).norm / 2;
257
- const a = this.rightArm.delta.normSquared;
258
- const b = I.minus(p).dot(this.rightArm.delta) * 2;
259
- const c = I.minus(p).normSquared - r * r;
260
- const discriminant = b * b - 4 * a * c;
261
- if (discriminant < (-10) ** -5) {
262
- return null;
263
- }
264
- const t = [];
265
- if (Math.abs(discriminant) < 10 ** -5) {
266
- t.push(-b / (2 * a));
267
- } else {
268
- t.push((-b + Math.sqrt(discriminant)) / (2 * a));
269
- t.push((-b - Math.sqrt(discriminant)) / (2 * a));
270
- }
271
- const result = [];
272
- t.forEach((t0) => {
273
- const O = this.rightArm.delta.times(t0).plus(I);
274
- result.push({
275
- circle: { centre: O, r },
276
- tangent: new Line(p, p.plus(O.minus(p).normal()))
277
- });
278
- });
279
- return result;
280
- }
281
- fit_Dl(l, err) {
282
- if (!this.formTriangle(l, err)) {
283
- return null;
284
- }
285
- const A = l.intersectionPoint(this.rightArm, 0);
286
- const B = l.intersectionPoint(this.leftArm, 0);
287
- const AB = new Line(A, B);
288
- const Ap = this.leftArm.closestPoint(A);
289
- const I = A.plus(Ap).over(2);
290
- const r = A.minus(Ap).norm / 2;
291
- const t1 = (AB.delta.cross(A.minus(I)) + r * AB.delta.norm) / AB.delta.cross(this.rightArm.delta);
292
- const t2 = (AB.delta.cross(A.minus(I)) - r * AB.delta.norm) / AB.delta.cross(this.rightArm.delta);
293
- const o1 = this.rightArm.delta.times(t1).plus(I);
294
- const o2 = this.rightArm.delta.times(t2).plus(I);
295
- return [
296
- {
297
- circle: { centre: o1, r },
298
- tangentParameter: l.closestPointParam(o1)
299
- },
300
- {
301
- circle: { centre: o2, r },
302
- tangentParameter: l.closestPointParam(o2)
303
- }
304
- ];
305
- }
306
- fit_NDp(p, err) {
307
- if (!this.strictlyContains(p, err)) {
308
- return null;
309
- }
310
- const C = this.leftArm.start;
311
- const A = this.leftArm.end;
312
- const B = this.rightArm.end;
313
- const a = C.minus(B).norm;
314
- const b = C.minus(A).norm;
315
- const D = A.minus(B).times(a / (a + b)).plus(B);
316
- const bisector = new Line(C, D);
317
- const eA = D.minus(C).normSquared - (A.minus(C).cross(D.minus(C)) / b) ** 2;
318
- const eB = D.minus(C).dot(C.minus(p)) * 2;
319
- const eC = C.minus(p).normSquared;
320
- const discriminant = eB * eB - 4 * eA * eC;
321
- if (discriminant < (-10) ** -5) {
322
- return null;
323
- }
324
- let O, r;
325
- if (Math.abs(discriminant) < 10 ** -5) {
326
- const t = -eB / (2 * eA);
327
- O = bisector.evaluate(t);
328
- r = O.minus(p).norm;
329
- } else {
330
- const t1 = (-eB + Math.sqrt(discriminant)) / (2 * eA);
331
- const t2 = (-eB - Math.sqrt(discriminant)) / (2 * eA);
332
- if (bisector.evaluate(t1).minus(p).normSquared > bisector.evaluate(t2).minus(p).normSquared) {
333
- O = bisector.evaluate(t1);
334
- r = bisector.evaluate(t1).minus(p).norm;
335
- } else {
336
- O = bisector.evaluate(t2);
337
- r = bisector.evaluate(t2).minus(p).norm;
338
- }
339
- }
340
- return [
341
- {
342
- circle: { centre: O, r },
343
- tangent: new Line(p, p.plus(O.minus(p).normal()))
344
- }
345
- ];
346
- }
347
- fit_NDl(l, err) {
348
- if (!this.formTriangle(l, err)) {
349
- return null;
350
- }
351
- const C = this.leftArm.start;
352
- const A = l.intersectionPoint(this.leftArm, 0);
353
- const B = l.intersectionPoint(this.rightArm, 0);
354
- const AC = new Line(A, C);
355
- const BC = new Line(B, C);
356
- const AB = new Line(A, B);
357
- const a = AC.length;
358
- const b = BC.length;
359
- const c = AB.length;
360
- const s = (a + b + c) / 2;
361
- if (s * (s - a) * (s - b) / (s - c) < 0) {
362
- return null;
363
- }
364
- const r = Math.sqrt(s * (s - a) * (s - b) / (s - c));
365
- const det = AB.delta.cross(AC.delta);
366
- const lhsAll = [
367
- new Vec2(B.cross(A) + r * c, C.cross(A) + r * a),
368
- new Vec2(B.cross(A) + r * c, C.cross(A) - r * a),
369
- new Vec2(B.cross(A) - r * c, C.cross(A) + r * a),
370
- new Vec2(B.cross(A) - r * c, C.cross(A) - r * a)
371
- ];
372
- const OAll = [];
373
- lhsAll.forEach((lhs) => {
374
- OAll.push(
375
- new Vec2(
376
- new Vec2(AB.delta.x, AC.delta.x).cross(lhs),
377
- new Vec2(AB.delta.y, AC.delta.y).cross(lhs)
378
- ).over(-det)
379
- );
380
- });
381
- let o = null;
382
- const dists = [];
383
- for (const O of OAll) {
384
- dists.push({
385
- raw: Math.abs(BC.distanceToPoint(O) - r),
386
- norm: Math.abs(BC.distanceToPoint(O) / r - 1)
387
- });
388
- const absoluteError = Math.abs(BC.distanceToPoint(O) - r);
389
- const relativeError = Math.abs(BC.distanceToPoint(O) / r - 1);
390
- if ((absoluteError < 10 ** -5 || relativeError < 10 ** -5) && AC.pointOnSide(O) !== BC.pointOnSide(O)) {
391
- o = O;
392
- break;
393
- }
394
- }
395
- let msg = "";
396
- if (o === null) {
397
- msg = "fit_NDl, centre is undefined";
398
- for (let i = 0; i < OAll.length; i++) {
399
- msg += `centre: (${OAll[i].x}, ${OAll[i].y}), r: ${r}, dist raw: ${dists[i].raw}, dist norm: ${dists[i].norm}
400
- `;
401
- }
402
- }
403
- if (o === null) {
404
- throw new Error(msg);
405
- }
406
- return [
407
- {
408
- circle: { centre: o, r },
409
- tangentParameter: l.closestPointParam(o)
410
- }
411
- ];
412
- }
413
- fitCircles(element, err) {
414
- if (element instanceof Vec2) {
415
- return this.isDegenerate ? this.fit_Dp(element, err) : this.fit_NDp(element, err);
416
- }
417
- if (element instanceof Line) {
418
- return this.isDegenerate ? this.fit_Dl(element instanceof Line ? element : element, err) : this.fit_NDl(element instanceof Line ? element : element, err);
419
- }
420
- return null;
421
- }
422
- toString() {
423
- return `LA: ${this.leftArm.start.toString()} --> ${this.leftArm.end.toString()}
424
- RA: ${this.rightArm.start.toString()} --> ${this.rightArm.end.toString()}`;
425
- }
426
- };
427
-
428
- // src/index.ts
429
- function lineTangentToHull(line, points, halo) {
430
- let holds = true;
431
- let side = 0 /* Top */;
432
- let k = 0;
433
- while (side === 0 /* Top */ && k < points.length) {
434
- side = line.pointOnSide(points[k], halo);
435
- k++;
436
- }
437
- for (let i = k; i < points.length; i++) {
438
- const testSide = line.pointOnSide(points[i], halo);
439
- if (testSide === 0 /* Top */) {
440
- continue;
441
- }
442
- if (testSide !== side) {
443
- holds = false;
444
- break;
445
- }
446
- }
447
- return { holds, side };
448
- }
449
- function findEnclosingSide(wedge, startVertex, endVertex, points, halo) {
450
- let side = null;
451
- let stopVertex = startVertex;
452
- let vertex = startVertex;
453
- while (side === null && vertex > endVertex) {
454
- const p1 = points[vertex];
455
- const p2 = points[vertex - 1];
456
- const edge = new Line(p1, p2);
457
- const circlesEdge = wedge.fitCircles(edge, halo);
458
- if (circlesEdge !== null) {
459
- let tangentParameter = 100;
460
- if (wedge.isDegenerate) {
461
- let sidedness = 0 /* Top */;
462
- let k = 0;
463
- while (sidedness === 0 /* Top */ && k < points.length) {
464
- sidedness = edge.pointOnSide(points[k], halo);
465
- k++;
466
- }
467
- tangentParameter = edge.pointOnSide(circlesEdge[0].circle.centre) !== sidedness ? circlesEdge[0].tangentParameter : circlesEdge[1].tangentParameter;
468
- } else {
469
- tangentParameter = circlesEdge[0].tangentParameter;
470
- }
471
- if (tangentParameter > 0 && tangentParameter < 1) {
472
- const Y = edge.evaluate(tangentParameter);
473
- const joint = wedge.leftArm.intersectionPoint(edge, halo);
474
- side = new Line(joint, Y);
475
- }
476
- }
477
- if (side === null) {
478
- const circlesPoint = wedge.fitCircles(p2, halo);
479
- if (circlesPoint !== null) {
480
- let tangent;
481
- if (wedge.isDegenerate) {
482
- let sidedness = 0 /* Top */;
483
- let k = 0;
484
- while (sidedness === 0 /* Top */ && k < points.length) {
485
- sidedness = circlesPoint[0].tangent.pointOnSide(points[k], halo);
486
- k++;
487
- }
488
- tangent = circlesPoint[0].tangent.pointOnSide(
489
- circlesPoint[0].circle.centre,
490
- halo
491
- ) !== sidedness ? circlesPoint[0].tangent : circlesPoint[1].tangent;
492
- } else {
493
- tangent = circlesPoint[0].tangent;
494
- }
495
- if (lineTangentToHull(tangent, points, halo).holds) {
496
- const joint = wedge.leftArm.intersectionPoint(tangent, halo);
497
- side = new Line(joint, p2);
498
- }
499
- }
500
- }
501
- stopVertex = vertex;
502
- vertex--;
503
- }
504
- return side === null ? null : { side, stopVertex };
505
- }
506
- function findAntipode(points) {
507
- let farthestIndex = 0;
508
- let farthestDist = 0;
509
- for (let i = 0, n = points.length; i < n; i++) {
510
- const testDist = new Line(points[0], points[n - 1]).distanceToPoint(
511
- points[i]
512
- );
513
- if (testDist > farthestDist) {
514
- farthestDist = testDist;
515
- farthestIndex = i;
516
- }
517
- }
518
- return farthestIndex;
519
- }
520
- function minTriangleWithBase(convexHull, err, tol) {
521
- let AB, AC;
522
- const n = convexHull.length;
523
- const BC = new Line(convexHull[0], convexHull[n - 1]);
524
- const antipodIndex = findAntipode(convexHull);
525
- const baseParallel = new Line(
526
- convexHull[antipodIndex],
527
- convexHull[antipodIndex].plus(BC.delta)
528
- );
529
- let wedge = Wedge.new(BC, baseParallel, err);
530
- let Pn = n - 1;
531
- let Qn = antipodIndex;
532
- do {
533
- const CQinfo = findEnclosingSide(wedge, Pn, antipodIndex, convexHull, err);
534
- if (CQinfo === null) {
535
- return null;
536
- }
537
- ;
538
- ({ side: AC, stopVertex: Pn } = CQinfo);
539
- wedge = Wedge.new(wedge.leftArm, AC, err);
540
- const BPinfo = findEnclosingSide(wedge, Qn, 0, convexHull, err);
541
- if (BPinfo === null) {
542
- return null;
543
- }
544
- ;
545
- ({ side: AB, stopVertex: Qn } = BPinfo);
546
- wedge = Wedge.new(wedge.leftArm, AB, err);
547
- } while (AB.length - AC.length > tol);
548
- const A = AC.intersectionPoint(AB, 0);
549
- const B = AB.start;
550
- const C = AC.start;
551
- return { A, B, C };
552
- }
553
- function minTriangle(convexHull, err, tol) {
554
- if (convexHull.length < 3) {
555
- return null;
556
- }
557
- if (convexHull.length === 3) {
558
- return { A: convexHull[0], B: convexHull[1], C: convexHull[2] };
559
- }
560
- const points = convexHull.map((p) => {
561
- return new Vec2(p.x, p.y);
562
- });
563
- let A = null;
564
- let B = null;
565
- let C = null;
566
- let perimeter = -1;
567
- let rotations = 0;
568
- while (rotations < points.length) {
569
- if (rotations > 0) {
570
- points.push(points.shift());
571
- }
572
- const triangle = minTriangleWithBase(points, err, tol);
573
- if (triangle !== null) {
574
- const { A: A1, B: B1, C: C1 } = triangle;
575
- const perimeter1 = A1.minus(B1).norm + B1.minus(C1).norm + C1.minus(A1).norm;
576
- if (perimeter1 < perimeter || perimeter === -1) {
577
- ;
578
- [A, B, C] = [A1, B1, C1];
579
- perimeter = perimeter1;
580
- }
581
- }
582
- rotations++;
583
- }
584
- return perimeter === -1 ? null : {
585
- A: { x: A.x, y: A.y },
586
- B: { x: B.x, y: B.y },
587
- C: { x: C.x, y: C.y }
588
- };
589
- }
590
- //# sourceMappingURL=index.cjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/index.ts", "../../src/line.ts", "../../src/vec2.ts", "../../src/inscribe.ts"],
4
- "sourcesContent": ["import * as Inscribe from './inscribe'\nimport { Line, Side } from './line'\nimport { Vec2 } from './vec2'\n\nexport function lineTangentToHull(\n line: Line,\n points: Vec2[],\n halo: number\n): { holds: boolean; side: number } {\n let holds = true\n let side = Side.Top\n\n let k = 0\n while (side === Side.Top && k < points.length) {\n side = line.pointOnSide(points[k], halo)\n k++\n }\n\n for (let i = k; i < points.length; i++) {\n const testSide = line.pointOnSide(points[i], halo)\n if (testSide === Side.Top) {\n continue\n }\n if (testSide !== side) {\n holds = false\n break\n }\n }\n\n return { holds, side }\n}\n\n/**\n * Solves an optimization problem of finding the shortest third side for a given wedge such that they\n * enclose the given convex hull.\n * Such side, if found, will be generated by a Line which start will lie on the left arm of the wedge\n * and end will be P or Q (as described in the reference to the main function).\n *\n * startVertex is used to define the edge we start from.\n * endVertex is the last possible vertex through which a circle can be fitted into the wedge\n * startVertex > endVertex\n */\nfunction findEnclosingSide(\n wedge: Inscribe.Wedge,\n startVertex: number,\n endVertex: number,\n points: Vec2[],\n halo: number\n): { side: Line; stopVertex: number } | null {\n // Enclosing side\n let side: Line | null = null\n // Keep strack at which vertex we stopped\n let stopVertex = startVertex\n\n let vertex = startVertex\n\n while (side === null && vertex > endVertex) {\n const p1 = points[vertex]\n const p2 = points[vertex - 1]\n\n // Edge can be constructed\n const edge = new Line(p1, p2)\n\n const circlesEdge = wedge.fitCircles(edge, halo)\n if (circlesEdge !== null) {\n // In case of a degenerate wedge there will be 2 circles.\n // In a more commong case of a regular wedge there will be only 1 circle.\n // In each case the circle has to touch the edge and not its extension.\n let tangentParameter = 100\n if (wedge.isDegenerate) {\n // Choose such a circle that it has its centre on a different side\n let sidedness = Side.Top\n let k = 0\n while (sidedness === Side.Top && k < points.length) {\n sidedness = edge.pointOnSide(points[k], halo)\n k++\n }\n\n tangentParameter =\n edge.pointOnSide(circlesEdge[0].circle.centre) !== sidedness\n ? circlesEdge[0].tangentParameter\n : circlesEdge[1].tangentParameter\n } else {\n tangentParameter = circlesEdge[0].tangentParameter\n }\n\n // Check whether this tangent point belongs to the edge\n if (tangentParameter > 0 && tangentParameter < 1) {\n const Y = edge.evaluate(tangentParameter)\n const joint = wedge.leftArm.intersectionPoint(edge, halo)!\n side = new Line(joint, Y)\n }\n }\n\n // Investigate for p2 to generate the side if it's still not found\n if (side === null) {\n const circlesPoint = wedge.fitCircles(p2, halo)\n if (circlesPoint !== null) {\n // In case of a degenerate wedge there will be 2 circles.\n // In a more commong case of a regular wedge there will be only 1 circle.\n // In each case the circle has to also be tangent to the hull.\n let tangent: Line\n if (wedge.isDegenerate) {\n // Choose such a circle that it has its centre on a different side\n let sidedness = Side.Top\n let k = 0\n while (sidedness === Side.Top && k < points.length) {\n sidedness = circlesPoint[0].tangent.pointOnSide(points[k], halo)\n k++\n }\n\n tangent =\n circlesPoint[0].tangent.pointOnSide(\n circlesPoint[0].circle.centre,\n halo\n ) !== sidedness\n ? circlesPoint[0].tangent\n : circlesPoint[1].tangent\n } else {\n tangent = circlesPoint[0].tangent\n }\n\n // `tangent` is such that:\n // 1. it is tangent to a circle going through p1,\n // 2. it separates the centre of this circle and the hull points\n // If it is also tangent to the hull => it generates the side\n if (lineTangentToHull(tangent, points, halo).holds) {\n const joint = wedge.leftArm.intersectionPoint(tangent, halo)!\n side = new Line(joint, p2)\n }\n }\n }\n stopVertex = vertex\n vertex--\n }\n\n return side === null ? null : { side, stopVertex }\n}\n\nfunction findAntipode(points: Vec2[]) {\n // find the farthest point from the start and end point of the range\n let farthestIndex = 0\n let farthestDist = 0\n\n for (let i = 0, n: number = points.length; i < n; i++) {\n //check if considered point is farther than farthest\n const testDist: number = new Line(points[0], points[n - 1]).distanceToPoint(\n points[i]\n )\n if (testDist > farthestDist) {\n farthestDist = testDist\n farthestIndex = i\n }\n }\n\n return farthestIndex\n}\n\n/**\n * Finds a minimal perimeter triangle enclosing a convex hull of an _arc_ trace\n * The longest side of the hull is considered to be a bottom of the triangle and\n * _is fixed_. This procedure is tailored from the generic algorithm given in\n * http://scholar.uwindsor.ca/cgi/viewcontent.cgi?article=2527&context=etd\n * starting from p. 22; In the notation of the generic algorithm BC is fixed\n */\nexport function minTriangleWithBase(\n convexHull: Vec2[],\n err: number,\n tol: number\n): { A: Vec2; B: Vec2; C: Vec2 } | null {\n // Sides of the triangle\n let AB: Line, AC: Line\n\n // The arrangement of the points assures that the base is formed by the first\n // and the last point of the hull\n const n = convexHull.length\n const BC = new Line(convexHull[0], convexHull[n - 1])\n\n // Find the antipodal point to the base, i.e. the farthest point\n const antipodIndex = findAntipode(convexHull)\n const baseParallel = new Line(\n convexHull[antipodIndex],\n convexHull[antipodIndex].plus(BC.delta)\n )!\n\n // Bootstrap the algorithm with a degenerate wedge\n let wedge = Inscribe.Wedge.new(BC, baseParallel, err)!\n\n // Progress of the algorithm through the verices (see ref.)\n let Pn = n - 1\n let Qn = antipodIndex\n\n do {\n //iterations\n\n const CQinfo = findEnclosingSide(wedge, Pn, antipodIndex, convexHull, err)\n if (CQinfo === null) {\n return null\n }\n ;({ side: AC, stopVertex: Pn } = CQinfo)\n\n // FYI: Q = AC.end;\n\n // reconstruct the wedge with left arm as is and right arm being the recently found side\n wedge = Inscribe.Wedge.new(wedge.leftArm, AC, err)!\n\n const BPinfo = findEnclosingSide(wedge, Qn, 0, convexHull, err)\n if (BPinfo === null) {\n return null\n }\n ;({ side: AB, stopVertex: Qn } = BPinfo)\n\n // FYI: P = AB.end;\n\n wedge = Inscribe.Wedge.new(wedge.leftArm, AB, err)!\n\n // By design |AB| >= |AC| (see ref.), stop when they are close\n } while (AB.length - AC.length > tol)\n\n const A = AC.intersectionPoint(AB, 0)!\n const B = AB.start\n const C = AC.start\n\n return { A, B, C }\n}\n\nexport function minTriangle(\n convexHull: Array<{ x: number; y: number }>,\n err: number,\n tol: number\n): {\n A: { x: number; y: number }\n B: { x: number; y: number }\n C: { x: number; y: number }\n} | null {\n if (convexHull.length < 3) {\n return null\n }\n\n if (convexHull.length === 3) {\n return { A: convexHull[0], B: convexHull[1], C: convexHull[2] }\n }\n\n const points = convexHull.map((p: { x: number; y: number }) => {\n return new Vec2(p.x, p.y)\n })\n\n let A: Vec2 | null = null\n let B: Vec2 | null = null\n let C: Vec2 | null = null\n let perimeter = -1\n\n let rotations = 0\n\n while (rotations < points.length) {\n // rotate array of points\n if (rotations > 0) {\n points.push(points.shift()!)\n }\n\n // re-calculate the triangle\n const triangle = minTriangleWithBase(points, err, tol)\n\n //assert triangle is found\n if (triangle !== null) {\n const { A: A1, B: B1, C: C1 } = triangle\n\n const perimeter1 =\n A1.minus(B1).norm + B1.minus(C1).norm + C1.minus(A1).norm\n if (perimeter1 < perimeter || perimeter === -1) {\n ;[A, B, C] = [A1, B1, C1]\n perimeter = perimeter1\n }\n }\n\n rotations++\n }\n\n return perimeter === -1\n ? null\n : {\n A: { x: A!.x, y: A!.y },\n B: { x: B!.x, y: B!.y },\n C: { x: C!.x, y: C!.y }\n }\n}\n", "import { Vec2 } from './vec2'\n\nexport enum Side {\n Right = -1,\n Top = 0,\n Left = 1\n}\n\nexport class Line {\n readonly start: Vec2\n readonly end: Vec2\n readonly delta: Vec2\n\n constructor(start: Vec2, end: Vec2) {\n this.start = start\n this.end = end\n this.delta = end.minus(start)\n }\n\n /**\n * Length of a line is the length between its two defining points\n */\n get length(): number {\n return this.delta.norm\n }\n\n evaluate(t: number): Vec2 {\n return this.start.plus(this.delta.times(t))\n }\n\n distanceToPoint(p: Vec2): number {\n return (\n Math.abs(p.cross(this.delta) - this.start.cross(this.end)) /\n this.delta.norm\n )\n }\n\n pointOnSide(p: Vec2, err = 0): number {\n const num = this.start.cross(this.end) - p.cross(this.delta)\n if (num === 0 || Math.abs(num) / this.delta.norm < err) {\n return Side.Top\n }\n return num > 0 ? Side.Left : Side.Right\n }\n\n pointOnTop(p: Vec2, err: number): boolean {\n return this.pointOnSide(p, err) === Side.Top\n }\n\n overlaps(that: Line, err: number): boolean {\n return this.pointOnTop(that.start, err) && this.pointOnTop(that.end, err)\n }\n\n /**\n * If alpha is less than deviationFromZeroAngle, the 2 lines are\n * considered parallel.\n * _______________________________\n * alpha (/\n * /\n * /\n * /\n */\n parallel(that: Line, deviationFromZeroAngle: number): boolean {\n const d: number = Math.abs(this.delta.cross(that.delta))\n //https://en.wikipedia.org/wiki/Cross_product#Geometric_meaning\n return (\n d === 0 ||\n d < this.length * this.length * Math.sin(deviationFromZeroAngle)\n )\n }\n\n intersectionParameter(that: Line, err: number): number | null {\n const d = this.delta.cross(that.delta)\n if (d === 0 || Math.abs(d) < err) {\n return null // lines are parallel\n }\n const dStart: Vec2 = this.start.minus(that.start)\n return that.delta.cross(dStart) / d\n }\n\n closestPointParam(p: Vec2): number {\n return this.delta.dot(p.minus(this.start)) / this.delta.normSquared\n }\n\n closestPoint(p: Vec2): Vec2 {\n return this.evaluate(this.closestPointParam(p))\n }\n\n intersectionPoint(that: Line, err: number): Vec2 | null {\n const t = this.intersectionParameter(that, err)\n return t === null ? null : this.evaluate(t)\n }\n}\n", "export class Vec2 {\n private readonly _x: number\n private readonly _y: number\n\n private _normSquared: number | undefined\n private _norm: number | undefined\n private _normalized: Vec2 | undefined\n\n constructor(x: number, y: number) {\n this._x = x\n this._y = y\n }\n\n times(s: number): Vec2 {\n return new Vec2(this._x * s, this._y * s)\n }\n\n over(s: number): Vec2 {\n return new Vec2(this._x / s, this._y / s)\n }\n\n get x(): number {\n return this._x\n }\n\n get y(): number {\n return this._y\n }\n\n plus(that: Vec2): Vec2 {\n return new Vec2(this._x + that._x, this._y + that._y)\n }\n\n minus(that: Vec2): Vec2 {\n return new Vec2(this._x - that._x, this._y - that._y)\n }\n\n get normSquared(): number {\n return this._normSquared === undefined\n ? (this._normSquared = this.dot(this))\n : this._normSquared\n }\n\n get norm(): number {\n return this._norm === undefined\n ? (this._norm = Math.sqrt(this.normSquared))\n : this._norm\n }\n\n get normalized(): Vec2 {\n return this._normalized === undefined\n ? (this._normalized = this.over(this.norm))\n : this._normalized\n }\n\n dot(that: Vec2): number {\n return this._x * that._x + this._y * that._y\n }\n\n cross(that: Vec2): number {\n return this._x * that._y - this._y * that._x\n }\n\n equals(that: Vec2, err: number): boolean {\n if (err === 0) {\n return this.x === that.x && this.y === that.y\n }\n return this.minus(that).normSquared < err * err\n }\n\n normal(): Vec2 {\n return new Vec2(this._y, -this._x)\n }\n\n toString(): string {\n return `(${this.x}, ${this.y})`\n }\n}\n", "import { Line, Side } from './line'\nimport { Vec2 } from './vec2'\n\nexport interface Circle {\n centre: Vec2\n r: number\n}\n\n/**\n * Class describing a wedge.\n * Wedge can be degenerate, i.e., its arms are parallel,\n * in this case they must point in the same direction\n */\nexport class Wedge {\n readonly leftArm: Line\n readonly rightArm: Line\n readonly isDegenerate: boolean\n\n private constructor(leftArm: Line, rightArm: Line, isDegenerate = false) {\n this.leftArm = leftArm\n this.rightArm = rightArm\n this.isDegenerate = isDegenerate\n }\n\n static new(leftArm: Line, rightArm: Line, err: number): Wedge | null {\n if (leftArm === null || rightArm === null) {\n return null\n }\n\n if (err !== 0 && leftArm.overlaps(rightArm, err)) {\n return null\n }\n\n // Check if they are parallel\n // Such value of deviation ensure that angle in between the Lines regardless\n // their lengths is 0.1 radians\n const deviationFromZeroAngle = 0.1 / (leftArm.length * rightArm.length)\n if (leftArm.parallel(rightArm, deviationFromZeroAngle)) {\n // Check if they point in the same direction\n // middle is non-null due to the overlap check\n const middle = new Line(leftArm.evaluate(0.5), rightArm.evaluate(0.5))\n const p = middle.evaluate(0.5)\n // Now p lies in between the arms\n // If arms point in the same direction p must be on the right of one and the left of another\n // --------*------------>\n // \\\n // \\\n // * p\n // \\\n // -------*----------->\n const sideLeft = leftArm.pointOnSide(p, err)\n const sideRight = rightArm.pointOnSide(p, err)\n if (sideLeft === Side.Top || sideRight === Side.Top) {\n throw new Error()\n }\n\n return sideLeft !== sideRight\n ? new Wedge(leftArm, rightArm, true)\n : new Wedge(leftArm, new Line(rightArm.end, rightArm.start))\n }\n\n // extensions of the wedge intersect, extend or cut the sides appropriately\n // err is set to 0 because we have already established that they intersect under appropriate angle\n const tLA = leftArm.intersectionParameter(rightArm, 0)!\n const tRA = rightArm.intersectionParameter(leftArm, 0)!\n\n // If it's impossible to tell the excess that need to be cut\n if (tLA === 0.5 || tRA === 0.5) {\n return null\n }\n\n // W will be the angle point of the wedge\n const W = leftArm.evaluate(tLA)\n\n // Arrange the arms in a way that they point away from W.\n // Make sure that after the cut, W and corresponding points are at least err distance apart\n const eLA = tLA < 1 - tLA ? leftArm.end : leftArm.start\n\n const eRA = tRA < 1 - tRA ? rightArm.end : rightArm.start\n\n return new Wedge(new Line(W, eLA), new Line(W, eRA))\n }\n\n formTriangle(line: Line, err: number): boolean {\n const thin =\n this.leftArm.parallel(line, 0.1 / (this.leftArm.length * line.length)) ||\n this.rightArm.parallel(line, 0.1 / (this.rightArm.length * line.length))\n if (thin) {\n return false\n }\n\n const A = line.intersectionPoint(this.leftArm, 0)!\n const B = line.intersectionPoint(this.rightArm, 0)!\n\n if (this.isDegenerate) {\n return !A.equals(B, err)\n }\n\n const C = this.leftArm.intersectionPoint(this.rightArm, 0)!\n\n return (\n !C.equals(A, err) &&\n !C.equals(B, err) &&\n !A.equals(B, err) &&\n !new Line(A, B).pointOnTop(C, err)\n )\n }\n\n looselyContains(p: Vec2, err: number): boolean {\n const pLeft = this.leftArm.pointOnSide(p, err)\n const pRight = this.rightArm.pointOnSide(p, err)\n\n if (pLeft === Side.Top || pRight === Side.Top) {\n return true\n }\n\n // Point is on neither arms; To be within the wedge it:\n // 1. must lie on different sides w.r.t. the arms\n if (pLeft === pRight) {\n return false\n }\n\n return this.isDegenerate\n ? // degenerate + different sides => true\n true\n : // 2. (Because the arms intersect)\n // Projection params of the point onto the arms must be larger than 0\n this.leftArm.closestPointParam(p) >= 0 &&\n this.rightArm.closestPointParam(p) >= 0\n }\n\n strictlyContains(p: Vec2, err: number): boolean {\n const pLeft = this.leftArm.pointOnSide(p, err)\n const pRight = this.rightArm.pointOnSide(p, err)\n\n if (pLeft === Side.Top || pRight === Side.Top) {\n return false\n }\n\n // Point is on neither arms; To be within the wedge it:\n // 1. must lie on different sides w.r.t. the arms\n if (pLeft === pRight) {\n return false\n }\n\n return this.isDegenerate\n ? // degenerate + different sides => true\n true\n : // 2. (Because the arms intersect)\n // Projection params of the point onto the arms must be larger than 0\n this.leftArm.closestPointParam(p) >= 0 &&\n this.rightArm.closestPointParam(p) >= 0\n }\n\n // While fitting circles into a wedge\n // There are four distinct cases:\n // 1. Wedge is degenerate and additional element is a point\n // 2. Wedge is degenerate and additional element is a line\n // 3. Wedge is non-degenerate and additional element is a point\n // 4. Wedge is non-degenerate and additional element is a line\n // according to these assumptions, the following methods are named\n\n private fit_Dp(\n p: Vec2,\n err: number\n ): Array<{ circle: Circle; tangent: Line }> | null {\n if (!this.strictlyContains(p, err)) {\n // point is not within the wedge\n return null\n }\n // Intersection are ensured by the previous check\n // => A and B are non-null-s\n // -----------------------*(Ap)---------------(left)------->\n // |\n // |\n // |\n // ----------------------*(I)-------------------\n // |\n // *(p)\n // |\n // -----------------------*(A)----(right)----------->\n\n const A = this.rightArm.closestPoint(p)\n const Ap = this.leftArm.closestPoint(A)\n\n // Line A-Ap is normal to both arms => I = (A+Ap)/2 is within arms of the wedge\n // and ||A-Ap|| is the radius of a circle to inscribe\n const I = A.plus(Ap).over(2)\n const r: number = A.minus(Ap).norm / 2\n // Now l = this.right_arm.delta*t + I = D_ra*t + I passes between the arms\n // We need to find Ic on l such that (Ic-p).(Ic-p) = r^2\n // |Ic-p|^2-r^2 = |D_ra*t + I - p|^2-r^2 = (D_ra*t + I - p).(D_ra*t + I - p)-r^2 =\n // |D_ra|^2 t^2 + 2*(I-P).D_ra*t + |I-p|^2 - r^2\n const a = this.rightArm.delta.normSquared\n const b = I.minus(p).dot(this.rightArm.delta) * 2\n const c = I.minus(p).normSquared - r * r\n const discriminant = b * b - 4 * a * c\n\n if (discriminant < (-10) ** -5) {\n // Account for possible computation errors\n // This should not happen if point is strictly contained within the wedge with a reasonable err\n return null\n }\n\n const t: number[] = []\n\n if (Math.abs(discriminant) < 10 ** -5) {\n t.push(-b / (2 * a))\n } else {\n t.push((-b + Math.sqrt(discriminant)) / (2 * a))\n t.push((-b - Math.sqrt(discriminant)) / (2 * a))\n }\n\n const result: Array<{ circle: Circle; tangent: Line }> = []\n\n t.forEach((t0: number) => {\n const O = this.rightArm.delta.times(t0).plus(I)\n result.push({\n circle: { centre: O, r },\n tangent: new Line(p, p.plus(O.minus(p).normal()))\n })\n })\n\n return result\n }\n\n private fit_Dl(\n l: Line,\n err: number\n ): Array<{ circle: Circle; tangentParameter: number }> | null {\n if (!this.formTriangle(l, err)) {\n // edge is parallel to the arms\n return null\n }\n\n // Intersection are ensured by the previous check\n // => A and B are non-null-s\n // ------(B)*-----*(Ap)---------------(left)------->\n // \\ |\n // \\ |\n // -----------\\--*(I)-------------------\n // \\ |\n // \\|\n // ---------------*(A)-------------(right)----------->\n const A = l.intersectionPoint(this.rightArm, 0)!\n const B = l.intersectionPoint(this.leftArm, 0)!\n\n const AB = new Line(A, B)!\n const Ap = this.leftArm.closestPoint(A)\n\n // Line A-Ap is normal to both arms => I = (A+Ap)/2 is within arms of the wedge\n // and ||A-Ap|| is the radius of a circle to inscribe\n const I = A.plus(Ap).over(2)\n const r = A.minus(Ap).norm / 2\n // Now this.right_arm.delta*t + I passes between the arms and parallel to them\n\n const t1 =\n (AB.delta.cross(A.minus(I)) + r * AB.delta.norm) /\n AB.delta.cross(this.rightArm.delta)\n const t2 =\n (AB.delta.cross(A.minus(I)) - r * AB.delta.norm) /\n AB.delta.cross(this.rightArm.delta)\n\n const o1: Vec2 = this.rightArm.delta.times(t1).plus(I)\n const o2: Vec2 = this.rightArm.delta.times(t2).plus(I)\n\n return [\n {\n circle: { centre: o1, r },\n tangentParameter: l.closestPointParam(o1)\n },\n {\n circle: { centre: o2, r },\n tangentParameter: l.closestPointParam(o2)\n }\n ]\n }\n\n private fit_NDp(\n p: Vec2,\n err: number\n ): Array<{ circle: Circle; tangent: Line }> | null {\n if (!this.strictlyContains(p, err)) {\n return null\n }\n // Point is in-between the wedge's arms\n\n // *(C)\n // /|\n // / |\n // / |\n // / |\n // / |\n // / *(p)|\n // / |\n // (A)* *(B)\n\n // By construction of wedge\n const C = this.leftArm.start // or = this.right_arm.end\n const A = this.leftArm.end\n const B = this.rightArm.end\n\n const a: number = C.minus(B).norm\n const b: number = C.minus(A).norm\n\n const D = A.minus(B)\n .times(a / (a + b))\n .plus(B)\n\n const bisector = new Line(C, D)\n\n const // coefficients for quadratic equations\n eA = D.minus(C).normSquared - (A.minus(C).cross(D.minus(C)) / b) ** 2\n const eB = D.minus(C).dot(C.minus(p)) * 2\n const eC = C.minus(p).normSquared\n const discriminant = eB * eB - 4 * eA * eC\n\n if (discriminant < (-10) ** -5) {\n // Account for possible computation errors\n // This should not happen if point is strictly contained within the wedge with a reasonable err\n return null\n }\n\n let O: Vec2, r: number\n\n if (Math.abs(discriminant) < 10 ** -5) {\n const t = -eB / (2 * eA)\n O = bisector.evaluate(t)\n r = O.minus(p).norm\n } else {\n const t1 = (-eB + Math.sqrt(discriminant)) / (2 * eA)\n const t2 = (-eB - Math.sqrt(discriminant)) / (2 * eA)\n // Pick the value corresponding to larger radius\n if (\n bisector.evaluate(t1).minus(p).normSquared >\n bisector.evaluate(t2).minus(p).normSquared\n ) {\n O = bisector.evaluate(t1)\n r = bisector.evaluate(t1).minus(p).norm\n } else {\n O = bisector.evaluate(t2)\n r = bisector.evaluate(t2).minus(p).norm\n }\n }\n\n return [\n {\n circle: { centre: O, r },\n tangent: new Line(p, p.plus(O.minus(p).normal()))\n }\n ]\n }\n\n private fit_NDl(\n l: Line,\n err: number\n ): Array<{ circle: Circle; tangentParameter: number }> | null {\n if (!this.formTriangle(l, err)) {\n // Edge is parallel to one of the arms\n return null\n }\n\n // Intersections are ensured by the previous check;\n // => A, B, and C are non-null-s\n // Form a triangle such that:\n // 1. vertex C is the wedge corner point\n const C = this.leftArm.start\n\n // 2. vertex A is the line-left-arm intersection\n const A = l.intersectionPoint(this.leftArm, 0)!\n\n // 3. vertex B is the line-right-arm intersection\n const B = l.intersectionPoint(this.rightArm, 0)!\n\n // => sides of the triangle are\n const AC = new Line(A, C)\n const BC = new Line(B, C)\n const AB = new Line(A, B)\n\n // lengths of sides\n const a = AC.length\n const b = BC.length\n const c = AB.length\n // half perimeter\n const s = (a + b + c) / 2\n\n if ((s * (s - a) * (s - b)) / (s - c) < 0) {\n // Case of a very thin triangle\n // Should not happen with a reasonable err\n return null\n }\n\n // We need to find an escribed circle touching AB\n // Radius of such circle\n const r = Math.sqrt((s * (s - a) * (s - b)) / (s - c))\n\n const det: number = AB.delta.cross(AC.delta)\n\n const lhsAll: Vec2[] = [\n new Vec2(B.cross(A) + r * c, C.cross(A) + r * a),\n new Vec2(B.cross(A) + r * c, C.cross(A) - r * a),\n new Vec2(B.cross(A) - r * c, C.cross(A) + r * a),\n new Vec2(B.cross(A) - r * c, C.cross(A) - r * a)\n ]\n\n // Possible centres\n const OAll: Vec2[] = []\n lhsAll.forEach((lhs: Vec2) => {\n OAll.push(\n new Vec2(\n new Vec2(AB.delta.x, AC.delta.x).cross(lhs),\n new Vec2(AB.delta.y, AC.delta.y).cross(lhs)\n ).over(-det)\n )\n })\n\n //choose the one touching the third side\n let o: Vec2 | null = null\n const dists: Array<{ raw: number; norm: number }> = []\n for (const O of OAll) {\n dists.push({\n raw: Math.abs(BC.distanceToPoint(O) - r),\n norm: Math.abs(BC.distanceToPoint(O) / r - 1)\n })\n // absolute error --- is the distance between circle and a line, this is the ultimate measure of closeness\n const absoluteError = Math.abs(BC.distanceToPoint(O) - r)\n // relative error --- is the distance between circle and a line normalized to the radius\n // this measure is usefull when circle has a very large radius and absolute error might grow\n const relativeError = Math.abs(BC.distanceToPoint(O) / r - 1)\n if (\n (absoluteError < 10 ** -5 || relativeError < 10 ** -5) &&\n AC.pointOnSide(O) !== BC.pointOnSide(O)\n ) {\n o = O\n break\n }\n }\n\n let msg = ''\n if (o === null) {\n msg = 'fit_NDl, centre is undefined'\n for (let i = 0; i < OAll.length; i++) {\n msg += `centre: (${OAll[i].x}, ${OAll[i].y}), r: ${r}, dist raw: ${dists[i].raw}, dist norm: ${dists[i].norm}\\n`\n }\n }\n if (o === null) {\n throw new Error(msg)\n }\n\n return [\n {\n circle: { centre: o, r },\n tangentParameter: l.closestPointParam(o)\n }\n ]\n }\n\n fitCircles(\n element: Vec2,\n err: number\n ): Array<{ circle: Circle; tangent: Line }> | null\n fitCircles(\n element: Line | Line,\n err: number\n ): Array<{ circle: Circle; tangentParameter: number }> | null\n fitCircles(element: Vec2 | Line | Line, err: number) {\n if (element instanceof Vec2) {\n return this.isDegenerate\n ? this.fit_Dp(element, err)\n : this.fit_NDp(element, err)\n }\n if (element instanceof Line) {\n return this.isDegenerate\n ? this.fit_Dl(element instanceof Line ? element : element, err)\n : this.fit_NDl(element instanceof Line ? element : element, err)\n }\n return null\n }\n\n toString(): string {\n return (\n `LA: ${this.leftArm.start.toString()} --> ${this.leftArm.end.toString()}\\n` +\n `RA: ${this.rightArm.start.toString()} --> ${this.rightArm.end.toString()}`\n )\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,IAAM,OAAN,MAAW;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,OAAa,KAAW;AAClC,SAAK,QAAQ;AACb,SAAK,MAAM;AACX,SAAK,QAAQ,IAAI,MAAM,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAiB;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,SAAS,GAAiB;AACxB,WAAO,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,EAC5C;AAAA,EAEA,gBAAgB,GAAiB;AAC/B,WACE,KAAK,IAAI,EAAE,MAAM,KAAK,KAAK,IAAI,KAAK,MAAM,MAAM,KAAK,GAAG,CAAC,IACzD,KAAK,MAAM;AAAA,EAEf;AAAA,EAEA,YAAY,GAAS,MAAM,GAAW;AACpC,UAAM,MAAM,KAAK,MAAM,MAAM,KAAK,GAAG,IAAI,EAAE,MAAM,KAAK,KAAK;AAC3D,QAAI,QAAQ,KAAK,KAAK,IAAI,GAAG,IAAI,KAAK,MAAM,OAAO,KAAK;AACtD,aAAO;AAAA,IACT;AACA,WAAO,MAAM,IAAI,eAAY;AAAA,EAC/B;AAAA,EAEA,WAAW,GAAS,KAAsB;AACxC,WAAO,KAAK,YAAY,GAAG,GAAG,MAAM;AAAA,EACtC;AAAA,EAEA,SAAS,MAAY,KAAsB;AACzC,WAAO,KAAK,WAAW,KAAK,OAAO,GAAG,KAAK,KAAK,WAAW,KAAK,KAAK,GAAG;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,MAAY,wBAAyC;AAC5D,UAAM,IAAY,KAAK,IAAI,KAAK,MAAM,MAAM,KAAK,KAAK,CAAC;AAEvD,WACE,MAAM,KACN,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,IAAI,sBAAsB;AAAA,EAEnE;AAAA,EAEA,sBAAsB,MAAY,KAA4B;AAC5D,UAAM,IAAI,KAAK,MAAM,MAAM,KAAK,KAAK;AACrC,QAAI,MAAM,KAAK,KAAK,IAAI,CAAC,IAAI,KAAK;AAChC,aAAO;AAAA,IACT;AACA,UAAM,SAAe,KAAK,MAAM,MAAM,KAAK,KAAK;AAChD,WAAO,KAAK,MAAM,MAAM,MAAM,IAAI;AAAA,EACpC;AAAA,EAEA,kBAAkB,GAAiB;AACjC,WAAO,KAAK,MAAM,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,IAAI,KAAK,MAAM;AAAA,EAC1D;AAAA,EAEA,aAAa,GAAe;AAC1B,WAAO,KAAK,SAAS,KAAK,kBAAkB,CAAC,CAAC;AAAA,EAChD;AAAA,EAEA,kBAAkB,MAAY,KAA0B;AACtD,UAAM,IAAI,KAAK,sBAAsB,MAAM,GAAG;AAC9C,WAAO,MAAM,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,EAC5C;AACF;;;AC5FO,IAAM,OAAN,MAAW;AAAA,EACC;AAAA,EACA;AAAA,EAET;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,GAAW,GAAW;AAChC,SAAK,KAAK;AACV,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,MAAM,GAAiB;AACrB,WAAO,IAAI,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK,CAAC;AAAA,EAC1C;AAAA,EAEA,KAAK,GAAiB;AACpB,WAAO,IAAI,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK,CAAC;AAAA,EAC1C;AAAA,EAEA,IAAI,IAAY;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,IAAY;AACd,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,KAAK,MAAkB;AACrB,WAAO,IAAI,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE;AAAA,EACtD;AAAA,EAEA,MAAM,MAAkB;AACtB,WAAO,IAAI,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE;AAAA,EACtD;AAAA,EAEA,IAAI,cAAsB;AACxB,WAAO,KAAK,iBAAiB,SACxB,KAAK,eAAe,KAAK,IAAI,IAAI,IAClC,KAAK;AAAA,EACX;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,UAAU,SACjB,KAAK,QAAQ,KAAK,KAAK,KAAK,WAAW,IACxC,KAAK;AAAA,EACX;AAAA,EAEA,IAAI,aAAmB;AACrB,WAAO,KAAK,gBAAgB,SACvB,KAAK,cAAc,KAAK,KAAK,KAAK,IAAI,IACvC,KAAK;AAAA,EACX;AAAA,EAEA,IAAI,MAAoB;AACtB,WAAO,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,EAC5C;AAAA,EAEA,MAAM,MAAoB;AACxB,WAAO,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,EAC5C;AAAA,EAEA,OAAO,MAAY,KAAsB;AACvC,QAAI,QAAQ,GAAG;AACb,aAAO,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK;AAAA,IAC9C;AACA,WAAO,KAAK,MAAM,IAAI,EAAE,cAAc,MAAM;AAAA,EAC9C;AAAA,EAEA,SAAe;AACb,WAAO,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE;AAAA,EACnC;AAAA,EAEA,WAAmB;AACjB,WAAO,IAAI,KAAK,MAAM,KAAK;AAAA,EAC7B;AACF;;;AChEO,IAAM,QAAN,MAAY;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EAED,YAAY,SAAe,UAAgB,eAAe,OAAO;AACvE,SAAK,UAAU;AACf,SAAK,WAAW;AAChB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,OAAO,IAAI,SAAe,UAAgB,KAA2B;AACnE,QAAI,YAAY,QAAQ,aAAa,MAAM;AACzC,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,KAAK,QAAQ,SAAS,UAAU,GAAG,GAAG;AAChD,aAAO;AAAA,IACT;AAKA,UAAM,yBAAyB,OAAO,QAAQ,SAAS,SAAS;AAChE,QAAI,QAAQ,SAAS,UAAU,sBAAsB,GAAG;AAGtD,YAAM,SAAS,IAAI,KAAK,QAAQ,SAAS,GAAG,GAAG,SAAS,SAAS,GAAG,CAAC;AACrE,YAAM,IAAI,OAAO,SAAS,GAAG;AAS7B,YAAM,WAAW,QAAQ,YAAY,GAAG,GAAG;AAC3C,YAAM,YAAY,SAAS,YAAY,GAAG,GAAG;AAC7C,UAAI,4BAAyB,2BAAwB;AACnD,cAAM,IAAI,MAAM;AAAA,MAClB;AAEA,aAAO,aAAa,YAChB,IAAI,MAAM,SAAS,UAAU,IAAI,IACjC,IAAI,MAAM,SAAS,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK,CAAC;AAAA,IAC/D;AAIA,UAAM,MAAM,QAAQ,sBAAsB,UAAU,CAAC;AACrD,UAAM,MAAM,SAAS,sBAAsB,SAAS,CAAC;AAGrD,QAAI,QAAQ,OAAO,QAAQ,KAAK;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,IAAI,QAAQ,SAAS,GAAG;AAI9B,UAAM,MAAM,MAAM,IAAI,MAAM,QAAQ,MAAM,QAAQ;AAElD,UAAM,MAAM,MAAM,IAAI,MAAM,SAAS,MAAM,SAAS;AAEpD,WAAO,IAAI,MAAM,IAAI,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;AAAA,EACrD;AAAA,EAEA,aAAa,MAAY,KAAsB;AAC7C,UAAM,OACJ,KAAK,QAAQ,SAAS,MAAM,OAAO,KAAK,QAAQ,SAAS,KAAK,OAAO,KACrE,KAAK,SAAS,SAAS,MAAM,OAAO,KAAK,SAAS,SAAS,KAAK,OAAO;AACzE,QAAI,MAAM;AACR,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,KAAK,kBAAkB,KAAK,SAAS,CAAC;AAChD,UAAM,IAAI,KAAK,kBAAkB,KAAK,UAAU,CAAC;AAEjD,QAAI,KAAK,cAAc;AACrB,aAAO,CAAC,EAAE,OAAO,GAAG,GAAG;AAAA,IACzB;AAEA,UAAM,IAAI,KAAK,QAAQ,kBAAkB,KAAK,UAAU,CAAC;AAEzD,WACE,CAAC,EAAE,OAAO,GAAG,GAAG,KAChB,CAAC,EAAE,OAAO,GAAG,GAAG,KAChB,CAAC,EAAE,OAAO,GAAG,GAAG,KAChB,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,WAAW,GAAG,GAAG;AAAA,EAErC;AAAA,EAEA,gBAAgB,GAAS,KAAsB;AAC7C,UAAM,QAAQ,KAAK,QAAQ,YAAY,GAAG,GAAG;AAC7C,UAAM,SAAS,KAAK,SAAS,YAAY,GAAG,GAAG;AAE/C,QAAI,yBAAsB,wBAAqB;AAC7C,aAAO;AAAA,IACT;AAIA,QAAI,UAAU,QAAQ;AACpB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK;AAAA;AAAA,MAER;AAAA;AAAA;AAAA;AAAA,MAGA,KAAK,QAAQ,kBAAkB,CAAC,KAAK,KACnC,KAAK,SAAS,kBAAkB,CAAC,KAAK;AAAA;AAAA,EAC9C;AAAA,EAEA,iBAAiB,GAAS,KAAsB;AAC9C,UAAM,QAAQ,KAAK,QAAQ,YAAY,GAAG,GAAG;AAC7C,UAAM,SAAS,KAAK,SAAS,YAAY,GAAG,GAAG;AAE/C,QAAI,yBAAsB,wBAAqB;AAC7C,aAAO;AAAA,IACT;AAIA,QAAI,UAAU,QAAQ;AACpB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK;AAAA;AAAA,MAER;AAAA;AAAA;AAAA;AAAA,MAGA,KAAK,QAAQ,kBAAkB,CAAC,KAAK,KACnC,KAAK,SAAS,kBAAkB,CAAC,KAAK;AAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,OACN,GACA,KACiD;AACjD,QAAI,CAAC,KAAK,iBAAiB,GAAG,GAAG,GAAG;AAElC,aAAO;AAAA,IACT;AAaA,UAAM,IAAI,KAAK,SAAS,aAAa,CAAC;AACtC,UAAM,KAAK,KAAK,QAAQ,aAAa,CAAC;AAItC,UAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC;AAC3B,UAAM,IAAY,EAAE,MAAM,EAAE,EAAE,OAAO;AAKrC,UAAM,IAAI,KAAK,SAAS,MAAM;AAC9B,UAAM,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,KAAK,SAAS,KAAK,IAAI;AAChD,UAAM,IAAI,EAAE,MAAM,CAAC,EAAE,cAAc,IAAI;AACvC,UAAM,eAAe,IAAI,IAAI,IAAI,IAAI;AAErC,QAAI,eAAgB,SAAQ,IAAI;AAG9B,aAAO;AAAA,IACT;AAEA,UAAM,IAAc,CAAC;AAErB,QAAI,KAAK,IAAI,YAAY,IAAI,MAAM,IAAI;AACrC,QAAE,KAAK,CAAC,KAAK,IAAI,EAAE;AAAA,IACrB,OAAO;AACL,QAAE,MAAM,CAAC,IAAI,KAAK,KAAK,YAAY,MAAM,IAAI,EAAE;AAC/C,QAAE,MAAM,CAAC,IAAI,KAAK,KAAK,YAAY,MAAM,IAAI,EAAE;AAAA,IACjD;AAEA,UAAM,SAAmD,CAAC;AAE1D,MAAE,QAAQ,CAAC,OAAe;AACxB,YAAM,IAAI,KAAK,SAAS,MAAM,MAAM,EAAE,EAAE,KAAK,CAAC;AAC9C,aAAO,KAAK;AAAA,QACV,QAAQ,EAAE,QAAQ,GAAG,EAAE;AAAA,QACvB,SAAS,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;AAAA,MAClD,CAAC;AAAA,IACH,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEQ,OACN,GACA,KAC4D;AAC5D,QAAI,CAAC,KAAK,aAAa,GAAG,GAAG,GAAG;AAE9B,aAAO;AAAA,IACT;AAWA,UAAM,IAAI,EAAE,kBAAkB,KAAK,UAAU,CAAC;AAC9C,UAAM,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC;AAE7C,UAAM,KAAK,IAAI,KAAK,GAAG,CAAC;AACxB,UAAM,KAAK,KAAK,QAAQ,aAAa,CAAC;AAItC,UAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC;AAC3B,UAAM,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO;AAG7B,UAAM,MACH,GAAG,MAAM,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,QAC3C,GAAG,MAAM,MAAM,KAAK,SAAS,KAAK;AACpC,UAAM,MACH,GAAG,MAAM,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,QAC3C,GAAG,MAAM,MAAM,KAAK,SAAS,KAAK;AAEpC,UAAM,KAAW,KAAK,SAAS,MAAM,MAAM,EAAE,EAAE,KAAK,CAAC;AACrD,UAAM,KAAW,KAAK,SAAS,MAAM,MAAM,EAAE,EAAE,KAAK,CAAC;AAErD,WAAO;AAAA,MACL;AAAA,QACE,QAAQ,EAAE,QAAQ,IAAI,EAAE;AAAA,QACxB,kBAAkB,EAAE,kBAAkB,EAAE;AAAA,MAC1C;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,QAAQ,IAAI,EAAE;AAAA,QACxB,kBAAkB,EAAE,kBAAkB,EAAE;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,QACN,GACA,KACiD;AACjD,QAAI,CAAC,KAAK,iBAAiB,GAAG,GAAG,GAAG;AAClC,aAAO;AAAA,IACT;AAcA,UAAM,IAAI,KAAK,QAAQ;AACvB,UAAM,IAAI,KAAK,QAAQ;AACvB,UAAM,IAAI,KAAK,SAAS;AAExB,UAAM,IAAY,EAAE,MAAM,CAAC,EAAE;AAC7B,UAAM,IAAY,EAAE,MAAM,CAAC,EAAE;AAE7B,UAAM,IAAI,EAAE,MAAM,CAAC,EAChB,MAAM,KAAK,IAAI,EAAE,EACjB,KAAK,CAAC;AAET,UAAM,WAAW,IAAI,KAAK,GAAG,CAAC;AAE9B,UACE,KAAK,EAAE,MAAM,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM;AACtE,UAAM,KAAK,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI;AACxC,UAAM,KAAK,EAAE,MAAM,CAAC,EAAE;AACtB,UAAM,eAAe,KAAK,KAAK,IAAI,KAAK;AAExC,QAAI,eAAgB,SAAQ,IAAI;AAG9B,aAAO;AAAA,IACT;AAEA,QAAI,GAAS;AAEb,QAAI,KAAK,IAAI,YAAY,IAAI,MAAM,IAAI;AACrC,YAAM,IAAI,CAAC,MAAM,IAAI;AACrB,UAAI,SAAS,SAAS,CAAC;AACvB,UAAI,EAAE,MAAM,CAAC,EAAE;AAAA,IACjB,OAAO;AACL,YAAM,MAAM,CAAC,KAAK,KAAK,KAAK,YAAY,MAAM,IAAI;AAClD,YAAM,MAAM,CAAC,KAAK,KAAK,KAAK,YAAY,MAAM,IAAI;AAElD,UACE,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,EAAE,cAC/B,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,EAAE,aAC/B;AACA,YAAI,SAAS,SAAS,EAAE;AACxB,YAAI,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,EAAE;AAAA,MACrC,OAAO;AACL,YAAI,SAAS,SAAS,EAAE;AACxB,YAAI,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,EAAE;AAAA,MACrC;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,QACE,QAAQ,EAAE,QAAQ,GAAG,EAAE;AAAA,QACvB,SAAS,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,QACN,GACA,KAC4D;AAC5D,QAAI,CAAC,KAAK,aAAa,GAAG,GAAG,GAAG;AAE9B,aAAO;AAAA,IACT;AAMA,UAAM,IAAI,KAAK,QAAQ;AAGvB,UAAM,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC;AAG7C,UAAM,IAAI,EAAE,kBAAkB,KAAK,UAAU,CAAC;AAG9C,UAAM,KAAK,IAAI,KAAK,GAAG,CAAC;AACxB,UAAM,KAAK,IAAI,KAAK,GAAG,CAAC;AACxB,UAAM,KAAK,IAAI,KAAK,GAAG,CAAC;AAGxB,UAAM,IAAI,GAAG;AACb,UAAM,IAAI,GAAG;AACb,UAAM,IAAI,GAAG;AAEb,UAAM,KAAK,IAAI,IAAI,KAAK;AAExB,QAAK,KAAK,IAAI,MAAM,IAAI,MAAO,IAAI,KAAK,GAAG;AAGzC,aAAO;AAAA,IACT;AAIA,UAAM,IAAI,KAAK,KAAM,KAAK,IAAI,MAAM,IAAI,MAAO,IAAI,EAAE;AAErD,UAAM,MAAc,GAAG,MAAM,MAAM,GAAG,KAAK;AAE3C,UAAM,SAAiB;AAAA,MACrB,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;AAAA,MAC/C,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;AAAA,MAC/C,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;AAAA,MAC/C,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;AAAA,IACjD;AAGA,UAAM,OAAe,CAAC;AACtB,WAAO,QAAQ,CAAC,QAAc;AAC5B,WAAK;AAAA,QACH,IAAI;AAAA,UACF,IAAI,KAAK,GAAG,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,MAAM,GAAG;AAAA,UAC1C,IAAI,KAAK,GAAG,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,MAAM,GAAG;AAAA,QAC5C,EAAE,KAAK,CAAC,GAAG;AAAA,MACb;AAAA,IACF,CAAC;AAGD,QAAI,IAAiB;AACrB,UAAM,QAA8C,CAAC;AACrD,eAAW,KAAK,MAAM;AACpB,YAAM,KAAK;AAAA,QACT,KAAK,KAAK,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAAA,QACvC,MAAM,KAAK,IAAI,GAAG,gBAAgB,CAAC,IAAI,IAAI,CAAC;AAAA,MAC9C,CAAC;AAED,YAAM,gBAAgB,KAAK,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAGxD,YAAM,gBAAgB,KAAK,IAAI,GAAG,gBAAgB,CAAC,IAAI,IAAI,CAAC;AAC5D,WACG,gBAAgB,MAAM,MAAM,gBAAgB,MAAM,OACnD,GAAG,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,GACtC;AACA,YAAI;AACJ;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM;AACV,QAAI,MAAM,MAAM;AACd,YAAM;AACN,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,eAAO,YAAY,KAAK,CAAC,EAAE,MAAM,KAAK,CAAC,EAAE,UAAU,gBAAgB,MAAM,CAAC,EAAE,oBAAoB,MAAM,CAAC,EAAE;AAAA;AAAA,MAC3G;AAAA,IACF;AACA,QAAI,MAAM,MAAM;AACd,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AAEA,WAAO;AAAA,MACL;AAAA,QACE,QAAQ,EAAE,QAAQ,GAAG,EAAE;AAAA,QACvB,kBAAkB,EAAE,kBAAkB,CAAC;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA,EAUA,WAAW,SAA6B,KAAa;AACnD,QAAI,mBAAmB,MAAM;AAC3B,aAAO,KAAK,eACR,KAAK,OAAO,SAAS,GAAG,IACxB,KAAK,QAAQ,SAAS,GAAG;AAAA,IAC/B;AACA,QAAI,mBAAmB,MAAM;AAC3B,aAAO,KAAK,eACR,KAAK,OAAO,mBAAmB,OAAO,UAAU,SAAS,GAAG,IAC5D,KAAK,QAAQ,mBAAmB,OAAO,UAAU,SAAS,GAAG;AAAA,IACnE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,WAAmB;AACjB,WACE,OAAO,KAAK,QAAQ,MAAM,SAAS,SAAS,KAAK,QAAQ,IAAI,SAAS;AAAA,MAC/D,KAAK,SAAS,MAAM,SAAS,SAAS,KAAK,SAAS,IAAI,SAAS;AAAA,EAE5E;AACF;;;AHjeO,SAAS,kBACd,MACA,QACA,MACkC;AAClC,MAAI,QAAQ;AACZ,MAAI;AAEJ,MAAI,IAAI;AACR,SAAO,wBAAqB,IAAI,OAAO,QAAQ;AAC7C,WAAO,KAAK,YAAY,OAAO,CAAC,GAAG,IAAI;AACvC;AAAA,EACF;AAEA,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,WAAW,KAAK,YAAY,OAAO,CAAC,GAAG,IAAI;AACjD,QAAI,0BAAuB;AACzB;AAAA,IACF;AACA,QAAI,aAAa,MAAM;AACrB,cAAQ;AACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AAYA,SAAS,kBACP,OACA,aACA,WACA,QACA,MAC2C;AAE3C,MAAI,OAAoB;AAExB,MAAI,aAAa;AAEjB,MAAI,SAAS;AAEb,SAAO,SAAS,QAAQ,SAAS,WAAW;AAC1C,UAAM,KAAK,OAAO,MAAM;AACxB,UAAM,KAAK,OAAO,SAAS,CAAC;AAG5B,UAAM,OAAO,IAAI,KAAK,IAAI,EAAE;AAE5B,UAAM,cAAc,MAAM,WAAW,MAAM,IAAI;AAC/C,QAAI,gBAAgB,MAAM;AAIxB,UAAI,mBAAmB;AACvB,UAAI,MAAM,cAAc;AAEtB,YAAI;AACJ,YAAI,IAAI;AACR,eAAO,6BAA0B,IAAI,OAAO,QAAQ;AAClD,sBAAY,KAAK,YAAY,OAAO,CAAC,GAAG,IAAI;AAC5C;AAAA,QACF;AAEA,2BACE,KAAK,YAAY,YAAY,CAAC,EAAE,OAAO,MAAM,MAAM,YAC/C,YAAY,CAAC,EAAE,mBACf,YAAY,CAAC,EAAE;AAAA,MACvB,OAAO;AACL,2BAAmB,YAAY,CAAC,EAAE;AAAA,MACpC;AAGA,UAAI,mBAAmB,KAAK,mBAAmB,GAAG;AAChD,cAAM,IAAI,KAAK,SAAS,gBAAgB;AACxC,cAAM,QAAQ,MAAM,QAAQ,kBAAkB,MAAM,IAAI;AACxD,eAAO,IAAI,KAAK,OAAO,CAAC;AAAA,MAC1B;AAAA,IACF;AAGA,QAAI,SAAS,MAAM;AACjB,YAAM,eAAe,MAAM,WAAW,IAAI,IAAI;AAC9C,UAAI,iBAAiB,MAAM;AAIzB,YAAI;AACJ,YAAI,MAAM,cAAc;AAEtB,cAAI;AACJ,cAAI,IAAI;AACR,iBAAO,6BAA0B,IAAI,OAAO,QAAQ;AAClD,wBAAY,aAAa,CAAC,EAAE,QAAQ,YAAY,OAAO,CAAC,GAAG,IAAI;AAC/D;AAAA,UACF;AAEA,oBACE,aAAa,CAAC,EAAE,QAAQ;AAAA,YACtB,aAAa,CAAC,EAAE,OAAO;AAAA,YACvB;AAAA,UACF,MAAM,YACF,aAAa,CAAC,EAAE,UAChB,aAAa,CAAC,EAAE;AAAA,QACxB,OAAO;AACL,oBAAU,aAAa,CAAC,EAAE;AAAA,QAC5B;AAMA,YAAI,kBAAkB,SAAS,QAAQ,IAAI,EAAE,OAAO;AAClD,gBAAM,QAAQ,MAAM,QAAQ,kBAAkB,SAAS,IAAI;AAC3D,iBAAO,IAAI,KAAK,OAAO,EAAE;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AACA,iBAAa;AACb;AAAA,EACF;AAEA,SAAO,SAAS,OAAO,OAAO,EAAE,MAAM,WAAW;AACnD;AAEA,SAAS,aAAa,QAAgB;AAEpC,MAAI,gBAAgB;AACpB,MAAI,eAAe;AAEnB,WAAS,IAAI,GAAG,IAAY,OAAO,QAAQ,IAAI,GAAG,KAAK;AAErD,UAAM,WAAmB,IAAI,KAAK,OAAO,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE;AAAA,MAC1D,OAAO,CAAC;AAAA,IACV;AACA,QAAI,WAAW,cAAc;AAC3B,qBAAe;AACf,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AACT;AASO,SAAS,oBACd,YACA,KACA,KACsC;AAEtC,MAAI,IAAU;AAId,QAAM,IAAI,WAAW;AACrB,QAAM,KAAK,IAAI,KAAK,WAAW,CAAC,GAAG,WAAW,IAAI,CAAC,CAAC;AAGpD,QAAM,eAAe,aAAa,UAAU;AAC5C,QAAM,eAAe,IAAI;AAAA,IACvB,WAAW,YAAY;AAAA,IACvB,WAAW,YAAY,EAAE,KAAK,GAAG,KAAK;AAAA,EACxC;AAGA,MAAI,QAAiB,MAAM,IAAI,IAAI,cAAc,GAAG;AAGpD,MAAI,KAAK,IAAI;AACb,MAAI,KAAK;AAET,KAAG;AAGD,UAAM,SAAS,kBAAkB,OAAO,IAAI,cAAc,YAAY,GAAG;AACzE,QAAI,WAAW,MAAM;AACnB,aAAO;AAAA,IACT;AACA;AAAC,KAAC,EAAE,MAAM,IAAI,YAAY,GAAG,IAAI;AAKjC,YAAiB,MAAM,IAAI,MAAM,SAAS,IAAI,GAAG;AAEjD,UAAM,SAAS,kBAAkB,OAAO,IAAI,GAAG,YAAY,GAAG;AAC9D,QAAI,WAAW,MAAM;AACnB,aAAO;AAAA,IACT;AACA;AAAC,KAAC,EAAE,MAAM,IAAI,YAAY,GAAG,IAAI;AAIjC,YAAiB,MAAM,IAAI,MAAM,SAAS,IAAI,GAAG;AAAA,EAGnD,SAAS,GAAG,SAAS,GAAG,SAAS;AAEjC,QAAM,IAAI,GAAG,kBAAkB,IAAI,CAAC;AACpC,QAAM,IAAI,GAAG;AACb,QAAM,IAAI,GAAG;AAEb,SAAO,EAAE,GAAG,GAAG,EAAE;AACnB;AAEO,SAAS,YACd,YACA,KACA,KAKO;AACP,MAAI,WAAW,SAAS,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,GAAG,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,GAAG,WAAW,CAAC,EAAE;AAAA,EAChE;AAEA,QAAM,SAAS,WAAW,IAAI,CAAC,MAAgC;AAC7D,WAAO,IAAI,KAAK,EAAE,GAAG,EAAE,CAAC;AAAA,EAC1B,CAAC;AAED,MAAI,IAAiB;AACrB,MAAI,IAAiB;AACrB,MAAI,IAAiB;AACrB,MAAI,YAAY;AAEhB,MAAI,YAAY;AAEhB,SAAO,YAAY,OAAO,QAAQ;AAEhC,QAAI,YAAY,GAAG;AACjB,aAAO,KAAK,OAAO,MAAM,CAAE;AAAA,IAC7B;AAGA,UAAM,WAAW,oBAAoB,QAAQ,KAAK,GAAG;AAGrD,QAAI,aAAa,MAAM;AACrB,YAAM,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI;AAEhC,YAAM,aACJ,GAAG,MAAM,EAAE,EAAE,OAAO,GAAG,MAAM,EAAE,EAAE,OAAO,GAAG,MAAM,EAAE,EAAE;AACvD,UAAI,aAAa,aAAa,cAAc,IAAI;AAC9C;AAAC,SAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;AACxB,oBAAY;AAAA,MACd;AAAA,IACF;AAEA;AAAA,EACF;AAEA,SAAO,cAAc,KACjB,OACA;AAAA,IACE,GAAG,EAAE,GAAG,EAAG,GAAG,GAAG,EAAG,EAAE;AAAA,IACtB,GAAG,EAAE,GAAG,EAAG,GAAG,GAAG,EAAG,EAAE;AAAA,IACtB,GAAG,EAAE,GAAG,EAAG,GAAG,GAAG,EAAG,EAAE;AAAA,EACxB;AACN;",
6
- "names": []
7
- }