@js-draw/math 1.21.3 → 1.23.1

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 (81) hide show
  1. package/build-config.json +1 -1
  2. package/dist/cjs/Color4.d.ts +24 -1
  3. package/dist/cjs/Color4.js +35 -3
  4. package/dist/cjs/Mat33.d.ts +21 -11
  5. package/dist/cjs/Mat33.js +28 -24
  6. package/dist/cjs/Vec3.d.ts +12 -3
  7. package/dist/cjs/Vec3.js +20 -9
  8. package/dist/cjs/lib.d.ts +3 -0
  9. package/dist/cjs/lib.js +3 -0
  10. package/dist/cjs/shapes/BezierJSWrapper.d.ts +2 -0
  11. package/dist/cjs/shapes/BezierJSWrapper.js +22 -13
  12. package/dist/cjs/shapes/LineSegment2.js +13 -17
  13. package/dist/cjs/shapes/Parameterized2DShape.js +1 -1
  14. package/dist/cjs/shapes/Path.d.ts +1 -0
  15. package/dist/cjs/shapes/Path.js +50 -47
  16. package/dist/cjs/shapes/QuadraticBezier.d.ts +19 -2
  17. package/dist/cjs/shapes/QuadraticBezier.js +26 -3
  18. package/dist/cjs/shapes/Rect2.d.ts +13 -0
  19. package/dist/cjs/shapes/Rect2.js +35 -16
  20. package/dist/cjs/shapes/Triangle.js +4 -5
  21. package/dist/cjs/utils/convexHull2Of.js +3 -3
  22. package/dist/mjs/Color4.d.ts +24 -1
  23. package/dist/mjs/Color4.mjs +35 -3
  24. package/dist/mjs/Mat33.d.ts +21 -11
  25. package/dist/mjs/Mat33.mjs +28 -24
  26. package/dist/mjs/Vec3.d.ts +12 -3
  27. package/dist/mjs/Vec3.mjs +20 -9
  28. package/dist/mjs/lib.d.ts +3 -0
  29. package/dist/mjs/lib.mjs +3 -0
  30. package/dist/mjs/shapes/BezierJSWrapper.d.ts +2 -0
  31. package/dist/mjs/shapes/BezierJSWrapper.mjs +22 -13
  32. package/dist/mjs/shapes/LineSegment2.mjs +13 -17
  33. package/dist/mjs/shapes/Parameterized2DShape.mjs +1 -1
  34. package/dist/mjs/shapes/Path.d.ts +1 -0
  35. package/dist/mjs/shapes/Path.mjs +50 -47
  36. package/dist/mjs/shapes/QuadraticBezier.d.ts +19 -2
  37. package/dist/mjs/shapes/QuadraticBezier.mjs +26 -3
  38. package/dist/mjs/shapes/Rect2.d.ts +13 -0
  39. package/dist/mjs/shapes/Rect2.mjs +35 -16
  40. package/dist/mjs/shapes/Triangle.mjs +4 -5
  41. package/dist/mjs/utils/convexHull2Of.mjs +3 -3
  42. package/dist-test/test_imports/test-require.cjs +1 -1
  43. package/package.json +3 -3
  44. package/src/Color4.test.ts +21 -21
  45. package/src/Color4.ts +61 -18
  46. package/src/Mat33.fromCSSMatrix.test.ts +32 -46
  47. package/src/Mat33.test.ts +64 -102
  48. package/src/Mat33.ts +81 -104
  49. package/src/Vec2.test.ts +3 -3
  50. package/src/Vec3.test.ts +2 -3
  51. package/src/Vec3.ts +46 -61
  52. package/src/lib.ts +3 -2
  53. package/src/polynomial/solveQuadratic.test.ts +39 -13
  54. package/src/polynomial/solveQuadratic.ts +5 -6
  55. package/src/rounding/cleanUpNumber.test.ts +1 -1
  56. package/src/rounding/constants.ts +1 -3
  57. package/src/rounding/getLenAfterDecimal.ts +1 -2
  58. package/src/rounding/lib.ts +1 -2
  59. package/src/rounding/toRoundedString.test.ts +1 -1
  60. package/src/rounding/toStringOfSamePrecision.test.ts +1 -2
  61. package/src/rounding/toStringOfSamePrecision.ts +1 -1
  62. package/src/shapes/BezierJSWrapper.ts +56 -37
  63. package/src/shapes/CubicBezier.ts +3 -3
  64. package/src/shapes/LineSegment2.test.ts +24 -17
  65. package/src/shapes/LineSegment2.ts +26 -29
  66. package/src/shapes/Parameterized2DShape.ts +5 -4
  67. package/src/shapes/Path.fromString.test.ts +5 -5
  68. package/src/shapes/Path.test.ts +122 -120
  69. package/src/shapes/Path.toString.test.ts +7 -7
  70. package/src/shapes/Path.ts +379 -352
  71. package/src/shapes/PointShape2D.ts +3 -3
  72. package/src/shapes/QuadraticBezier.test.ts +27 -21
  73. package/src/shapes/QuadraticBezier.ts +26 -11
  74. package/src/shapes/Rect2.test.ts +44 -75
  75. package/src/shapes/Rect2.ts +47 -35
  76. package/src/shapes/Triangle.test.ts +31 -29
  77. package/src/shapes/Triangle.ts +17 -18
  78. package/src/utils/convexHull2Of.test.ts +54 -15
  79. package/src/utils/convexHull2Of.ts +9 -7
  80. package/tsconfig.json +1 -3
  81. 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,13 +437,29 @@ 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
 
