@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
@@ -55,7 +55,7 @@ export class Color4 {
55
55
  // Each character is a component
56
56
  const components = hexString.split('');
57
57
  // Convert to RRGGBBAA or RRGGBB format
58
- hexString = components.map(component => `${component}0`).join('');
58
+ hexString = components.map((component) => `${component}0`).join('');
59
59
  }
60
60
  if (hexString.length === 6) {
61
61
  // Alpha component
@@ -165,7 +165,7 @@ export class Color4 {
165
165
  // - https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
166
166
  // - https://stackoverflow.com/a/9733420
167
167
  // Normalize the components, as per above
168
- const components = [this.r, this.g, this.b].map(component => {
168
+ const components = [this.r, this.g, this.b].map((component) => {
169
169
  if (component < 0.03928) {
170
170
  return component / 12.92;
171
171
  }
@@ -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
@@ -70,11 +70,7 @@ export class Mat33 {
70
70
  this.c2 = c2;
71
71
  this.c3 = c3;
72
72
  this.cachedInverse = undefined;
73
- this.rows = [
74
- Vec3.of(a1, a2, a3),
75
- Vec3.of(b1, b2, b3),
76
- Vec3.of(c1, c2, c3),
77
- ];
73
+ this.rows = [Vec3.of(a1, a2, a3), Vec3.of(b1, b2, b3), Vec3.of(c1, c2, c3)];
78
74
  }
79
75
  /**
80
76
  * Creates a matrix from the given rows:
@@ -106,16 +102,8 @@ export class Mat33 {
106
102
  if (this.cachedInverse !== undefined) {
107
103
  return this.cachedInverse;
108
104
  }
109
- const toIdentity = [
110
- this.rows[0],
111
- this.rows[1],
112
- this.rows[2],
113
- ];
114
- const toResult = [
115
- Vec3.unitX,
116
- Vec3.unitY,
117
- Vec3.unitZ,
118
- ];
105
+ const toIdentity = [this.rows[0], this.rows[1], this.rows[2]];
106
+ const toResult = [Vec3.unitX, Vec3.unitY, Vec3.unitZ];
119
107
  // Convert toIdentity to the identity matrix and
120
108
  // toResult to the inverse through elementary row operations
121
109
  for (let cursor = 0; cursor < 3; cursor++) {
@@ -311,11 +299,7 @@ export class Mat33 {
311
299
  * ```
312
300
  */
313
301
  toArray() {
314
- return [
315
- this.a1, this.a2, this.a3,
316
- this.b1, this.b2, this.b3,
317
- this.c1, this.c2, this.c3,
318
- ];
302
+ return [this.a1, this.a2, this.a3, this.b1, this.b2, this.b3, this.c1, this.c2, this.c3];
319
303
  }
320
304
  /**
321
305
  * Returns a new `Mat33` where each entry is the output of the function
@@ -421,7 +405,7 @@ export class Mat33 {
421
405
  return Mat33.identity;
422
406
  }
423
407
  const parseArguments = (argumentString) => {
424
- const parsed = argumentString.split(/[, \t\n]+/g).map(argString => {
408
+ const parsed = argumentString.split(/[, \t\n]+/g).map((argString) => {
425
409
  // Handle trailing spaces/commands
426
410
  if (argString.trim() === '') {
427
411
  return null;
@@ -432,7 +416,7 @@ export class Mat33 {
432
416
  argString = argString.substring(0, argString.length - 1);
433
417
  }
434
418
  // Remove trailing px units.
435
- argString = argString.replace(/px$/ig, '');
419
+ argString = argString.replace(/px$/gi, '');
436
420
  const numberExp = /^[-]?\d*(?:\.\d*)?(?:[eE][-+]?\d+)?$/i;
437
421
  if (!numberExp.exec(argString)) {
438
422
  throw new Error(`All arguments to transform functions must be numeric (state: ${JSON.stringify({
@@ -446,7 +430,7 @@ export class Mat33 {
446
430
  }
447
431
  return argNumber;
448
432
  });
449
- return parsed.filter(n => n !== null);
433
+ return parsed.filter((n) => n !== null);
450
434
  };
451
435
  const keywordToAction = {
452
436
  matrix: (matrixData) => {
@@ -496,7 +480,7 @@ export class Mat33 {
496
480
  };
497
481
  // A command (\w+)
498
482
  // followed by a set of arguments ([ \t\n0-9eE.,\-%]+)
499
- const partRegex = /\s*(\w+)\s*\(([^)]*)\)/ig;
483
+ const partRegex = /\s*(\w+)\s*\(([^)]*)\)/gi;
500
484
  let match;
501
485
  let matrix = null;
502
486
  while ((match = partRegex.exec(cssString)) !== null) {
package/dist/mjs/Vec3.mjs CHANGED
@@ -103,9 +103,9 @@ class Vec3Impl {
103
103
  return [this.x, this.y, this.z];
104
104
  }
105
105
  eq(other, fuzz = defaultEqlTolerance) {
106
- return (Math.abs(other.x - this.x) <= fuzz
107
- && Math.abs(other.y - this.y) <= fuzz
108
- && Math.abs(other.z - this.z) <= fuzz);
106
+ return (Math.abs(other.x - this.x) <= fuzz &&
107
+ Math.abs(other.y - this.y) <= fuzz &&
108
+ Math.abs(other.z - this.z) <= fuzz);
109
109
  }
110
110
  toString() {
111
111
  return `Vec(${this.x}, ${this.y}, ${this.z})`;
@@ -116,7 +116,9 @@ class Vec2Impl {
116
116
  this.x = x;
117
117
  this.y = y;
118
118
  }
119
- get z() { return 0; }
119
+ get z() {
120
+ return 0;
121
+ }
120
122
  get xy() {
121
123
  // Useful for APIs that behave differently if .z is present.
122
124
  return {
@@ -213,9 +215,9 @@ class Vec2Impl {
213
215
  return [this.x, this.y, 0];
214
216
  }
215
217
  eq(other, fuzz = defaultEqlTolerance) {
216
- return (Math.abs(other.x - this.x) <= fuzz
217
- && Math.abs(other.y - this.y) <= fuzz
218
- && Math.abs(other.z) <= fuzz);
218
+ return (Math.abs(other.x - this.x) <= fuzz &&
219
+ Math.abs(other.y - this.y) <= fuzz &&
220
+ Math.abs(other.z) <= fuzz);
219
221
  }
220
222
  toString() {
221
223
  return `Vec(${this.x}, ${this.y})`;
@@ -34,7 +34,7 @@ export class BezierJSWrapper extends Parameterized2DShape {
34
34
  }
35
35
  getBezier() {
36
36
  if (!__classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f")) {
37
- __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new Bezier(this.getPoints().map(p => p.xy)), "f");
37
+ __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new Bezier(this.getPoints().map((p) => p.xy)), "f");
38
38
  }
39
39
  return __classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f");
40
40
  }
@@ -88,10 +88,12 @@ export class BezierJSWrapper extends Parameterized2DShape {
88
88
  const asLine = LineSegment2.ofSmallestContainingPoints(this.getPoints());
89
89
  if (asLine) {
90
90
  const intersection = asLine.intersectsLineSegment(line);
91
- return intersection.map(p => this.nearestPointTo(p).parameterValue);
91
+ return intersection.map((p) => this.nearestPointTo(p).parameterValue);
92
92
  }
93
93
  const bezier = this.getBezier();
94
- return bezier.intersects(line).map(t => {
94
+ return bezier
95
+ .intersects(line)
96
+ .map((t) => {
95
97
  // We're using the .intersects(line) function, which is documented
96
98
  // to always return numbers. However, to satisfy the type checker (and
97
99
  // possibly improperly-defined types),
@@ -100,12 +102,12 @@ export class BezierJSWrapper extends Parameterized2DShape {
100
102
  }
101
103
  const point = Vec2.ofXY(this.at(t));
102
104
  // Ensure that the intersection is on the line segment
103
- if (point.distanceTo(line.p1) > line.length
104
- || point.distanceTo(line.p2) > line.length) {
105
+ if (point.distanceTo(line.p1) > line.length || point.distanceTo(line.p2) > line.length) {
105
106
  return null;
106
107
  }
107
108
  return t;
108
- }).filter(entry => entry !== null);
109
+ })
110
+ .filter((entry) => entry !== null);
109
111
  }
110
112
  splitAt(t) {
111
113
  if (t <= 0 || t >= 1) {
@@ -114,8 +116,8 @@ export class BezierJSWrapper extends Parameterized2DShape {
114
116
  const bezier = this.getBezier();
115
117
  const split = bezier.split(t);
116
118
  return [
117
- new BezierJSWrapperImpl(split.left.points.map(point => Vec2.ofXY(point)), split.left),
118
- new BezierJSWrapperImpl(split.right.points.map(point => Vec2.ofXY(point)), split.right),
119
+ new BezierJSWrapperImpl(split.left.points.map((point) => Vec2.ofXY(point)), split.left),
120
+ new BezierJSWrapperImpl(split.right.points.map((point) => Vec2.ofXY(point)), split.right),
119
121
  ];
120
122
  }
121
123
  nearestPointTo(point) {
@@ -159,16 +161,19 @@ export class BezierJSWrapper extends Parameterized2DShape {
159
161
  const b = this.at(t);
160
162
  const bPrime = this.derivativeAt(t);
161
163
  const bPrimePrime = this.secondDerivativeAt(t);
162
- return (2 * bPrime.x * bPrime.x + 2 * b.x * bPrimePrime.x - 2 * point.x * bPrimePrime.x
163
- + 2 * bPrime.y * bPrime.y + 2 * b.y * bPrimePrime.y - 2 * point.y * bPrimePrime.y);
164
+ return (2 * bPrime.x * bPrime.x +
165
+ 2 * b.x * bPrimePrime.x -
166
+ 2 * point.x * bPrimePrime.x +
167
+ 2 * bPrime.y * bPrime.y +
168
+ 2 * b.y * bPrimePrime.y -
169
+ 2 * point.y * bPrimePrime.y);
164
170
  };
165
171
  // Because we're zeroing f'(t), we also need to be able to compute it:
166
172
  const derivativeAt = (t) => {
167
173
  // f'(t) = 2Bₓ(t)Bₓ'(t) - 2pₓBₓ'(t) + 2Bᵧ(t)Bᵧ'(t) - 2pᵧBᵧ'(t)
168
174
  const b = this.at(t);
169
175
  const bPrime = this.derivativeAt(t);
170
- return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x
171
- + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
176
+ return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
172
177
  };
173
178
  const iterate = () => {
174
179
  const slope = secondDerivativeAt(t);
@@ -219,7 +224,9 @@ export class BezierJSWrapper extends Parameterized2DShape {
219
224
  return result;
220
225
  }
221
226
  toString() {
222
- return `Bézier(${this.getPoints().map(point => point.toString()).join(', ')})`;
227
+ return `Bézier(${this.getPoints()
228
+ .map((point) => point.toString())
229
+ .join(', ')})`;
223
230
  }
224
231
  }
225
232
  _BezierJSWrapper_bezierJs = new WeakMap();
@@ -40,7 +40,7 @@ export class LineSegment2 extends Parameterized2DShape {
40
40
  static ofSmallestContainingPoints(points) {
41
41
  if (points.length <= 1)
42
42
  return null;
43
- const sorted = [...points].sort((a, b) => a.x !== b.x ? a.x - b.x : a.y - b.y);
43
+ const sorted = [...points].sort((a, b) => (a.x !== b.x ? a.x - b.x : a.y - b.y));
44
44
  const line = new LineSegment2(sorted[0], sorted[sorted.length - 1]);
45
45
  for (const point of sorted) {
46
46
  if (!line.containsPoint(point)) {
@@ -90,10 +90,7 @@ export class LineSegment2 extends Parameterized2DShape {
90
90
  if (t <= 0 || t >= 1) {
91
91
  return [this];
92
92
  }
93
- return [
94
- new LineSegment2(this.point1, this.at(t)),
95
- new LineSegment2(this.at(t), this.point2),
96
- ];
93
+ return [new LineSegment2(this.point1, this.at(t)), new LineSegment2(this.at(t), this.point2)];
97
94
  }
98
95
  /**
99
96
  * Returns the intersection of this with another line segment.
@@ -143,18 +140,17 @@ export class LineSegment2 extends Parameterized2DShape {
143
140
  return null;
144
141
  }
145
142
  const xIntersect = this.point1.x;
146
- const yIntersect = (this.point1.x - other.point1.x) * other.direction.y / other.direction.x + other.point1.y;
143
+ const yIntersect = ((this.point1.x - other.point1.x) * other.direction.y) / other.direction.x + other.point1.y;
147
144
  resultPoint = Vec2.of(xIntersect, yIntersect);
148
145
  resultT = (yIntersect - this.point1.y) / this.direction.y;
149
146
  }
150
147
  else {
151
148
  // From above,
152
149
  // x = ((o₁ᵧ - o₂ᵧ)(d₁ₓd₂ₓ) + (d₂ᵧd₁ₓ)(o₂ₓ) - (d₁ᵧd₂ₓ)(o₁ₓ))/(d₂ᵧd₁ₓ - d₁ᵧd₂ₓ)
153
- const numerator = ((this.point1.y - other.point1.y) * this.direction.x * other.direction.x
154
- + this.direction.x * other.direction.y * other.point1.x
155
- - this.direction.y * other.direction.x * this.point1.x);
156
- const denominator = (other.direction.y * this.direction.x
157
- - this.direction.y * other.direction.x);
150
+ const numerator = (this.point1.y - other.point1.y) * this.direction.x * other.direction.x +
151
+ this.direction.x * other.direction.y * other.point1.x -
152
+ this.direction.y * other.direction.x * this.point1.x;
153
+ const denominator = other.direction.y * this.direction.x - this.direction.y * other.direction.x;
158
154
  // Avoid dividing by zero. It means there is no intersection
159
155
  if (denominator === 0) {
160
156
  return null;
@@ -170,10 +166,10 @@ export class LineSegment2 extends Parameterized2DShape {
170
166
  const resultToP2 = resultPoint.distanceTo(this.point2);
171
167
  const resultToP3 = resultPoint.distanceTo(other.point1);
172
168
  const resultToP4 = resultPoint.distanceTo(other.point2);
173
- if (resultToP1 > this.length
174
- || resultToP2 > this.length
175
- || resultToP3 > other.length
176
- || resultToP4 > other.length) {
169
+ if (resultToP1 > this.length ||
170
+ resultToP2 > this.length ||
171
+ resultToP3 > other.length ||
172
+ resultToP4 > other.length) {
177
173
  return null;
178
174
  }
179
175
  return {
@@ -258,8 +254,8 @@ export class LineSegment2 extends Parameterized2DShape {
258
254
  }
259
255
  const tolerance = options?.tolerance;
260
256
  const ignoreDirection = options?.ignoreDirection ?? true;
261
- return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance))
262
- || (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
257
+ return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance)) ||
258
+ (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
263
259
  }
264
260
  }
265
261
  export default LineSegment2;
@@ -7,7 +7,7 @@ import Abstract2DShape from './Abstract2DShape.mjs';
7
7
  */
8
8
  export class Parameterized2DShape extends Abstract2DShape {
9
9
  intersectsLineSegment(line) {
10
- return this.argIntersectsLineSegment(line).map(t => this.at(t));
10
+ return this.argIntersectsLineSegment(line).map((t) => this.at(t));
11
11
  }
12
12
  }
13
13
  export default Parameterized2DShape;
@@ -319,9 +319,7 @@ export class Path {
319
319
  const maxRaymarchSteps = 8;
320
320
  // Start raymarching from each of these points. This allows detection of multiple
321
321
  // intersections.
322
- const startPoints = [
323
- line.p1, ...additionalRaymarchStartPoints, line.p2
324
- ];
322
+ const startPoints = [line.p1, ...additionalRaymarchStartPoints, line.p2];
325
323
  // Converts a point ON THE LINE to a parameter
326
324
  const pointToParameter = (point) => {
327
325
  // Because line.direction is a unit vector, this computes the length
@@ -427,7 +425,9 @@ export class Path {
427
425
  return [];
428
426
  }
429
427
  if (this.parts.length === 0) {
430
- return new Path(this.startPoint, [{ kind: PathCommandType.MoveTo, point: this.startPoint }]).intersection(line, strokeRadius);
428
+ return new Path(this.startPoint, [
429
+ { kind: PathCommandType.MoveTo, point: this.startPoint },
430
+ ]).intersection(line, strokeRadius);
431
431
  }
432
432
  let index = 0;
433
433
  for (const part of this.geometry) {
@@ -448,7 +448,7 @@ export class Path {
448
448
  const doRaymarching = strokeRadius && strokeRadius > 1e-8;
449
449
  if (doRaymarching) {
450
450
  // Starting points for raymarching (in addition to the end points of the line).
451
- const startPoints = result.map(intersection => intersection.point);
451
+ const startPoints = result.map((intersection) => intersection.point);
452
452
  result = this.raymarchIntersectionWith(line, strokeRadius, startPoints);
453
453
  }
454
454
  return result;
@@ -501,7 +501,8 @@ export class Path {
501
501
  */
502
502
  spliced(deleteFrom, deleteTo, insert, options) {
503
503
  const isBeforeOrEqual = (a, b) => {
504
- return a.curveIndex < b.curveIndex || (a.curveIndex === b.curveIndex && a.parameterValue <= b.parameterValue);
504
+ return (a.curveIndex < b.curveIndex ||
505
+ (a.curveIndex === b.curveIndex && a.parameterValue <= b.parameterValue));
505
506
  };
506
507
  if (isBeforeOrEqual(deleteFrom, deleteTo)) {
507
508
  // deleteFrom deleteTo
@@ -539,15 +540,15 @@ export class Path {
539
540
  //
540
541
  // Bounds checking & reversal.
541
542
  //
542
- while (splitAt.length > 0
543
- && splitAt[splitAt.length - 1].curveIndex >= this.parts.length - 1
544
- && splitAt[splitAt.length - 1].parameterValue >= 1) {
543
+ while (splitAt.length > 0 &&
544
+ splitAt[splitAt.length - 1].curveIndex >= this.parts.length - 1 &&
545
+ splitAt[splitAt.length - 1].parameterValue >= 1) {
545
546
  splitAt.pop();
546
547
  }
547
548
  splitAt.reverse(); // .reverse() <-- We're `.pop`ing from the end
548
- while (splitAt.length > 0
549
- && splitAt[splitAt.length - 1].curveIndex <= 0
550
- && splitAt[splitAt.length - 1].parameterValue <= 0) {
549
+ while (splitAt.length > 0 &&
550
+ splitAt[splitAt.length - 1].curveIndex <= 0 &&
551
+ splitAt[splitAt.length - 1].parameterValue <= 0) {
551
552
  splitAt.pop();
552
553
  }
553
554
  if (splitAt.length === 0 || this.parts.length === 0) {
@@ -738,7 +739,7 @@ export class Path {
738
739
  if (affineTransfm.isIdentity()) {
739
740
  return this;
740
741
  }
741
- return this.mapPoints(point => affineTransfm.transformVec2(point));
742
+ return this.mapPoints((point) => affineTransfm.transformVec2(point));
742
743
  }
743
744
  /**
744
745
  * @internal
@@ -827,11 +828,10 @@ export class Path {
827
828
  });
828
829
  lastPoint = part.endPoint;
829
830
  break;
830
- default:
831
- {
832
- const exhaustivenessCheck = part;
833
- return exhaustivenessCheck;
834
- }
831
+ default: {
832
+ const exhaustivenessCheck = part;
833
+ return exhaustivenessCheck;
834
+ }
835
835
  }
836
836
  }
837
837
  newParts.reverse();
@@ -843,7 +843,8 @@ export class Path {
843
843
  return this.startPoint;
844
844
  }
845
845
  const lastPart = this.parts[this.parts.length - 1];
846
- if (lastPart.kind === PathCommandType.QuadraticBezierTo || lastPart.kind === PathCommandType.CubicBezierTo) {
846
+ if (lastPart.kind === PathCommandType.QuadraticBezierTo ||
847
+ lastPart.kind === PathCommandType.CubicBezierTo) {
847
848
  return lastPart.endPoint;
848
849
  }
849
850
  else {
@@ -952,9 +953,9 @@ export class Path {
952
953
  if (part1.kind !== part2.kind) {
953
954
  return false;
954
955
  }
955
- else if (!part1.controlPoint1.eq(part2.controlPoint1, tolerance)
956
- || !part1.controlPoint2.eq(part2.controlPoint2, tolerance)
957
- || !part1.endPoint.eq(part2.endPoint, tolerance)) {
956
+ else if (!part1.controlPoint1.eq(part2.controlPoint1, tolerance) ||
957
+ !part1.controlPoint2.eq(part2.controlPoint2, tolerance) ||
958
+ !part1.endPoint.eq(part2.endPoint, tolerance)) {
958
959
  return false;
959
960
  }
960
961
  break;
@@ -962,16 +963,15 @@ export class Path {
962
963
  if (part1.kind !== part2.kind) {
963
964
  return false;
964
965
  }
965
- else if (!part1.controlPoint.eq(part2.controlPoint, tolerance)
966
- || !part1.endPoint.eq(part2.endPoint, tolerance)) {
966
+ else if (!part1.controlPoint.eq(part2.controlPoint, tolerance) ||
967
+ !part1.endPoint.eq(part2.endPoint, tolerance)) {
967
968
  return false;
968
969
  }
969
970
  break;
970
- default:
971
- {
972
- const exhaustivenessCheck = part1;
973
- return exhaustivenessCheck;
974
- }
971
+ default: {
972
+ const exhaustivenessCheck = part1;
973
+ return exhaustivenessCheck;
974
+ }
975
975
  }
976
976
  }
977
977
  return true;
@@ -993,11 +993,7 @@ export class Path {
993
993
  const cornerToEdge = Vec2.of(lineWidth, lineWidth).times(0.5);
994
994
  const innerRect = Rect2.fromCorners(rect.topLeft.plus(cornerToEdge), rect.bottomRight.minus(cornerToEdge));
995
995
  const outerRect = Rect2.fromCorners(rect.topLeft.minus(cornerToEdge), rect.bottomRight.plus(cornerToEdge));
996
- corners = [
997
- innerRect.corners[3],
998
- ...innerRect.corners,
999
- ...outerRect.corners.reverse(),
1000
- ];
996
+ corners = [innerRect.corners[3], ...innerRect.corners, ...outerRect.corners.reverse()];
1001
997
  startPoint = outerRect.corners[3];
1002
998
  }
1003
999
  else {
@@ -1180,19 +1176,23 @@ export class Path {
1180
1176
  });
1181
1177
  };
1182
1178
  const commandArgCounts = {
1183
- 'm': 1,
1184
- 'l': 1,
1185
- 'c': 3,
1186
- 'q': 2,
1187
- 'z': 0,
1188
- 'h': 1,
1189
- 'v': 1,
1179
+ m: 1,
1180
+ l: 1,
1181
+ c: 3,
1182
+ q: 2,
1183
+ z: 0,
1184
+ h: 1,
1185
+ v: 1,
1190
1186
  };
1191
1187
  // Each command: Command character followed by anything that isn't a command character
1192
- const commandExp = /([MZLHVCSQTA])\s*([^MZLHVCSQTA]*)/ig;
1188
+ const commandExp = /([MZLHVCSQTA])\s*([^MZLHVCSQTA]*)/gi;
1193
1189
  let current;
1194
1190
  while ((current = commandExp.exec(pathString)) !== null) {
1195
- const argParts = current[2].trim().split(/[^0-9Ee.-]/).filter(part => part.length > 0).reduce((accumualtor, current) => {
1191
+ const argParts = current[2]
1192
+ .trim()
1193
+ .split(/[^0-9Ee.-]/)
1194
+ .filter((part) => part.length > 0)
1195
+ .reduce((accumualtor, current) => {
1196
1196
  // As of 09/2022, iOS Safari doesn't support support lookbehind in regular
1197
1197
  // expressions. As such, we need an alternative.
1198
1198
  // Because '-' can be used as a path separator, unless preceeded by an 'e' (as in 1e-5),
@@ -1202,10 +1202,10 @@ export class Path {
1202
1202
  if (parts[0] !== '') {
1203
1203
  accumualtor.push(parts[0]);
1204
1204
  }
1205
- accumualtor.push(...parts.slice(1).map(part => `-${part}`));
1205
+ accumualtor.push(...parts.slice(1).map((part) => `-${part}`));
1206
1206
  return accumualtor;
1207
1207
  }, []);
1208
- let numericArgs = argParts.map(arg => parseFloat(arg));
1208
+ let numericArgs = argParts.map((arg) => parseFloat(arg));
1209
1209
  let commandChar = current[1].toLowerCase();
1210
1210
  let uppercaseCommand = current[1] !== commandChar;
1211
1211
  // Convert commands that don't take points into commands that do.
@@ -1233,7 +1233,8 @@ export class Path {
1233
1233
  commandChar = 'l';
1234
1234
  }
1235
1235
  const commandArgCount = commandArgCounts[commandChar] ?? 0;
1236
- const allArgs = numericArgs.reduce((accumulator, current, index, parts) => {
1236
+ const allArgs = numericArgs
1237
+ .reduce((accumulator, current, index, parts) => {
1237
1238
  if (index % 2 !== 0) {
1238
1239
  const currentAsFloat = current;
1239
1240
  const prevAsFloat = parts[index - 1];
@@ -1242,7 +1243,8 @@ export class Path {
1242
1243
  else {
1243
1244
  return accumulator;
1244
1245
  }
1245
- }, []).map((coordinate, index) => {
1246
+ }, [])
1247
+ .map((coordinate, index) => {
1246
1248
  // Lowercase commands are relative, uppercase commands use absolute
1247
1249
  // positioning
1248
1250
  let newPos;
@@ -34,13 +34,16 @@ export class Rect2 extends Abstract2DShape {
34
34
  return new Rect2(this.x, this.y, size.x, size.y);
35
35
  }
36
36
  containsPoint(other) {
37
- return this.x <= other.x && this.y <= other.y
38
- && this.x + this.w >= other.x && this.y + this.h >= other.y;
37
+ return (this.x <= other.x &&
38
+ this.y <= other.y &&
39
+ this.x + this.w >= other.x &&
40
+ this.y + this.h >= other.y);
39
41
  }
40
42
  containsRect(other) {
41
- return this.x <= other.x && this.y <= other.y
42
- && this.x + this.w >= other.x + other.w
43
- && this.y + this.h >= other.y + other.h;
43
+ return (this.x <= other.x &&
44
+ this.y <= other.y &&
45
+ this.x + this.w >= other.x + other.w &&
46
+ this.y + this.h >= other.y + other.h);
44
47
  }
45
48
  /**
46
49
  * @returns true iff this and `other` overlap
@@ -125,7 +128,7 @@ export class Rect2 extends Abstract2DShape {
125
128
  return new Rect2(this.x - margin, this.y - margin, this.w + margin * 2, this.h + margin * 2);
126
129
  }
127
130
  getClosestPointOnBoundaryTo(target) {
128
- const closestEdgePoints = this.getEdges().map(edge => {
131
+ const closestEdgePoints = this.getEdges().map((edge) => {
129
132
  return edge.closestPointTo(target);
130
133
  });
131
134
  let closest = null;
@@ -152,15 +155,10 @@ export class Rect2 extends Abstract2DShape {
152
155
  return false;
153
156
  }
154
157
  const squareRadius = radius * radius;
155
- return this.corners.every(corner => corner.minus(point).magnitudeSquared() < squareRadius);
158
+ return this.corners.every((corner) => corner.minus(point).magnitudeSquared() < squareRadius);
156
159
  }
157
160
  get corners() {
158
- return [
159
- this.bottomRight,
160
- this.topRight,
161
- this.topLeft,
162
- this.bottomLeft,
163
- ];
161
+ return [this.bottomRight, this.topRight, this.topLeft, this.bottomLeft];
164
162
  }
165
163
  get maxDimension() {
166
164
  return Math.max(this.w, this.h);
@@ -201,7 +199,7 @@ export class Rect2 extends Abstract2DShape {
201
199
  const result = [];
202
200
  for (const edge of this.getEdges()) {
203
201
  const intersection = edge.intersectsLineSegment(lineSegment);
204
- intersection.forEach(point => result.push(point));
202
+ intersection.forEach((point) => result.push(point));
205
203
  }
206
204
  return result;
207
205
  }
@@ -219,7 +217,7 @@ export class Rect2 extends Abstract2DShape {
219
217
  // [affineTransform] is a transformation matrix that both scales and **translates**.
220
218
  // the bounding box of this' four corners after transformed by the given affine transformation.
221
219
  transformedBoundingBox(affineTransform) {
222
- return Rect2.bboxOf(this.corners.map(corner => affineTransform.transformVec2(corner)));
220
+ return Rect2.bboxOf(this.corners.map((corner) => affineTransform.transformVec2(corner)));
223
221
  }
224
222
  /** @return true iff this is equal to `other ± tolerance` */
225
223
  eq(other, tolerance = 0) {
@@ -39,12 +39,12 @@ class Triangle extends Abstract2DShape {
39
39
  }
40
40
  // Transform, treating this as composed of 2D points.
41
41
  transformed2DBy(affineTransform) {
42
- return this.map(vertex => affineTransform.transformVec2(vertex));
42
+ return this.map((vertex) => affineTransform.transformVec2(vertex));
43
43
  }
44
44
  // Transforms this by a linear transform --- verticies are treated as
45
45
  // 3D points.
46
46
  transformedBy(linearTransform) {
47
- return this.map(vertex => linearTransform.transformVec3(vertex));
47
+ return this.map((vertex) => linearTransform.transformVec3(vertex));
48
48
  }
49
49
  /**
50
50
  * Returns the sides of this triangle, as an array of `LineSegment2`s.
@@ -66,8 +66,7 @@ class Triangle extends Abstract2DShape {
66
66
  intersectsLineSegment(lineSegment) {
67
67
  const result = [];
68
68
  for (const edge of this.getEdges()) {
69
- edge.intersectsLineSegment(lineSegment)
70
- .forEach(point => result.push(point));
69
+ edge.intersectsLineSegment(lineSegment).forEach((point) => result.push(point));
71
70
  }
72
71
  return result;
73
72
  }
@@ -101,7 +100,7 @@ class Triangle extends Abstract2DShape {
101
100
  */
102
101
  signedDistance(point) {
103
102
  const sides = this.getEdges();
104
- const distances = sides.map(side => side.distance(point));
103
+ const distances = sides.map((side) => side.distance(point));
105
104
  const distance = Math.min(...distances);
106
105
  // If the point is in this' interior, signedDistance must return a negative
107
106
  // number.
@@ -10,9 +10,9 @@ const convexHull2Of = (points) => {
10
10
  return [];
11
11
  }
12
12
  // 1. Start with a vertex on the hull
13
- const lowestPoint = points.reduce((lowest, current) => current.y < lowest.y ? current : lowest, points[0]);
13
+ const lowestPoint = points.reduce((lowest, current) => (current.y < lowest.y ? current : lowest), points[0]);
14
14
  const vertices = [lowestPoint];
15
- let toProcess = [...points.filter(p => !p.eq(lowestPoint))];
15
+ let toProcess = [...points.filter((p) => !p.eq(lowestPoint))];
16
16
  let lastBaseDirection = Vec2.of(-1, 0);
17
17
  // 2. Find the point with greatest angle from the vertex:
18
18
  //
@@ -38,7 +38,7 @@ const convexHull2Of = (points) => {
38
38
  smallestDotProductSoFar = currentDotProduct;
39
39
  }
40
40
  }
41
- toProcess = toProcess.filter(p => !p.eq(furthestPointSoFar));
41
+ toProcess = toProcess.filter((p) => !p.eq(furthestPointSoFar));
42
42
  const newBaseDirection = furthestPointSoFar.minus(lastVertex).normalized();
43
43
  // If the last vertex is on the same edge as the current, there's no need to include
44
44
  // the previous one.
@@ -12,4 +12,4 @@ if (!Mat33.identity) {
12
12
 
13
13
  if (!Color4.red) {
14
14
  throw new Error('Failed to import Color4 from js-draw');
15
- }
15
+ }