@js-draw/math 1.21.2 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/build-config.json +1 -1
  2. package/dist/cjs/Color4.js +2 -2
  3. package/dist/cjs/Mat33.d.ts +1 -11
  4. package/dist/cjs/Mat33.js +8 -24
  5. package/dist/cjs/Vec3.js +9 -7
  6. package/dist/cjs/shapes/BezierJSWrapper.js +20 -13
  7. package/dist/cjs/shapes/LineSegment2.js +13 -17
  8. package/dist/cjs/shapes/Parameterized2DShape.js +1 -1
  9. package/dist/cjs/shapes/Path.js +49 -47
  10. package/dist/cjs/shapes/Rect2.js +13 -15
  11. package/dist/cjs/shapes/Triangle.js +4 -5
  12. package/dist/cjs/utils/convexHull2Of.js +3 -3
  13. package/dist/mjs/Color4.mjs +2 -2
  14. package/dist/mjs/Mat33.d.ts +1 -11
  15. package/dist/mjs/Mat33.mjs +8 -24
  16. package/dist/mjs/Vec3.mjs +9 -7
  17. package/dist/mjs/shapes/BezierJSWrapper.mjs +20 -13
  18. package/dist/mjs/shapes/LineSegment2.mjs +13 -17
  19. package/dist/mjs/shapes/Parameterized2DShape.mjs +1 -1
  20. package/dist/mjs/shapes/Path.mjs +49 -47
  21. package/dist/mjs/shapes/Rect2.mjs +13 -15
  22. package/dist/mjs/shapes/Triangle.mjs +4 -5
  23. package/dist/mjs/utils/convexHull2Of.mjs +3 -3
  24. package/dist-test/test_imports/test-require.cjs +1 -1
  25. package/package.json +3 -3
  26. package/src/Color4.test.ts +16 -21
  27. package/src/Color4.ts +22 -17
  28. package/src/Mat33.fromCSSMatrix.test.ts +31 -45
  29. package/src/Mat33.test.ts +58 -96
  30. package/src/Mat33.ts +61 -104
  31. package/src/Vec2.test.ts +3 -3
  32. package/src/Vec3.test.ts +2 -3
  33. package/src/Vec3.ts +34 -58
  34. package/src/lib.ts +0 -2
  35. package/src/polynomial/solveQuadratic.test.ts +39 -13
  36. package/src/polynomial/solveQuadratic.ts +5 -6
  37. package/src/rounding/cleanUpNumber.test.ts +1 -1
  38. package/src/rounding/constants.ts +1 -3
  39. package/src/rounding/getLenAfterDecimal.ts +1 -2
  40. package/src/rounding/lib.ts +1 -2
  41. package/src/rounding/toRoundedString.test.ts +1 -1
  42. package/src/rounding/toStringOfSamePrecision.test.ts +1 -2
  43. package/src/rounding/toStringOfSamePrecision.ts +1 -1
  44. package/src/shapes/BezierJSWrapper.ts +54 -37
  45. package/src/shapes/CubicBezier.ts +3 -3
  46. package/src/shapes/LineSegment2.test.ts +24 -17
  47. package/src/shapes/LineSegment2.ts +26 -29
  48. package/src/shapes/Parameterized2DShape.ts +5 -4
  49. package/src/shapes/Path.fromString.test.ts +5 -5
  50. package/src/shapes/Path.test.ts +122 -120
  51. package/src/shapes/Path.toString.test.ts +7 -7
  52. package/src/shapes/Path.ts +378 -352
  53. package/src/shapes/PointShape2D.ts +3 -3
  54. package/src/shapes/QuadraticBezier.test.ts +27 -21
  55. package/src/shapes/QuadraticBezier.ts +4 -9
  56. package/src/shapes/Rect2.test.ts +44 -75
  57. package/src/shapes/Rect2.ts +30 -35
  58. package/src/shapes/Triangle.test.ts +31 -29
  59. package/src/shapes/Triangle.ts +17 -18
  60. package/src/utils/convexHull2Of.test.ts +54 -15
  61. package/src/utils/convexHull2Of.ts +9 -7
  62. package/tsconfig.json +1 -3
  63. package/typedoc.json +2 -2