443
+ /**
444
+ * Creates a matrix for rotating `Vec2`s about `center` by some number of `radians`.
445
+ *
446
+ * For this function, {@link Vec2}s are considered to be points in 2D space.
447
+ *
448
+ * For example,
449
+ * ```ts,runnable,console
450
+ * import { Mat33, Vec2 } from '@js-draw/math';
451
+ *
452
+ * const halfCircle = Math.PI; // PI radians = 180 degrees = 1/2 circle
453
+ * const center = Vec2.of(1, 1); // The point (1,1)
454
+ * const rotationMatrix = Mat33.zRotation(halfCircle, center);
455
+ *
456
+ * console.log(
457
+ * 'Rotating (0,0) 180deg about', center, 'results in',
458
+ * // Rotates (0,0)
459
+ * rotationMatrix.transformVec2(Vec2.zero),
460
+ * );
461
+ * ```
462
+ */
473
463
  public static zRotation(radians: number, center: Point2 = Vec2.zero): Mat33 {
474
464
  if (radians === 0) {
475
465
  return Mat33.identity;
@@ -481,15 +471,11 @@ export class Mat33 {
481
471
  // Translate everything so that rotation is about the origin
482
472
  let result = Mat33.translation(center);
483
473
 
484
- result = result.rightMul(new Mat33(
485
- cos, -sin, 0,
486
- sin, cos, 0,
487
- 0, 0, 1
488
- ));
474
+ result = result.rightMul(new Mat33(cos, -sin, 0, sin, cos, 0, 0, 0, 1));
489
475
  return result.rightMul(Mat33.translation(center.times(-1)));
490
476
  }
491
477
 
492
- public static scaling2D(amount: number|Vec2, center: Point2 = Vec2.zero): Mat33 {
478
+ public static scaling2D(amount: number | Vec2, center: Point2 = Vec2.zero): Mat33 {
493
479
  let result = Mat33.translation(center);
494
480
  let xAmount, yAmount;
495
481
 
@@ -501,11 +487,7 @@ export class Mat33 {
501
487
  yAmount = amount.y;
502
488
  }
503
489
 
504
- result = result.rightMul(new Mat33(
505
- xAmount, 0, 0,
506
- 0, yAmount, 0,
507
- 0, 0, 1
508
- ));
490
+ result = result.rightMul(new Mat33(xAmount, 0, 0, 0, yAmount, 0, 0, 0, 1));
509
491
 
510
492
  // Translate such that [center] goes to (0, 0)
511
493
  return result.rightMul(Mat33.translation(center.times(-1)));
@@ -536,7 +518,7 @@ export class Mat33 {
536
518
  }
537
519
 
538
520
  const parseArguments = (argumentString: string): number[] => {
539
- const parsed = argumentString.split(/[, \t\n]+/g).map(argString => {
521
+ const parsed = argumentString.split(/[, \t\n]+/g).map((argString) => {
540
522
  // Handle trailing spaces/commands
541
523
  if (argString.trim() === '') {
542
524
  return null;
@@ -549,18 +531,16 @@ export class Mat33 {
549
531
  }
550
532
 
551
533
  // Remove trailing px units.
552
- argString = argString.replace(/px$/ig, '');
534
+ argString = argString.replace(/px$/gi, '');
553
535
 
554
536
  const numberExp = /^[-]?\d*(?:\.\d*)?(?:[eE][-+]?\d+)?$/i;
555
537
 
556
538
  if (!numberExp.exec(argString)) {
557
539
  throw new Error(
558
- `All arguments to transform functions must be numeric (state: ${
559
- JSON.stringify({
560
- currentArgument: argString,
561
- allArguments: argumentString,
562
- })
563
- })`
540
+ `All arguments to transform functions must be numeric (state: ${JSON.stringify({
541
+ currentArgument: argString,
542
+ allArguments: argumentString,
543
+ })})`,
564
544
  );
565
545
  }
566
546
 
@@ -572,10 +552,9 @@ export class Mat33 {
572
552
 
573
553
  return argNumber;
574
554
  });
575
- return parsed.filter(n => n !== null);
555
+ return parsed.filter((n) => n !== null);
576
556
  };
577
557
 
578
-
579
558
  const keywordToAction = {
580
559
  matrix: (matrixData: number[]) => {
581
560
  if (matrixData.length !== 6) {
@@ -589,11 +568,7 @@ export class Mat33 {
589
568
  const e = matrixData[4];
590
569
  const f = matrixData[5];
591
570
 
592
- const transform = new Mat33(
593
- a, c, e,
594
- b, d, f,
595
- 0, 0, 1
596
- );
571
+ const transform = new Mat33(a, c, e, b, d, f, 0, 0, 1);
597
572
  return transform;
598
573
  },
599
574
 
@@ -623,7 +598,9 @@ export class Mat33 {
623
598
  translateX = translateArgs[0];
624
599
  translateY = translateArgs[1];
625
600
  } else {
626
- throw new Error(`The translate() function requires either 1 or 2 arguments. Given ${translateArgs}`);
601
+ throw new Error(
602
+ `The translate() function requires either 1 or 2 arguments. Given ${translateArgs}`,
603
+ );
627
604
  }
628
605
 
629
606
  return Mat33.translation(Vec2.of(translateX, translateY));
@@ -632,9 +609,9 @@ export class Mat33 {
632
609
 
633
610
  // A command (\w+)
634
611
  // followed by a set of arguments ([ \t\n0-9eE.,\-%]+)
635
- const partRegex = /\s*(\w+)\s*\(([^)]*)\)/ig;
612
+ const partRegex = /\s*(\w+)\s*\(([^)]*)\)/gi;
636
613
  let match;
637
- let matrix: Mat33|null = null;
614
+ let matrix: Mat33 | null = null;
638
615
 
639
616
  while ((match = partRegex.exec(cssString)) !== null) {
640
617
  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,13 +163,12 @@ 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
- * [fuzz] The maximum difference between two components for this and [other]
171
+ * @param tolerance The maximum difference between two components for this and [other]
177
172
  * to be considered equal.
178
173
  *
179
174
  * @example
@@ -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
 
@@ -505,12 +481,16 @@ class Vec2Impl implements Vec3 {
505
481
  }
506
482
 
507
483
  /**
508
- * A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
484
+ * A `Vec2` is a {@link Vec3} optimized for working in a plane. `Vec2`s have an
509
485
  * always-zero `z` component.
510
486
  *
511
487
  * ```ts,runnable,console
512
488
  * import { Vec2 } from '@js-draw/math';
513
- * console.log(Vec2.of(1, 2));
489
+ *
490
+ * const v = Vec2.of(1, 2);
491
+ * console.log('a Vec2:', v);
492
+ * console.log('x component:', v.x);
493
+ * console.log('z component:', v.z);
514
494
  * ```
515
495
  */
516
496
  export namespace Vec2 {
@@ -537,7 +517,7 @@ export namespace Vec2 {
537
517
  * const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
538
518
  * ```
539
519
  */
540
- export const ofXY = ({x, y}: {x: number, y: number}) => {
520
+ export const ofXY = ({ x, y }: { x: number; y: number }) => {
541
521
  return Vec2.of(x, y);
542
522
  };
543
523
 
@@ -551,6 +531,7 @@ export namespace Vec2 {
551
531
  export const zero = Vec2.of(0, 0);
552
532
  }
553
533
 
534
+ /** Contains static methods for constructing a {@link Vec3}. */
554
535
  export namespace Vec3 {
555
536
  /**
556
537
  * Construct a vector from three components.
@@ -559,6 +540,7 @@ export namespace Vec3 {
559
540
  * ```ts,runnable,console
560
541
  * import { Vec3 } from '@js-draw/math';
561
542
  * const v1 = Vec3.of(1, 2, 3);
543
+ * console.log(v1.plus(Vec3.of(0, 100, 0)));
562
544
  * ```
563
545
  */
564
546
  export const of = (x: number, y: number, z: number): Vec3 => {
@@ -569,8 +551,11 @@ export namespace Vec3 {
569
551
  }
570
552
  };
571
553
 
554
+ /** A unit vector in the x direction (`[1, 0, 0]`). */
572
555
  export const unitX = Vec2.unitX;
556
+ /** A unit vector in the y direction (`[0, 1, 0]`). */
573
557
  export const unitY = Vec2.unitY;
558
+ /** The zero vector (`[0, 0, 0]`). */
574
559
  export const zero = Vec2.zero;
575
560
 
576
561
  /** A vector of length 1 in the z direction. */
package/src/lib.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  /**
2
+ * This package contains general math utilities used by `js-draw`.
3
+ * These include 2D and 3D vectors, 2D paths, and 3x3 matrices.
4
+ *
2
5
  * ```ts,runnable,console
3
6
  * import { Vec2, Mat33, Rect2 } from '@js-draw/math';
4
7
  *
@@ -20,7 +23,6 @@
20
23
  export { LineSegment2 } from './shapes/LineSegment2';
21
24
  export {
22
25
  Path,
23
-
24
26
  IntersectionResult as PathIntersectionResult,
25
27
  CurveIndexRecord as PathCurveIndex,
26
28
  stepCurveIndexBy as stepPathIndexBy,
@@ -43,6 +45,5 @@ export { Vec3 } from './Vec3';
43
45
  export { Color4 } from './Color4';
44
46
  export * from './rounding/lib';
45
47
 
46
-
47
48
  // Note: All above exports cannot use `export { default as ... } from "..."` because this
48
49
  // breaks TypeDoc -- TypeDoc otherwise labels any imports of these classes as `default`.