@js-draw/math 1.21.3 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/build-config.json +1 -1
  2. package/dist/cjs/Color4.js +2 -2
  3. package/dist/cjs/Mat33.d.ts +1 -11
  4. package/dist/cjs/Mat33.js +8 -24
  5. package/dist/cjs/Vec3.js +9 -7
  6. package/dist/cjs/shapes/BezierJSWrapper.js +20 -13
  7. package/dist/cjs/shapes/LineSegment2.js +13 -17
  8. package/dist/cjs/shapes/Parameterized2DShape.js +1 -1
  9. package/dist/cjs/shapes/Path.js +49 -47
  10. package/dist/cjs/shapes/Rect2.js +13 -15
  11. package/dist/cjs/shapes/Triangle.js +4 -5
  12. package/dist/cjs/utils/convexHull2Of.js +3 -3
  13. package/dist/mjs/Color4.mjs +2 -2
  14. package/dist/mjs/Mat33.d.ts +1 -11
  15. package/dist/mjs/Mat33.mjs +8 -24
  16. package/dist/mjs/Vec3.mjs +9 -7
  17. package/dist/mjs/shapes/BezierJSWrapper.mjs +20 -13
  18. package/dist/mjs/shapes/LineSegment2.mjs +13 -17
  19. package/dist/mjs/shapes/Parameterized2DShape.mjs +1 -1
  20. package/dist/mjs/shapes/Path.mjs +49 -47
  21. package/dist/mjs/shapes/Rect2.mjs +13 -15
  22. package/dist/mjs/shapes/Triangle.mjs +4 -5
  23. package/dist/mjs/utils/convexHull2Of.mjs +3 -3
  24. package/dist-test/test_imports/test-require.cjs +1 -1
  25. package/package.json +3 -3
  26. package/src/Color4.test.ts +16 -21
  27. package/src/Color4.ts +22 -17
  28. package/src/Mat33.fromCSSMatrix.test.ts +31 -45
  29. package/src/Mat33.test.ts +58 -96
  30. package/src/Mat33.ts +61 -104
  31. package/src/Vec2.test.ts +3 -3
  32. package/src/Vec3.test.ts +2 -3
  33. package/src/Vec3.ts +34 -58
  34. package/src/lib.ts +0 -2
  35. package/src/polynomial/solveQuadratic.test.ts +39 -13
  36. package/src/polynomial/solveQuadratic.ts +5 -6
  37. package/src/rounding/cleanUpNumber.test.ts +1 -1
  38. package/src/rounding/constants.ts +1 -3
  39. package/src/rounding/getLenAfterDecimal.ts +1 -2
  40. package/src/rounding/lib.ts +1 -2
  41. package/src/rounding/toRoundedString.test.ts +1 -1
  42. package/src/rounding/toStringOfSamePrecision.test.ts +1 -2
  43. package/src/rounding/toStringOfSamePrecision.ts +1 -1
  44. package/src/shapes/BezierJSWrapper.ts +54 -37
  45. package/src/shapes/CubicBezier.ts +3 -3
  46. package/src/shapes/LineSegment2.test.ts +24 -17
  47. package/src/shapes/LineSegment2.ts +26 -29
  48. package/src/shapes/Parameterized2DShape.ts +5 -4
  49. package/src/shapes/Path.fromString.test.ts +5 -5
  50. package/src/shapes/Path.test.ts +122 -120
  51. package/src/shapes/Path.toString.test.ts +7 -7
  52. package/src/shapes/Path.ts +378 -352
  53. package/src/shapes/PointShape2D.ts +3 -3
  54. package/src/shapes/QuadraticBezier.test.ts +27 -21
  55. package/src/shapes/QuadraticBezier.ts +4 -9
  56. package/src/shapes/Rect2.test.ts +44 -75
  57. package/src/shapes/Rect2.ts +30 -35
  58. package/src/shapes/Triangle.test.ts +31 -29
  59. package/src/shapes/Triangle.ts +17 -18
  60. package/src/utils/convexHull2Of.test.ts +54 -15
  61. package/src/utils/convexHull2Of.ts +9 -7
  62. package/tsconfig.json +1 -3
  63. package/typedoc.json +2 -2
package/build-config.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "inDirectory": "./src",
3
3
  "outDirectory": "./dist"
4
- }
4
+ }
@@ -61,7 +61,7 @@ class Color4 {
61
61
  // Each character is a component
62
62
  const components = hexString.split('');
63
63
  // Convert to RRGGBBAA or RRGGBB format
64
- hexString = components.map(component => `${component}0`).join('');
64
+ hexString = components.map((component) => `${component}0`).join('');
65
65
  }