package/src/Mat33.ts CHANGED
@@ -4,11 +4,7 @@ import Vec3 from './Vec3';
4
4
  /**
5
5
  * See {@link Mat33.toArray}.
6
6
  */
7
- export type Mat33Array = [
8
- number, number, number,
9
- number, number, number,
10
- number, number, number,
11
- ];
7
+ export type Mat33Array = [number, number, number, number, number, number, number, number, number];
12
8
 
13
9
  /**
14
10
  * Represents a three dimensional linear transformation or
@@ -82,13 +78,9 @@ export class Mat33 {
82
78
 
83
79
  public readonly c1: number,
84
80
  public readonly c2: number,
85
- public readonly c3: number
81
+ public readonly c3: number,
86
82
  ) {
87
- this.rows = [
88
- Vec3.of(a1, a2, a3),
89
- Vec3.of(b1, b2, b3),
90
- Vec3.of(c1, c2, c3),
91
- ];
83
+ this.rows = [Vec3.of(a1, a2, a3), Vec3.of(b1, b2, b3), Vec3.of(c1, c2, c3)];
92
84
  }
93
85
 
94
86
  /**
@@ -102,19 +94,11 @@ export class Mat33 {
102
94
  * $$
103
95
  */
104
96
  public static ofRows(r1: Vec3, r2: Vec3, r3: Vec3): Mat33 {
105
- return new Mat33(
106
- r1.x, r1.y, r1.z,
107
- r2.x, r2.y, r2.z,
108
- r3.x, r3.y, r3.z
109
- );
97
+ return new Mat33(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.z);
110
98
  }
111
99
 
112
100
  /** The 3x3 [identity matrix](https://en.wikipedia.org/wiki/Identity_matrix). */
113
- public static identity = new Mat33(
114
- 1, 0, 0,
115
- 0, 1, 0,
116
- 0, 0, 1
117
- );
101
+ public static identity = new Mat33(1, 0, 0, 0, 1, 0, 0, 0, 1);
118
102
 
119
103
  /**
120
104
  * Either returns the inverse of this, or, if this matrix is singular/uninvertable,
@@ -131,23 +115,15 @@ export class Mat33 {
131
115
  return this.computeInverse() !== null;
132
116
  }
133
117
 
134
- private cachedInverse: Mat33|undefined|null = undefined;
135
- private computeInverse(): Mat33|null {
118
+ private cachedInverse: Mat33 | undefined | null = undefined;
119
+ private computeInverse(): Mat33 | null {
136
120
  if (this.cachedInverse !== undefined) {
137
121
  return this.cachedInverse;
138
122
  }
139
123
 
140
- const toIdentity = [
141
- this.rows[0],
142
- this.rows[1],
143
- this.rows[2],
144
- ];
124
+ const toIdentity = [this.rows[0], this.rows[1], this.rows[2]];
145
125
 
146
- const toResult = [
147
- Vec3.unitX,
148
- Vec3.unitY,
149
- Vec3.unitZ,
150
- ];
126
+ const toResult = [Vec3.unitX, Vec3.unitY, Vec3.unitZ];
151
127
 
152
128
  // Convert toIdentity to the identity matrix and
153
129
  // toResult to the inverse through elementary row operations
@@ -199,29 +175,27 @@ export class Mat33 {
199
175
  for (let i = 1; i <= 2; i++) {
200
176
  const otherRowIdx = (cursor + i) % 3;
201
177
  scale = -toIdentity[otherRowIdx].at(cursor);
202
- toIdentity[otherRowIdx] = toIdentity[otherRowIdx].plus(
203
- cursorToIdentityRow.times(scale)
204
- );
205
- toResult[otherRowIdx] = toResult[otherRowIdx].plus(
206
- cursorToResultRow.times(scale)
207
- );
178
+ toIdentity[otherRowIdx] = toIdentity[otherRowIdx].plus(cursorToIdentityRow.times(scale));
179
+ toResult[otherRowIdx] = toResult[otherRowIdx].plus(cursorToResultRow.times(scale));
208
180
  }
209
181
  }
210
182
 
211
- const inverse = Mat33.ofRows(
212
- toResult[0],
213
- toResult[1],
214
- toResult[2]
215
- );
183
+ const inverse = Mat33.ofRows(toResult[0], toResult[1], toResult[2]);
216
184
  this.cachedInverse = inverse;
217
185
  return inverse;
218
186
  }
219
187
 
220
188
  public transposed(): Mat33 {
221
189
  return new Mat33(
222
- this.a1, this.b1, this.c1,
223
- this.a2, this.b2, this.c2,
224
- this.a3, this.b3, this.c3
190
+ this.a1,
191
+ this.b1,
192
+ this.c1,
193
+ this.a2,
194
+ this.b2,
195
+ this.c2,
196
+ this.a3,
197
+ this.b3,
198
+ this.c3,
225
199
  );
226
200
  }
227
201
 
@@ -256,9 +230,15 @@ export class Mat33 {
256
230
  };
257
231
 
258
232
  return new Mat33(
259
- at(0, 0), at(0, 1), at(0, 2),
260
- at(1, 0), at(1, 1), at(1, 2),
261
- at(2, 0), at(2, 1), at(2, 2)
233
+ at(0, 0),
234
+ at(0, 1),
235
+ at(0, 2),
236
+ at(1, 0),
237
+ at(1, 1),
238
+ at(1, 2),
239
+ at(2, 0),
240
+ at(2, 1),
241
+ at(2, 2),
262
242
  );
263
243
  }
264
244
 
@@ -288,11 +268,7 @@ export class Mat33 {
288
268
  * This is the standard way of transforming vectors in ℝ³.
289
269
  */
