@js-draw/math 1.21.2 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
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.