66
66
  if (hexString.length === 6) {
67
67
  // Alpha component
@@ -171,7 +171,7 @@ class Color4 {
171
171
  // - https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
172
172
  // - https://stackoverflow.com/a/9733420
173
173
  // Normalize the components, as per above
174
- const components = [this.r, this.g, this.b].map(component => {
174
+ const components = [this.r, this.g, this.b].map((component) => {
175
175
  if (component < 0.03928) {
176
176
  return component / 12.92;
177
177
  }
@@ -3,17 +3,7 @@ import Vec3 from './Vec3';
3
3
  /**
4
4
  * See {@link Mat33.toArray}.
5
5
  */
6
- export type Mat33Array = [
7
- number,
8
- number,
9
- number,
10
- number,
11
- number,
12
- number,
13
- number,
14
- number,
15
- number
16
- ];
6
+ export type Mat33Array = [number, number, number, number, number, number, number, number, number];
17
7
  /**
18
8
  * Represents a three dimensional linear transformation or
19
9
  * a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
package/dist/cjs/Mat33.js CHANGED
@@ -76,11 +76,7 @@ class Mat33 {
76
76
  this.c2 = c2;
77
77
  this.c3 = c3;
78
78
  this.cachedInverse = undefined;
79
- this.rows = [
80
- Vec3_1.default.of(a1, a2, a3),
81
- Vec3_1.default.of(b1, b2, b3),
82
- Vec3_1.default.of(c1, c2, c3),
83
- ];
79
+ this.rows = [Vec3_1.default.of(a1, a2, a3), Vec3_1.default.of(b1, b2, b3), Vec3_1.default.of(c1, c2, c3)];
84
80
  }
85
81
  /**
86
82
  * Creates a matrix from the given rows:
@@ -112,16 +108,8 @@ class Mat33 {
112
108
  if (this.cachedInverse !== undefined) {
113
109
  return this.cachedInverse;
114
110
  }
115
- const toIdentity = [
116
- this.rows[0],
117
- this.rows[1],
118
- this.rows[2],
119
- ];
120
- const toResult = [
121
- Vec3_1.default.unitX,
122
- Vec3_1.default.unitY,
123
- Vec3_1.default.unitZ,
124
- ];
111
+ const toIdentity = [this.rows[0], this.rows[1], this.rows[2]];
112
+ const toResult = [Vec3_1.default.unitX, Vec3_1.default.unitY, Vec3_1.default.unitZ];
125
113
  // Convert toIdentity to the identity matrix and
126
114
  // toResult to the inverse through elementary row operations
127
115
  for (let cursor = 0; cursor < 3; cursor++) {
@@ -317,11 +305,7 @@ class Mat33 {
317
305
  * ```
318
306
  */
319
307
  toArray() {
320
- return [
321
- this.a1, this.a2, this.a3,
322
- this.b1, this.b2, this.b3,
323
- this.c1, this.c2, this.c3,
324
- ];
308
+ return [this.a1, this.a2, this.a3, this.b1, this.b2, this.b3, this.c1, this.c2, this.c3];
325
309
  }
326
310
  /**
327
311
  * Returns a new `Mat33` where each entry is the output of the function
@@ -427,7 +411,7 @@ class Mat33 {
427
411
  return Mat33.identity;
428
412
  }
429
413
  const parseArguments = (argumentString) => {
430
- const parsed = argumentString.split(/[, \t\n]+/g).map(argString => {
414
+ const parsed = argumentString.split(/[, \t\n]+/g).map((argString) => {
431
415
  // Handle trailing spaces/commands
432
416
  if (argString.trim() === '') {
433
417
  return null;
@@ -438,7 +422,7 @@ class Mat33 {
438
422
  argString = argString.substring(0, argString.length - 1);
439
423
  }
440
424
  // Remove trailing px units.
441
- argString = argString.replace(/px$/ig, '');
425
+ argString = argString.replace(/px$/gi, '');
442
426
  const numberExp = /^[-]?\d*(?:\.\d*)?(?:[eE][-+]?\d+)?$/i;
443
427
  if (!numberExp.exec(argString)) {
444
428
  throw new Error(`All arguments to transform functions must be numeric (state: ${JSON.stringify({
@@ -452,7 +436,7 @@ class Mat33 {
452
436
  }
453
437
  return argNumber;
454
438
  });
455
- return parsed.filter(n => n !== null);
439
+ return parsed.filter((n) => n !== null);
456
440
  };
457
441
  const keywordToAction = {
458
442
  matrix: (matrixData) => {
@@ -502,7 +486,7 @@ class Mat33 {
502
486
  };
503
487
  // A command (\w+)
504
488
  // followed by a set of arguments ([ \t\n0-9eE.,\-%]+)
505
- const partRegex = /\s*(\w+)\s*\(([^)]*)\)/ig;
489
+ const partRegex = /\s*(\w+)\s*\(([^)]*)\)/gi;
506
490
  let match;
507
491
  let matrix = null;
508
492
  while ((match = partRegex.exec(cssString)) !== null) {
package/dist/cjs/Vec3.js CHANGED
@@ -106,9 +106,9 @@ class Vec3Impl {
106
106
  return [this.x, this.y, this.z];
107
107
  }
108
108
  eq(other, fuzz = defaultEqlTolerance) {
109
- return (Math.abs(other.x - this.x) <= fuzz
110
- && Math.abs(other.y - this.y) <= fuzz
111
- && Math.abs(other.z - this.z) <= fuzz);
109
+ return (Math.abs(other.x - this.x) <= fuzz &&
110
+ Math.abs(other.y - this.y) <= fuzz &&
111
+ Math.abs(other.z - this.z) <= fuzz);
112
112
  }
113
113
  toString() {
114
114
  return `Vec(${this.x}, ${this.y}, ${this.z})`;
@@ -119,7 +119,9 @@ class Vec2Impl {
119
119
  this.x = x;
120
120
  this.y = y;
121
121
  }
122
- get z() { return 0; }
122
+ get z() {
123
+ return 0;
124
+ }
123
125
  get xy() {
124
126
  // Useful for APIs that behave differently if .z is present.
125
127
  return {
@@ -216,9 +218,9 @@ class Vec2Impl {
216
218
  return [this.x, this.y, 0];
217
219
  }
218
220
  eq(other, fuzz = defaultEqlTolerance) {
219
- return (Math.abs(other.x - this.x) <= fuzz
220
- && Math.abs(other.y - this.y) <= fuzz
221
- && Math.abs(other.z) <= fuzz);
221
+ return (Math.abs(other.x - this.x) <= fuzz &&
222
+ Math.abs(other.y - this.y) <= fuzz &&
223
+ Math.abs(other.z) <= fuzz);
222
224
  }
223
225
  toString() {
224
226
  return `Vec(${this.x}, ${this.y})`;
@@ -40,7 +40,7 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
40
40
  }
41
41
  getBezier() {
42
42
  if (!__classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f")) {
43
- __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new bezier_js_1.Bezier(this.getPoints().map(p => p.xy)), "f");
43
+ __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new bezier_js_1.Bezier(this.getPoints().map((p) => p.xy)), "f");
44
44
  }
45
45
  return __classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f");
46
46
  }
@@ -94,10 +94,12 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
94
94
  const asLine = LineSegment2_1.default.ofSmallestContainingPoints(this.getPoints());
95
95
  if (asLine) {
96
96
  const intersection = asLine.intersectsLineSegment(line);
97
- return intersection.map(p => this.nearestPointTo(p).parameterValue);
97
+ return intersection.map((p) => this.nearestPointTo(p).parameterValue);
98
98
  }
99
99
  const bezier = this.getBezier();
100
- return bezier.intersects(line).map(t => {
100
+ return bezier
101
+ .intersects(line)
102
+ .map((t) => {
101
103
  // We're using the .intersects(line) function, which is documented
102
104
  // to always return numbers. However, to satisfy the type checker (and
103
105
  // possibly improperly-defined types),
@@ -106,12 +108,12 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
106
108
  }
107
109
  const point = Vec2_1.Vec2.ofXY(this.at(t));
108
110
  // Ensure that the intersection is on the line segment
109
- if (point.distanceTo(line.p1) > line.length
110
- || point.distanceTo(line.p2) > line.length) {
111
+ if (point.distanceTo(line.p1) > line.length || point.distanceTo(line.p2) > line.length) {
111
112
  return null;
112
113
  }
113
114
  return t;
114
- }).filter(entry => entry !== null);
115
+ })
116
+ .filter((entry) => entry !== null);
115
117
  }
116
118
  splitAt(t) {
117
119
  if (t <= 0 || t >= 1) {
@@ -120,8 +122,8 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
120
122
  const bezier = this.getBezier();
121
123
  const split = bezier.split(t);
122
124
  return [
123
- new BezierJSWrapperImpl(split.left.points.map(point => Vec2_1.Vec2.ofXY(point)), split.left),
124
- new BezierJSWrapperImpl(split.right.points.map(point => Vec2_1.Vec2.ofXY(point)), split.right),
125
+ new BezierJSWrapperImpl(split.left.points.map((point) => Vec2_1.Vec2.ofXY(point)), split.left),
126
+ new BezierJSWrapperImpl(split.right.points.map((point) => Vec2_1.Vec2.ofXY(point)), split.right),
125
127
  ];
126
128
  }
127
129
  nearestPointTo(point) {
@@ -165,16 +167,19 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
165
167
  const b = this.at(t);
166
168
  const bPrime = this.derivativeAt(t);
167
169
  const bPrimePrime = this.secondDerivativeAt(t);
168
- return (2 * bPrime.x * bPrime.x + 2 * b.x * bPrimePrime.x - 2 * point.x * bPrimePrime.x
169
- + 2 * bPrime.y * bPrime.y + 2 * b.y * bPrimePrime.y - 2 * point.y * bPrimePrime.y);
170
+ return (2 * bPrime.x * bPrime.x +
171
+ 2 * b.x * bPrimePrime.x -
172
+ 2 * point.x * bPrimePrime.x +
173
+ 2 * bPrime.y * bPrime.y +
174
+ 2 * b.y * bPrimePrime.y -
175
+ 2 * point.y * bPrimePrime.y);
170
176
  };
171
177
  // Because we're zeroing f'(t), we also need to be able to compute it:
172
178
  const derivativeAt = (t) => {
173
179
  // f'(t) = 2Bₓ(t)Bₓ'(t) - 2pₓBₓ'(t) + 2Bᵧ(t)Bᵧ'(t) - 2pᵧBᵧ'(t)
174
180
  const b = this.at(t);
175
181
  const bPrime = this.derivativeAt(t);
176
- return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x
177
- + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
182
+ return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
178
183
  };
179
184
  const iterate = () => {
180
185
  const slope = secondDerivativeAt(t);
@@ -225,7 +230,9 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
225
230
  return result;
226
231
  }
227
232
  toString() {
228
- return `Bézier(${this.getPoints().map(point => point.toString()).join(', ')})`;
233
+ return `Bézier(${this.getPoints()
234
+ .map((point) => point.toString())
235
+ .join(', ')})`;
229
236
  }
230
237
  }
231
238
  exports.BezierJSWrapper = BezierJSWrapper;
@@ -46,7 +46,7 @@ class LineSegment2 extends Parameterized2DShape_1.default {
46
46
  static ofSmallestContainingPoints(points) {
47
47
  if (points.length <= 1)
48
48
  return null;
49
- const sorted = [...points].sort((a, b) => a.x !== b.x ? a.x - b.x : a.y - b.y);
49
+ const sorted = [...points].sort((a, b) => (a.x !== b.x ? a.x - b.x : a.y - b.y));
50
50
  const line = new LineSegment2(sorted[0], sorted[sorted.length - 1]);
51
51
  for (const point of sorted) {
52
52
  if (!line.containsPoint(point)) {
@@ -96,10 +96,7 @@ class LineSegment2 extends Parameterized2DShape_1.default {
96
96
  if (t <= 0 || t >= 1) {
97
97
  return [this];
98
98
  }
99
- return [
100
- new LineSegment2(this.point1, this.at(t)),
101
- new LineSegment2(this.at(t), this.point2),
102
- ];
99
+ return [new LineSegment2(this.point1, this.at(t)), new LineSegment2(this.at(t), this.point2)];
103
100
  }
104
101
  /**
105
102
  * Returns the intersection of this with another line segment.
@@ -149,18 +146,17 @@ class LineSegment2 extends Parameterized2DShape_1.default {
149
146
  return null;
150
147
  }
151
148
  const xIntersect = this.point1.x;
152
- const yIntersect = (this.point1.x - other.point1.x) * other.direction.y / other.direction.x + other.point1.y;
149
+ const yIntersect = ((this.point1.x - other.point1.x) * other.direction.y) / other.direction.x + other.point1.y;
153
150
  resultPoint = Vec2_1.Vec2.of(xIntersect, yIntersect);
154
151
  resultT = (yIntersect - this.point1.y) / this.direction.y;
155
152
  }
156
153
  else {
157
154
  // From above,
158
155
  // x = ((o₁ᵧ - o₂ᵧ)(d₁ₓd₂ₓ) + (d₂ᵧd₁ₓ)(o₂ₓ) - (d₁ᵧd₂ₓ)(o₁ₓ))/(d₂ᵧd₁ₓ - d₁ᵧd₂ₓ)
159
- const numerator = ((this.point1.y - other.point1.y) * this.direction.x * other.direction.x
160
- + this.direction.x * other.direction.y * other.point1.x
161
- - this.direction.y * other.direction.x * this.point1.x);
162
- const denominator = (other.direction.y * this.direction.x
163
- - this.direction.y * other.direction.x);
156
+ const numerator = (this.point1.y - other.point1.y) * this.direction.x * other.direction.x +
157
+ this.direction.x * other.direction.y * other.point1.x -
158
+ this.direction.y * other.direction.x * this.point1.x;
159
+ const denominator = other.direction.y * this.direction.x - this.direction.y * other.direction.x;
164
160
  // Avoid dividing by zero. It means there is no intersection
165
161
  if (denominator === 0) {
166
162
  return null;
@@ -176,10 +172,10 @@ class LineSegment2 extends Parameterized2DShape_1.default {
176
172
  const resultToP2 = resultPoint.distanceTo(this.point2);
177
173
  const resultToP3 = resultPoint.distanceTo(other.point1);
178
174
  const resultToP4 = resultPoint.distanceTo(other.point2);
179
- if (resultToP1 > this.length
180
- || resultToP2 > this.length
181
- || resultToP3 > other.length
182
- || resultToP4 > other.length) {
175
+ if (resultToP1 > this.length ||
176
+ resultToP2 > this.length ||
177
+ resultToP3 > other.length ||
178
+ resultToP4 > other.length) {
183
179
  return null;
184
180
  }
185
181
  return {
@@ -264,8 +260,8 @@ class LineSegment2 extends Parameterized2DShape_1.default {
264
260
  }
265
261
  const tolerance = options?.tolerance;
266
262
  const ignoreDirection = options?.ignoreDirection ?? true;
267
- return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance))
268
- || (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
263
+ return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance)) ||
264
+ (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
269
265
  }
270
266
  }
271
267
  exports.LineSegment2 = LineSegment2;
@@ -13,7 +13,7 @@ const Abstract2DShape_1 = __importDefault(require("./Abstract2DShape"));
13
13
  */
14
14
  class Parameterized2DShape extends Abstract2DShape_1.default {
15
15
  intersectsLineSegment(line) {
16
- return this.argIntersectsLineSegment(line).map(t => this.at(t));
16
+ return this.argIntersectsLineSegment(line).map((t) => this.at(t));
17
17
  }
18
18
  }
19
19
  exports.Parameterized2DShape = Parameterized2DShape;
@@ -327,9 +327,7 @@ class Path {
327
327
  const maxRaymarchSteps = 8;
328
328
  // Start raymarching from each of these points. This allows detection of multiple
329
329
  // intersections.
330
- const startPoints = [
331
- line.p1, ...additionalRaymarchStartPoints, line.p2
332
- ];
330
+ const startPoints = [line.p1, ...additionalRaymarchStartPoints, line.p2];
333
331
  // Converts a point ON THE LINE to a parameter
334
332
  const pointToParameter = (point) => {
335
333
  // Because line.direction is a unit vector, this computes the length
@@ -435,7 +433,9 @@ class Path {
435
433
  return [];
436
434
  }
437
435
  if (this.parts.length === 0) {
438
- return new Path(this.startPoint, [{ kind: PathCommandType.MoveTo, point: this.startPoint }]).intersection(line, strokeRadius);
436
+ return new Path(this.startPoint, [
437
+ { kind: PathCommandType.MoveTo, point: this.startPoint },
438
+ ]).intersection(line, strokeRadius);
439
439
  }
440
440
  let index = 0;
441
441
  for (const part of this.geometry) {
@@ -456,7 +456,7 @@ class Path {
456
456
  const doRaymarching = strokeRadius && strokeRadius > 1e-8;
457
457
  if (doRaymarching) {
458
458
  // Starting points for raymarching (in addition to the end points of the line).
459
- const startPoints = result.map(intersection => intersection.point);
459
+ const startPoints = result.map((intersection) => intersection.point);
460
460
  result = this.raymarchIntersectionWith(line, strokeRadius, startPoints);
461
461
  }
462
462
  return result;
@@ -509,7 +509,8 @@ class Path {
509
509
  */
510
510
  spliced(deleteFrom, deleteTo, insert, options) {
511
511
  const isBeforeOrEqual = (a, b) => {
512
- return a.curveIndex < b.curveIndex || (a.curveIndex === b.curveIndex && a.parameterValue <= b.parameterValue);
512
+ return (a.curveIndex < b.curveIndex ||
513
+ (a.curveIndex === b.curveIndex && a.parameterValue <= b.parameterValue));
513
514
  };
514
515
  if (isBeforeOrEqual(deleteFrom, deleteTo)) {
515
516
  // deleteFrom deleteTo
@@ -547,15 +548,15 @@ class Path {
547
548
  //
548
549
  // Bounds checking & reversal.
549
550
  //
550
- while (splitAt.length > 0
551
- && splitAt[splitAt.length - 1].curveIndex >= this.parts.length - 1
552
- && splitAt[splitAt.length - 1].parameterValue >= 1) {
551
+ while (splitAt.length > 0 &&
552
+ splitAt[splitAt.length - 1].curveIndex >= this.parts.length - 1 &&
553
+ splitAt[splitAt.length - 1].parameterValue >= 1) {
553
554
  splitAt.pop();
554
555
  }
555
556
  splitAt.reverse(); // .reverse() <-- We're `.pop`ing from the end
556
- while (splitAt.length > 0
557
- && splitAt[splitAt.length - 1].curveIndex <= 0
558
- && splitAt[splitAt.length - 1].parameterValue <= 0) {
557
+ while (splitAt.length > 0 &&
558
+ splitAt[splitAt.length - 1].curveIndex <= 0 &&
559
+ splitAt[splitAt.length - 1].parameterValue <= 0) {
559
560
  splitAt.pop();
560
561
  }
561
562
  if (splitAt.length === 0 || this.parts.length === 0) {
@@ -746,7 +747,7 @@ class Path {
746
747
  if (affineTransfm.isIdentity()) {
747
748
  return this;
748
749
  }
749
- return this.mapPoints(point => affineTransfm.transformVec2(point));
750
+ return this.mapPoints((point) => affineTransfm.transformVec2(point));
750
751
  }
751
752
  /**
752
753
  * @internal
@@ -835,11 +836,10 @@ class Path {
835
836
  });
836
837
  lastPoint = part.endPoint;
837
838
  break;
838
- default:
839
- {
840
- const exhaustivenessCheck = part;
841
- return exhaustivenessCheck;
842
- }
839
+ default: {
840
+ const exhaustivenessCheck = part;
841
+ return exhaustivenessCheck;
842
+ }
843
843
  }
844
844
  }
845
845
  newParts.reverse();
@@ -851,7 +851,8 @@ class Path {
851
851
  return this.startPoint;
852
852
  }
853
853
  const lastPart = this.parts[this.parts.length - 1];
854
- if (lastPart.kind === PathCommandType.QuadraticBezierTo || lastPart.kind === PathCommandType.CubicBezierTo) {
854
+ if (lastPart.kind === PathCommandType.QuadraticBezierTo ||
855
+ lastPart.kind === PathCommandType.CubicBezierTo) {
855
856
  return lastPart.endPoint;
856
857
  }
857
858
  else {
@@ -960,9 +961,9 @@ class Path {
960
961
  if (part1.kind !== part2.kind) {
961
962
  return false;
962
963
  }
963
- else if (!part1.controlPoint1.eq(part2.controlPoint1, tolerance)
964
- || !part1.controlPoint2.eq(part2.controlPoint2, tolerance)
965
- || !part1.endPoint.eq(part2.endPoint, tolerance)) {
964
+ else if (!part1.controlPoint1.eq(part2.controlPoint1, tolerance) ||
965
+ !part1.controlPoint2.eq(part2.controlPoint2, tolerance) ||
966
+ !part1.endPoint.eq(part2.endPoint, tolerance)) {
966
967
  return false;
967
968
  }
968
969
  break;
@@ -970,16 +971,15 @@ class Path {
970
971
  if (part1.kind !== part2.kind) {
971
972
  return false;
972
973
  }
973
- else if (!part1.controlPoint.eq(part2.controlPoint, tolerance)
974
- || !part1.endPoint.eq(part2.endPoint, tolerance)) {
974
+ else if (!part1.controlPoint.eq(part2.controlPoint, tolerance) ||
975
+ !part1.endPoint.eq(part2.endPoint, tolerance)) {
975
976
  return false;
976
977
  }
977
978
  break;
978
- default:
979
- {
980
- const exhaustivenessCheck = part1;
981
- return exhaustivenessCheck;
982
- }
979
+ default: {
980
+ const exhaustivenessCheck = part1;
981
+ return exhaustivenessCheck;
982
+ }
983
983
  }
984
984
  }
985
985
  return true;
@@ -1001,11 +1001,7 @@ class Path {
1001
1001
  const cornerToEdge = Vec2_1.Vec2.of(lineWidth, lineWidth).times(0.5);
1002
1002
  const innerRect = Rect2_1.default.fromCorners(rect.topLeft.plus(cornerToEdge), rect.bottomRight.minus(cornerToEdge));
1003
1003
  const outerRect = Rect2_1.default.fromCorners(rect.topLeft.minus(cornerToEdge), rect.bottomRight.plus(cornerToEdge));
1004
- corners = [
1005
- innerRect.corners[3],
1006
- ...innerRect.corners,
1007
- ...outerRect.corners.reverse(),
1008
- ];
1004
+ corners = [innerRect.corners[3], ...innerRect.corners, ...outerRect.corners.reverse()];
1009
1005
  startPoint = outerRect.corners[3];
1010
1006
  }
1011
1007
  else {
@@ -1188,19 +1184,23 @@ class Path {
1188
1184
  });
1189
1185
  };
1190
1186
  const commandArgCounts = {
1191
- 'm': 1,
1192
- 'l': 1,
1193
- 'c': 3,
1194
- 'q': 2,
1195
- 'z': 0,
1196
- 'h': 1,
1197
- 'v': 1,
1187
+ m: 1,
1188
+ l: 1,
1189
+ c: 3,
1190
+ q: 2,
1191
+ z: 0,
1192
+ h: 1,
1193
+ v: 1,
1198
1194
  };
1199
1195
  // Each command: Command character followed by anything that isn't a command character
1200
- const commandExp = /([MZLHVCSQTA])\s*([^MZLHVCSQTA]*)/ig;
1196
+ const commandExp = /([MZLHVCSQTA])\s*([^MZLHVCSQTA]*)/gi;
1201
1197
  let current;
1202
1198
  while ((current = commandExp.exec(pathString)) !== null) {
1203
- const argParts = current[2].trim().split(/[^0-9Ee.-]/).filter(part => part.length > 0).reduce((accumualtor, current) => {
1199
+ const argParts = current[2]
1200
+ .trim()
1201
+ .split(/[^0-9Ee.-]/)
1202
+ .filter((part) => part.length > 0)
1203
+ .reduce((accumualtor, current) => {
1204
1204
  // As of 09/2022, iOS Safari doesn't support support lookbehind in regular
1205
1205
  // expressions. As such, we need an alternative.
1206
1206
  // Because '-' can be used as a path separator, unless preceeded by an 'e' (as in 1e-5),
@@ -1210,10 +1210,10 @@ class Path {
1210
1210
  if (parts[0] !== '') {
1211
1211
  accumualtor.push(parts[0]);
1212
1212
  }
1213
- accumualtor.push(...parts.slice(1).map(part => `-${part}`));
1213
+ accumualtor.push(...parts.slice(1).map((part) => `-${part}`));
1214
1214
  return accumualtor;
1215
1215
  }, []);
1216
- let numericArgs = argParts.map(arg => parseFloat(arg));
1216
+ let numericArgs = argParts.map((arg) => parseFloat(arg));
1217
1217
  let commandChar = current[1].toLowerCase();
1218
1218
  let uppercaseCommand = current[1] !== commandChar;
1219
1219
  // Convert commands that don't take points into commands that do.
@@ -1241,7 +1241,8 @@ class Path {
1241
1241
  commandChar = 'l';
1242
1242
  }
1243
1243
  const commandArgCount = commandArgCounts[commandChar] ?? 0;
1244
- const allArgs = numericArgs.reduce((accumulator, current, index, parts) => {
1244
+ const allArgs = numericArgs
1245
+ .reduce((accumulator, current, index, parts) => {
1245
1246
  if (index % 2 !== 0) {
1246
1247
  const currentAsFloat = current;
1247
1248
  const prevAsFloat = parts[index - 1];
@@ -1250,7 +1251,8 @@ class Path {
1250
1251
  else {
1251
1252
  return accumulator;
1252
1253
  }
1253
- }, []).map((coordinate, index) => {
1254
+ }, [])
1255
+ .map((coordinate, index) => {
1254
1256
  // Lowercase commands are relative, uppercase commands use absolute
1255
1257
  // positioning
1256
1258
  let newPos;
@@ -40,13 +40,16 @@ class Rect2 extends Abstract2DShape_1.default {
40
40
  return new Rect2(this.x, this.y, size.x, size.y);
41
41
  }
42
42
  containsPoint(other) {
43
- return this.x <= other.x && this.y <= other.y
44
- && this.x + this.w >= other.x && this.y + this.h >= other.y;
43
+ return (this.x <= other.x &&
44
+ this.y <= other.y &&
45
+ this.x + this.w >= other.x &&
46
+ this.y + this.h >= other.y);
45
47
  }
46
48
  containsRect(other) {
47
- return this.x <= other.x && this.y <= other.y
48
- && this.x + this.w >= other.x + other.w
49
- && this.y + this.h >= other.y + other.h;
49
+ return (this.x <= other.x &&
50
+ this.y <= other.y &&
51
+ this.x + this.w >= other.x + other.w &&
52
+ this.y + this.h >= other.y + other.h);
50
53
  }
51
54
  /**
52
55
  * @returns true iff this and `other` overlap
@@ -131,7 +134,7 @@ class Rect2 extends Abstract2DShape_1.default {
131
134
  return new Rect2(this.x - margin, this.y - margin, this.w + margin * 2, this.h + margin * 2);
132
135
  }
133
136
  getClosestPointOnBoundaryTo(target) {
134
- const closestEdgePoints = this.getEdges().map(edge => {
137
+ const closestEdgePoints = this.getEdges().map((edge) => {
135
138
  return edge.closestPointTo(target);
136
139
  });
137
140
  let closest = null;
@@ -158,15 +161,10 @@ class Rect2 extends Abstract2DShape_1.default {
158
161
  return false;
159
162
  }
160
163
  const squareRadius = radius * radius;
161
- return this.corners.every(corner => corner.minus(point).magnitudeSquared() < squareRadius);
164
+ return this.corners.every((corner) => corner.minus(point).magnitudeSquared() < squareRadius);
162
165
  }
163
166
  get corners() {
164
- return [
165
- this.bottomRight,
166
- this.topRight,
167
- this.topLeft,
168
- this.bottomLeft,
169
- ];
167
+ return [this.bottomRight, this.topRight, this.topLeft, this.bottomLeft];
170
168
  }
171
169
  get maxDimension() {
172
170
  return Math.max(this.w, this.h);
@@ -207,7 +205,7 @@ class Rect2 extends Abstract2DShape_1.default {
207
205
  const result = [];
208
206
  for (const edge of this.getEdges()) {
209
207
  const intersection = edge.intersectsLineSegment(lineSegment);
210
- intersection.forEach(point => result.push(point));
208
+ intersection.forEach((point) => result.push(point));
211
209
  }
212
210
  return result;
213
211
  }
@@ -225,7 +223,7 @@ class Rect2 extends Abstract2DShape_1.default {
225
223
  // [affineTransform] is a transformation matrix that both scales and **translates**.
226
224
  // the bounding box of this' four corners after transformed by the given affine transformation.
227
225
  transformedBoundingBox(affineTransform) {
228
- return Rect2.bboxOf(this.corners.map(corner => affineTransform.transformVec2(corner)));
226
+ return Rect2.bboxOf(this.corners.map((corner) => affineTransform.transformVec2(corner)));
229
227
  }
230
228
  /** @return true iff this is equal to `other ± tolerance` */
231
229
  eq(other, tolerance = 0) {
@@ -44,12 +44,12 @@ class Triangle extends Abstract2DShape_1.default {
44
44
  }
45
45
  // Transform, treating this as composed of 2D points.
46
46
  transformed2DBy(affineTransform) {
47
- return this.map(vertex => affineTransform.transformVec2(vertex));
47
+ return this.map((vertex) => affineTransform.transformVec2(vertex));
48
48
  }
49
49
  // Transforms this by a linear transform --- verticies are treated as
50
50
  // 3D points.
51
51
  transformedBy(linearTransform) {
52
- return this.map(vertex => linearTransform.transformVec3(vertex));
52
+ return this.map((vertex) => linearTransform.transformVec3(vertex));
53
53
  }
54
54
  /**
55
55
  * Returns the sides of this triangle, as an array of `LineSegment2`s.
@@ -71,8 +71,7 @@ class Triangle extends Abstract2DShape_1.default {
71
71
  intersectsLineSegment(lineSegment) {
72
72
  const result = [];
73
73
  for (const edge of this.getEdges()) {
74
- edge.intersectsLineSegment(lineSegment)
75
- .forEach(point => result.push(point));
74
+ edge.intersectsLineSegment(lineSegment).forEach((point) => result.push(point));
76
75
  }
77
76
  return result;
78
77
  }
@@ -106,7 +105,7 @@ class Triangle extends Abstract2DShape_1.default {
106
105
  */
107
106
  signedDistance(point) {
108
107
  const sides = this.getEdges();
109
- const distances = sides.map(side => side.distance(point));
108
+ const distances = sides.map((side) => side.distance(point));
110
109
  const distance = Math.min(...distances);
111
110
  // If the point is in this' interior, signedDistance must return a negative
112
111
  // number.
@@ -12,9 +12,9 @@ const convexHull2Of = (points) => {
12
12
  return [];
13
13
  }
14
14
  // 1. Start with a vertex on the hull
15
- const lowestPoint = points.reduce((lowest, current) => current.y < lowest.y ? current : lowest, points[0]);
15
+ const lowestPoint = points.reduce((lowest, current) => (current.y < lowest.y ? current : lowest), points[0]);
16
16
  const vertices = [lowestPoint];
17
- let toProcess = [...points.filter(p => !p.eq(lowestPoint))];
17
+ let toProcess = [...points.filter((p) => !p.eq(lowestPoint))];
18
18
  let lastBaseDirection = Vec2_1.Vec2.of(-1, 0);
19
19
  // 2. Find the point with greatest angle from the vertex:
20
20
  //
@@ -40,7 +40,7 @@ const convexHull2Of = (points) => {
40
40
  smallestDotProductSoFar = currentDotProduct;
41
41
  }
42
42
  }
43
- toProcess = toProcess.filter(p => !p.eq(furthestPointSoFar));
43
+ toProcess = toProcess.filter((p) => !p.eq(furthestPointSoFar));
44
44
  const newBaseDirection = furthestPointSoFar.minus(lastVertex).normalized();
45
45
  // If the last vertex is on the same edge as the current, there's no need to include
46
46
  // the previous one.