290
270
  public transformVec3(other: Vec3): Vec3 {
291
- return Vec3.of(
292
- this.rows[0].dot(other),
293
- this.rows[1].dot(other),
294
- this.rows[2].dot(other)
295
- );
271
+ return Vec3.of(this.rows[0].dot(other), this.rows[1].dot(other), this.rows[2].dot(other));
296
272
  }
297
273
 
298
274
  /** @returns true iff this is the identity matrix. */
@@ -326,7 +302,7 @@ export class Mat33 {
326
302
  */
327
303
  public toString(): string {
328
304
  let result = '';
329
- const maxColumnLens = [ 0, 0, 0 ];
305
+ const maxColumnLens = [0, 0, 0];
330
306
 
331
307
  // Determine the longest item in each column so we can pad the others to that
332
308
  // length.
@@ -390,11 +366,7 @@ export class Mat33 {
390
366
  * ```
391
367
  */
392
368
  public toArray(): Mat33Array {
393
- return [
394
- this.a1, this.a2, this.a3,
395
- this.b1, this.b2, this.b3,
396
- this.c1, this.c2, this.c3,
397
- ];
369
+ return [this.a1, this.a2, this.a3, this.b1, this.b2, this.b3, this.c1, this.c2, this.c3];
398
370
  }
399
371
 
400
372
  /**
@@ -413,11 +385,17 @@ export class Mat33 {
413
385
  * // ⎣ 6, 7, 8 ⎦
414
386
  * ```
415
387
  */
416
- public mapEntries(mapping: (component: number, rowcol: [number, number])=>number): Mat33 {
388
+ public mapEntries(mapping: (component: number, rowcol: [number, number]) => number): Mat33 {
417
389
  return new Mat33(
418
- mapping(this.a1, [0, 0]), mapping(this.a2, [0, 1]), mapping(this.a3, [0, 2]),
419
- mapping(this.b1, [1, 0]), mapping(this.b2, [1, 1]), mapping(this.b3, [1, 2]),
420
- mapping(this.c1, [2, 0]), mapping(this.c2, [2, 1]), mapping(this.c3, [2, 2]),
390
+ mapping(this.a1, [0, 0]),
391
+ mapping(this.a2, [0, 1]),
392
+ mapping(this.a3, [0, 2]),
393
+ mapping(this.b1, [1, 0]),
394
+ mapping(this.b2, [1, 1]),
395
+ mapping(this.b3, [1, 2]),
396
+ mapping(this.c1, [2, 0]),
397
+ mapping(this.c2, [2, 1]),
398
+ mapping(this.c3, [2, 2]),
421
399
  );
422
400
  }
423
401
 
@@ -428,11 +406,7 @@ export class Mat33 {
428
406
 
429
407
  /** Returns the `idx`-th column (`idx` is 0-indexed). */
430
408
  public getColumn(idx: number) {
431
- return Vec3.of(
432
- this.rows[0].at(idx),
433
- this.rows[1].at(idx),
434
- this.rows[2].at(idx),
435
- );
409
+ return Vec3.of(this.rows[0].at(idx), this.rows[1].at(idx), this.rows[2].at(idx));
436
410
  }
437
411
 
438
412
  /** Returns the magnitude of the entry with the largest entry */
@@ -463,11 +437,7 @@ export class Mat33 {
463
437
  // Vec2s z = 1. As such,
464
438
  // outVec2.x = inVec2.x * 1 + inVec2.y * 0 + 1 * amount.x
465
439
  // ...
466
- return new Mat33(
467
- 1, 0, amount.x,
468
- 0, 1, amount.y,
469
- 0, 0, 1
470
- );
440
+ return new Mat33(1, 0, amount.x, 0, 1, amount.y, 0, 0, 1);
471
441
  }
472
442
 
473
443
  public static zRotation(radians: number, center: Point2 = Vec2.zero): Mat33 {
@@ -481,15 +451,11 @@ export class Mat33 {
481
451
  // Translate everything so that rotation is about the origin
482
452
  let result = Mat33.translation(center);
483
453
 
484
- result = result.rightMul(new Mat33(
485
- cos, -sin, 0,
486
- sin, cos, 0,
487
- 0, 0, 1
488
- ));
454
+ result = result.rightMul(new Mat33(cos, -sin, 0, sin, cos, 0, 0, 0, 1));
489
455
  return result.rightMul(Mat33.translation(center.times(-1)));
490
456
  }
491
457
 
492
- public static scaling2D(amount: number|Vec2, center: Point2 = Vec2.zero): Mat33 {
458
+ public static scaling2D(amount: number | Vec2, center: Point2 = Vec2.zero): Mat33 {
493
459
  let result = Mat33.translation(center);
494
460
  let xAmount, yAmount;
495
461
 
@@ -501,11 +467,7 @@ export class Mat33 {
501
467
  yAmount = amount.y;
502
468
  }
503
469
 
504
- result = result.rightMul(new Mat33(
505
- xAmount, 0, 0,
506
- 0, yAmount, 0,
507
- 0, 0, 1
508
- ));
470
+ result = result.rightMul(new Mat33(xAmount, 0, 0, 0, yAmount, 0, 0, 0, 1));
509
471
 
510
472
  // Translate such that [center] goes to (0, 0)
511
473
  return result.rightMul(Mat33.translation(center.times(-1)));
@@ -536,7 +498,7 @@ export class Mat33 {
536
498
  }
537
499
 
538
500
  const parseArguments = (argumentString: string): number[] => {
539
- const parsed = argumentString.split(/[, \t\n]+/g).map(argString => {
501
+ const parsed = argumentString.split(/[, \t\n]+/g).map((argString) => {
540
502
  // Handle trailing spaces/commands
541
503
  if (argString.trim() === '') {
542
504
  return null;
@@ -549,18 +511,16 @@ export class Mat33 {
549
511
  }
550
512
 
551
513
  // Remove trailing px units.
552
- argString = argString.replace(/px$/ig, '');
514
+ argString = argString.replace(/px$/gi, '');
553
515
 
554
516
  const numberExp = /^[-]?\d*(?:\.\d*)?(?:[eE][-+]?\d+)?$/i;
555
517
 
556
518
  if (!numberExp.exec(argString)) {
557
519
  throw new Error(
558
- `All arguments to transform functions must be numeric (state: ${
559
- JSON.stringify({
560
- currentArgument: argString,
561
- allArguments: argumentString,
562
- })
563
- })`
520
+ `All arguments to transform functions must be numeric (state: ${JSON.stringify({
521
+ currentArgument: argString,
522
+ allArguments: argumentString,
523
+ })})`,
564
524
  );
565
525
  }
566
526
 
@@ -572,10 +532,9 @@ export class Mat33 {
572
532
 
573
533
  return argNumber;
574
534
  });
575
- return parsed.filter(n => n !== null);
535
+ return parsed.filter((n) => n !== null);
576
536
  };
577
537
 
578
-
579
538
  const keywordToAction = {
580
539
  matrix: (matrixData: number[]) => {
581
540
  if (matrixData.length !== 6) {
@@ -589,11 +548,7 @@ export class Mat33 {
589
548
  const e = matrixData[4];
590
549
  const f = matrixData[5];
591
550
 
592
- const transform = new Mat33(
593
- a, c, e,
594
- b, d, f,
595
- 0, 0, 1
596
- );
551
+ const transform = new Mat33(a, c, e, b, d, f, 0, 0, 1);
597
552
  return transform;
598
553
  },
599
554
 
@@ -623,7 +578,9 @@ export class Mat33 {
623
578
  translateX = translateArgs[0];
624
579
  translateY = translateArgs[1];
625
580
  } else {
626
- throw new Error(`The translate() function requires either 1 or 2 arguments. Given ${translateArgs}`);
581
+ throw new Error(
582
+ `The translate() function requires either 1 or 2 arguments. Given ${translateArgs}`,
583
+ );
627
584
  }
628
585
 
629
586
  return Mat33.translation(Vec2.of(translateX, translateY));
@@ -632,9 +589,9 @@ export class Mat33 {
632
589
 
633
590
  // A command (\w+)
634
591
  // followed by a set of arguments ([ \t\n0-9eE.,\-%]+)
635
- const partRegex = /\s*(\w+)\s*\(([^)]*)\)/ig;
592
+ const partRegex = /\s*(\w+)\s*\(([^)]*)\)/gi;
636
593
  let match;
637
- let matrix: Mat33|null = null;
594
+ let matrix: Mat33 | null = null;
638
595
 
639
596
  while ((match = partRegex.exec(cssString)) !== null) {
640
597
  const action = match[1].toLowerCase();
package/src/Vec2.test.ts CHANGED
@@ -17,11 +17,11 @@ describe('Vec2', () => {
17
17
  });
18
18
 
19
19
  it('More complicated expressions', () => {
20
- expect((Vec2.of(1, 2).plus(Vec2.of(3, 4))).times(2)).objEq(Vec2.of(8, 12));
20
+ expect(Vec2.of(1, 2).plus(Vec2.of(3, 4)).times(2)).objEq(Vec2.of(8, 12));
21
21
  });
22
22
 
23
23
  it('Angle', () => {
24
- expect(Vec2.of(-1, 1).angle()).toBeCloseTo(3 * Math.PI / 4);
24
+ expect(Vec2.of(-1, 1).angle()).toBeCloseTo((3 * Math.PI) / 4);
25
25
  });
26
26
 
27
27
  it('Perpindicular', () => {
@@ -29,4 +29,4 @@ describe('Vec2', () => {
29
29
  expect(Vec2.unitX.cross(Vec3.unitZ)).objEq(Vec2.unitY.times(-1), tolerance);
30
30
  expect(Vec2.unitX.orthog()).objEq(Vec2.unitY, tolerance);
31
31
  });
32
- });
32
+ });
package/src/Vec3.test.ts CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import Vec3 from './Vec3';
3
2
 
4
3
  describe('Vec3', () => {
@@ -60,7 +59,7 @@ describe('Vec3', () => {
60
59
  { from: Vec3.of(-1, -10, 0), to: Vec3.of(1, 2, 0), expected: 148 },
61
60
  ])(
62
61
  '.squareDistanceTo and .distanceTo should return correct square and euclidean distances (%j)',
63
- ({ from , to, expected }) => {
62
+ ({ from, to, expected }) => {
64
63
  expect(from.squareDistanceTo(to)).toBe(expected);
65
64
  expect(to.squareDistanceTo(from)).toBe(expected);
66
65
  expect(to.distanceTo(from)).toBeCloseTo(Math.sqrt(expected));
@@ -83,4 +82,4 @@ describe('Vec3', () => {
83
82
  expect(a.eq(b, tolerance)).toBe(eq);
84
83
  expect(b.eq(a, tolerance)).toBe(eq);
85
84
  });
86
- });
85
+ });
package/src/Vec3.ts CHANGED
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  /**
4
2
  * A vector with three components, $\begin{pmatrix} x \\ y \\ z \end{pmatrix}$.
5
3
  * Can also be used to represent a two-component vector.
@@ -28,7 +26,7 @@ export interface Vec3 {
28
26
  * Returns the x, y components of this.
29
27
  * May be implemented as a getter method.
30
28
  */
31
- readonly xy: { x: number, y: number };
29
+ readonly xy: { x: number; y: number };
32
30
 
33
31
  /** Returns the vector's `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
34
32
  at(i: number): number;
@@ -124,7 +122,7 @@ export interface Vec3 {
124
122
  * Vec3.of(1, 2, 3).scale(Vec3.of(2, 4, 6)); // → Vec3(2, 8, 18)
125
123
  * ```
126
124
  */
127
- scale(other: Vec3|number): Vec3;
125
+ scale(other: Vec3 | number): Vec3;
128
126
 
129
127
  /**
130
128
  * Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
@@ -154,9 +152,7 @@ export interface Vec3 {
154
152
  * console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
155
153
  * ```
156
154
  */
157
- zip(
158
- other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
159
- ): Vec3;
155
+ zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
160
156
 
161
157
  /**
162
158
  * Returns a vector with each component acted on by `fn`.
@@ -167,10 +163,9 @@ export interface Vec3 {
167
163
  * console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
168
164
  * ```
169
165
  */
170
- map(fn: (component: number, index: number)=> number): Vec3;
171
-
172
- asArray(): [ number, number, number ];
166
+ map(fn: (component: number, index: number) => number): Vec3;
173
167
 
168
+ asArray(): [number, number, number];
174
169
 
175
170
  /**
176
171
  * [fuzz] The maximum difference between two components for this and [other]
@@ -196,9 +191,8 @@ class Vec3Impl implements Vec3 {
196
191
  public constructor(
197
192
  public readonly x: number,
198
193
  public readonly y: number,
199
- public readonly z: number
200
- ) {
201
- }
194
+ public readonly z: number,
195
+ ) {}
202
196
 
203
197
  public get xy(): { x: number; y: number } {
204
198
  // Useful for APIs that behave differently if .z is present.
@@ -288,16 +282,12 @@ class Vec3Impl implements Vec3 {
288
282
  );
289
283
  }
290
284
 
291
- public scale(other: Vec3|number): Vec3 {
285
+ public scale(other: Vec3 | number): Vec3 {
292
286
  if (typeof other === 'number') {
293
287
  return this.times(other);
294
288
  }
295
289
 
296
- return Vec3.of(
297
- this.x * other.x,
298
- this.y * other.y,
299
- this.z * other.z,
300
- );
290
+ return Vec3.of(this.x * other.x, this.y * other.y, this.z * other.z);
301
291
  }
302
292
 
303
293
  public orthog(): Vec3 {
@@ -318,28 +308,25 @@ class Vec3Impl implements Vec3 {
318
308
  }
319
309
 
320
310
  public zip(
321
- other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
311
+ other: Vec3,
312
+ zip: (componentInThis: number, componentInOther: number) => number,
322
313
  ): Vec3 {
323
- return Vec3.of(
324
- zip(other.x, this.x),
325
- zip(other.y, this.y),
326
- zip(other.z, this.z)
327
- );
314
+ return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, this.z));
328
315
  }
329
316
 
330
- public map(fn: (component: number, index: number)=> number): Vec3 {
317
+ public map(fn: (component: number, index: number) => number): Vec3 {
331
318
  return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(this.z, 2));
332
319
  }
333
320
 
334
- public asArray(): [ number, number, number ] {
321
+ public asArray(): [number, number, number] {
335
322
  return [this.x, this.y, this.z];
336
323
  }
337
324
 
338
325
  public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
339
326
  return (
340
- Math.abs(other.x - this.x) <= fuzz
341
- && Math.abs(other.y - this.y) <= fuzz
342
- && Math.abs(other.z - this.z) <= fuzz
327
+ Math.abs(other.x - this.x) <= fuzz &&
328
+ Math.abs(other.y - this.y) <= fuzz &&
329
+ Math.abs(other.z - this.z) <= fuzz
343
330
  );
344
331
  }
345
332
 
@@ -352,10 +339,11 @@ class Vec2Impl implements Vec3 {
352
339
  public constructor(
353
340
  public readonly x: number,
354
341
  public readonly y: number,
355
- ) {
356
- }
342
+ ) {}
357
343
 
358
- public get z() { return 0; }
344
+ public get z() {
345
+ return 0;
346
+ }
359
347
 
360
348
  public get xy(): { x: number; y: number } {
361
349
  // Useful for APIs that behave differently if .z is present.
@@ -436,22 +424,15 @@ class Vec2Impl implements Vec3 {
436
424
  // | i j k |
437
425
  // | x1 y1 z1| = (i)(y1z2 - y2z1) - (j)(x1z2 - x2z1) + (k)(x1y2 - x2y1)
438
426
  // | x2 y2 z2|
439
- return Vec3.of(
440
- this.y * other.z,
441
- -this.x * other.z,
442
- this.x * other.y - other.x * this.y,
443
- );
427
+ return Vec3.of(this.y * other.z, -this.x * other.z, this.x * other.y - other.x * this.y);
444
428
  }
445
429
 
446
- public scale(other: Vec3|number): Vec3 {
430
+ public scale(other: Vec3 | number): Vec3 {
447
431
  if (typeof other === 'number') {
448
432
  return this.times(other);
449
433
  }
450
434
 
451
- return Vec2.of(
452
- this.x * other.x,
453
- this.y * other.y,
454
- );
435
+ return Vec2.of(this.x * other.x, this.y * other.y);
455
436
  }
456
437
 
457
438
  public orthog(): Vec3 {
@@ -472,30 +453,25 @@ class Vec2Impl implements Vec3 {
472
453
  }
473
454
 
474
455
  public zip(
475
- other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
456
+ other: Vec3,
457
+ zip: (componentInThis: number, componentInOther: number) => number,
476
458
  ): Vec3 {
477
- return Vec3.of(
478
- zip(other.x, this.x),
479
- zip(other.y, this.y),
480
- zip(other.z, 0),
481
- );
459
+ return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, 0));
482
460
  }
483
461
 
484
- public map(fn: (component: number, index: number)=> number): Vec3 {
485
- return Vec3.of(
486
- fn(this.x, 0), fn(this.y, 1), fn(0, 2)
487
- );
462
+ public map(fn: (component: number, index: number) => number): Vec3 {
463
+ return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(0, 2));
488
464
  }
489
465
 
490
- public asArray(): [ number, number, number ] {
466
+ public asArray(): [number, number, number] {
491
467
  return [this.x, this.y, 0];
492
468
  }
493
469
 
494
470
  public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
495
471
  return (
496
- Math.abs(other.x - this.x) <= fuzz
497
- && Math.abs(other.y - this.y) <= fuzz
498
- && Math.abs(other.z) <= fuzz
472
+ Math.abs(other.x - this.x) <= fuzz &&
473
+ Math.abs(other.y - this.y) <= fuzz &&
474
+ Math.abs(other.z) <= fuzz
499
475
  );
500
476
  }
501
477
 
@@ -537,7 +513,7 @@ export namespace Vec2 {
537
513
  * const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
538
514
  * ```
539
515
  */
540
- export const ofXY = ({x, y}: {x: number, y: number}) => {
516
+ export const ofXY = ({ x, y }: { x: number; y: number }) => {
541
517
  return Vec2.of(x, y);
542
518
  };
543
519
 
package/src/lib.ts CHANGED
@@ -20,7 +20,6 @@
20
20
  export { LineSegment2 } from './shapes/LineSegment2';
21
21
  export {
22
22
  Path,
23
-
24
23
  IntersectionResult as PathIntersectionResult,
25
24
  CurveIndexRecord as PathCurveIndex,
26
25
  stepCurveIndexBy as stepPathIndexBy,
@@ -43,6 +42,5 @@ export { Vec3 } from './Vec3';
43
42
  export { Color4 } from './Color4';
44
43
  export * from './rounding/lib';
45
44
 
46
-
47
45
  // Note: All above exports cannot use `export { default as ... } from "..."` because this
48
46
  // breaks TypeDoc -- TypeDoc otherwise labels any imports of these classes as `default`.
@@ -1,9 +1,8 @@
1
-
2
1
  import solveQuadratic from './solveQuadratic';
3
2
 
4
3
  describe('solveQuadratic', () => {
5
4
  it('should solve linear equations', () => {
6
- expect(solveQuadratic(0, 1, 2)).toMatchObject([ -2, -2 ]);
5
+ expect(solveQuadratic(0, 1, 2)).toMatchObject([-2, -2]);
7
6
  expect(solveQuadratic(0, 0, 2)[0]).toBeNaN();
8
7
  });
9
8
 
@@ -11,21 +10,48 @@ describe('solveQuadratic', () => {
11
10
  type TestCase = [[number, number, number], [number, number]];
12
11
 
13
12
  const testCases: TestCase[] = [
14
- [ [ 1, 0, 0 ], [ 0, 0 ] ],
15
- [ [ 2, 0, 0 ], [ 0, 0 ] ],
13
+ [
14
+ [1, 0, 0],
15
+ [0, 0],
16
+ ],
17
+ [
18
+ [2, 0, 0],
19
+ [0, 0],
20
+ ],
16
21
 
17
- [ [ 1, 0, -1 ], [ 1, -1 ] ],
18
- [ [ 1, 0, -4 ], [ 2, -2 ] ],
19
- [ [ 1, 0, 4 ], [ NaN, NaN ] ],
22
+ [
23
+ [1, 0, -1],
24
+ [1, -1],
25
+ ],
26
+ [
27
+ [1, 0, -4],
28
+ [2, -2],
29
+ ],
30
+ [
31
+ [1, 0, 4],
32
+ [NaN, NaN],
33
+ ],
20
34
 
21
- [ [ 1, 1, 0 ], [ 0, -1 ] ],
22
- [ [ 1, 2, 0 ], [ 0, -2 ] ],
35
+ [
36
+ [1, 1, 0],
37
+ [0, -1],
38
+ ],
39
+ [
40
+ [1, 2, 0],
41
+ [0, -2],
42
+ ],
23
43
 
24
- [ [ 1, 2, 1 ], [ -1, -1 ] ],
25
- [ [ -9, 2, 1/3 ], [ 1/3, -1/9 ] ],
44
+ [
45
+ [1, 2, 1],
46
+ [-1, -1],
47
+ ],
48
+ [
49
+ [-9, 2, 1 / 3],
50
+ [1 / 3, -1 / 9],
51
+ ],
26
52
  ];
27
53
 
28
- for (const [ testCase, solution ] of testCases) {
54
+ for (const [testCase, solution] of testCases) {
29
55
  const foundSolutions = solveQuadratic(...testCase);
30
56
  for (let i = 0; i < 2; i++) {
31
57
  if (isNaN(solution[i]) && isNaN(foundSolutions[i])) {
@@ -36,4 +62,4 @@ describe('solveQuadratic', () => {
36
62
  }
37
63
  }
38
64
  });
39
- });
65
+ });
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Solves an equation of the form ax² + bx + c = 0.
4
3
  * The larger solution is returned first.
@@ -21,13 +20,13 @@ const solveQuadratic = (a: number, b: number, c: number): [number, number] => {
21
20
  solution = -c / b;
22
21
  }
23
22
 
24
- return [ solution, solution ];
23
+ return [solution, solution];
25
24
  }
26
25
 
27
26
  const discriminant = b * b - 4 * a * c;
28
27
 
29
28
  if (discriminant < 0) {
30
- return [ NaN, NaN ];
29
+ return [NaN, NaN];
31
30
  }
32
31
 
33
32
  const rootDiscriminant = Math.sqrt(discriminant);
@@ -35,9 +34,9 @@ const solveQuadratic = (a: number, b: number, c: number): [number, number] => {
35
34
  const solution2 = (-b - rootDiscriminant) / (2 * a);
36
35
 
37
36
  if (solution1 > solution2) {
38
- return [ solution1, solution2 ];
37
+ return [solution1, solution2];
39
38
  } else {
40
- return [ solution2, solution1 ];
39
+ return [solution2, solution1];
41
40
  }
42
41
  };
43
- export default solveQuadratic;
42
+ export default solveQuadratic;
@@ -12,4 +12,4 @@ it('cleanUpNumber', () => {
12
12
  expect(cleanUpNumber('1234.5')).toBe('1234.5');
13
13
  expect(cleanUpNumber('1234.500')).toBe('1234.5');
14
14
  expect(cleanUpNumber('1.1368683772161603e-13')).toBe('0');
15
- });
15
+ });