@js-draw/math 1.21.3 → 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
@@ -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
+ }