@js-draw/math 1.21.3 → 1.23.1

Sign up to get free protection for your applications and to get access to all the features.
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/build-config.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "inDirectory": "./src",
3
3
  "outDirectory": "./dist"
4
- }
4
+ }
@@ -28,9 +28,32 @@ export declare class Color4 {
28
28
  * Each component should be in the range [0, 1].
29
29
  */
30
30
  static ofRGB(red: number, green: number, blue: number): Color4;
31
+ /**
32
+ * Creates a color from red, green, blue, and transparency components. Each component should
33
+ * be in the range $[0, 1]$.
34
+ */
31
35
  static ofRGBA(red: number, green: number, blue: number, alpha: number): Color4;
36
+ /**
37
+ * Creates a color from an RGB (or RGBA) array.
38
+ *
39
+ * This is similar to {@link ofRGB} and {@link ofRGBA}, but, by default, takes values
40
+ * that range from 0 to 255.
41
+ *
42
+ * If the array values instead range from 0-1, pass `maxValue` as `1`.
43
+ */
44
+ static fromRGBArray(array: Uint8Array | Uint8ClampedArray | number[], maxValue?: number): Color4;
45
+ /**
46
+ * Creates a `Color4` from a three or four-component hexadecimal
47
+ * [color string](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet).
48
+ *
49
+ * Example:
50
+ * ```ts,runnable,console
51
+ * import { Color4 } from '@js-draw/math';
52
+ * console.log(Color4.fromHex('#ff0'));
53
+ * ```
54
+ */
32
55
  static fromHex(hexString: string): Color4;
33
- /** Like fromHex, but can handle additional colors if an `HTMLCanvasElement` is available. */
56
+ /** Like {@link fromHex}, but can handle additional colors if an `HTMLCanvasElement` is available. */
34
57
  static fromString(text: string): Color4;
35
58
  /** @returns true if `this` and `other` are approximately equal. */
36
59
  eq(other: Color4 | null | undefined): boolean;
@@ -42,6 +42,10 @@ class Color4 {
42
42
  static ofRGB(red, green, blue) {
43
43
  return Color4.ofRGBA(red, green, blue, 1.0);
44
44
  }
45
+ /**
46
+ * Creates a color from red, green, blue, and transparency components. Each component should
47
+ * be in the range $[0, 1]$.
48
+ */
45
49
  static ofRGBA(red, green, blue, alpha) {
46
50
  red = Math.max(0, Math.min(red, 1));
47
51
  green = Math.max(0, Math.min(green, 1));
@@ -49,6 +53,34 @@ class Color4 {
49
53
  alpha = Math.max(0, Math.min(alpha, 1));
50
54
  return new Color4(red, green, blue, alpha);
51
55
  }
56
+ /**
57
+ * Creates a color from an RGB (or RGBA) array.
58
+ *
59
+ * This is similar to {@link ofRGB} and {@link ofRGBA}, but, by default, takes values
60
+ * that range from 0 to 255.
61
+ *
62
+ * If the array values instead range from 0-1, pass `maxValue` as `1`.
63
+ */
64
+ static fromRGBArray(array, maxValue = 255) {
65
+ const red = array[0];
66
+ const green = array[1] ?? red;
67
+ const blue = array[2] ?? red;
68
+ let alpha = 255;
69
+ if (3 < array.length) {
70
+ alpha = array[3];
71
+ }
72
+ return Color4.ofRGBA(red / maxValue, green / maxValue, blue / maxValue, alpha / maxValue);
73
+ }
74
+ /**
75
+ * Creates a `Color4` from a three or four-component hexadecimal
76
+ * [color string](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet).
77
+ *
78
+ * Example:
79
+ * ```ts,runnable,console
80
+ * import { Color4 } from '@js-draw/math';
81
+ * console.log(Color4.fromHex('#ff0'));
82
+ * ```
83
+ */
52
84
  static fromHex(hexString) {
53
85
  // Remove starting '#' (if present)
54
86
  hexString = (hexString.match(/^[#]?(.*)$/) ?? [])[1];
@@ -61,7 +93,7 @@ class Color4 {
61
93
  // Each character is a component
62
94
  const components = hexString.split('');
63
95
  // Convert to RRGGBBAA or RRGGBB format
64
- hexString = components.map(component => `${component}0`).join('');
96
+ hexString = components.map((component) => `${component}0`).join('');
65
97
  }
66
98
  if (hexString.length === 6) {
67
99
  // Alpha component
@@ -77,7 +109,7 @@ class Color4 {
77
109
  }
78
110
  return Color4.ofRGBA(components[0], components[1], components[2], components[3]);
79
111
  }
80
- /** Like fromHex, but can handle additional colors if an `HTMLCanvasElement` is available. */
112
+ /** Like {@link fromHex}, but can handle additional colors if an `HTMLCanvasElement` is available. */
81
113
  static fromString(text) {
82
114
  if (text.startsWith('#')) {
83
115
  return Color4.fromHex(text);
@@ -171,7 +203,7 @@ class Color4 {
171
203
  // - https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
172
204
  // - https://stackoverflow.com/a/9733420
173
205
  // Normalize the components, as per above
174
- const components = [this.r, this.g, this.b].map(component => {
206
+ const components = [this.r, this.g, this.b].map((component) => {
175
207
  if (component < 0.03928) {
176
208
  return component / 12.92;
177
209
  }
@@ -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
@@ -216,6 +206,26 @@ export declare class Mat33 {
216
206
  * $$
217
207
  */
218
208
  static translation(amount: Vec2): Mat33;
209
+ /**
210
+ * Creates a matrix for rotating `Vec2`s about `center` by some number of `radians`.
211
+ *
212
+ * For this function, {@link Vec2}s are considered to be points in 2D space.
213
+ *
214
+ * For example,
215
+ * ```ts,runnable,console
216
+ * import { Mat33, Vec2 } from '@js-draw/math';
217
+ *
218
+ * const halfCircle = Math.PI; // PI radians = 180 degrees = 1/2 circle
219
+ * const center = Vec2.of(1, 1); // The point (1,1)
220
+ * const rotationMatrix = Mat33.zRotation(halfCircle, center);
221
+ *
222
+ * console.log(
223
+ * 'Rotating (0,0) 180deg about', center, 'results in',
224
+ * // Rotates (0,0)
225
+ * rotationMatrix.transformVec2(Vec2.zero),
226
+ * );
227
+ * ```
228
+ */
219
229
  static zRotation(radians: number, center?: Point2): Mat33;
220
230
  static scaling2D(amount: number | Vec2, center?: Point2): Mat33;
221
231
  /**
package/dist/cjs/Mat33.js CHANGED
@@ -76,11 +76,7 @@ class Mat33 {
76
76
  this.c2 = c2;
77
77
  this.c3 = c3;
78
78
  this.cachedInverse = undefined;
79
- this.rows = [
80
- Vec3_1.default.of(a1, a2, a3),
81
- Vec3_1.default.of(b1, b2, b3),
82
- Vec3_1.default.of(c1, c2, c3),
83
- ];
79
+ this.rows = [Vec3_1.default.of(a1, a2, a3), Vec3_1.default.of(b1, b2, b3), Vec3_1.default.of(c1, c2, c3)];
84
80
  }
85
81
  /**
86
82
  * Creates a matrix from the given rows:
@@ -112,16 +108,8 @@ class Mat33 {
112
108
  if (this.cachedInverse !== undefined) {
113
109
  return this.cachedInverse;
114
110
  }
115
- const toIdentity = [
116
- this.rows[0],
117
- this.rows[1],
118
- this.rows[2],
119
- ];
120
- const toResult = [
121
- Vec3_1.default.unitX,
122
- Vec3_1.default.unitY,
123
- Vec3_1.default.unitZ,
124
- ];
111
+ const toIdentity = [this.rows[0], this.rows[1], this.rows[2]];
112
+ const toResult = [Vec3_1.default.unitX, Vec3_1.default.unitY, Vec3_1.default.unitZ];
125
113
  // Convert toIdentity to the identity matrix and
126
114
  // toResult to the inverse through elementary row operations
127
115
  for (let cursor = 0; cursor < 3; cursor++) {
@@ -317,11 +305,7 @@ class Mat33 {
317
305
  * ```
318
306
  */
319
307
  toArray() {
320
- return [
321
- this.a1, this.a2, this.a3,
322
- this.b1, this.b2, this.b3,
323
- this.c1, this.c2, this.c3,
324
- ];
308
+ return [this.a1, this.a2, this.a3, this.b1, this.b2, this.b3, this.c1, this.c2, this.c3];
325
309
  }
326
310
  /**
327
311
  * Returns a new `Mat33` where each entry is the output of the function
@@ -378,6 +362,26 @@ class Mat33 {
378
362
  // ...
379
363
  return new Mat33(1, 0, amount.x, 0, 1, amount.y, 0, 0, 1);
380
364
  }
365
+ /**
366
+ * Creates a matrix for rotating `Vec2`s about `center` by some number of `radians`.
367
+ *
368
+ * For this function, {@link Vec2}s are considered to be points in 2D space.
369
+ *
370
+ * For example,
371
+ * ```ts,runnable,console
372
+ * import { Mat33, Vec2 } from '@js-draw/math';
373
+ *
374
+ * const halfCircle = Math.PI; // PI radians = 180 degrees = 1/2 circle
375
+ * const center = Vec2.of(1, 1); // The point (1,1)
376
+ * const rotationMatrix = Mat33.zRotation(halfCircle, center);
377
+ *
378
+ * console.log(
379
+ * 'Rotating (0,0) 180deg about', center, 'results in',
380
+ * // Rotates (0,0)
381
+ * rotationMatrix.transformVec2(Vec2.zero),
382
+ * );
383
+ * ```
384
+ */
381
385
  static zRotation(radians, center = Vec2_1.Vec2.zero) {
382
386
  if (radians === 0) {
383
387
  return Mat33.identity;
@@ -427,7 +431,7 @@ class Mat33 {
427
431
  return Mat33.identity;
428
432
  }
429
433
  const parseArguments = (argumentString) => {
430
- const parsed = argumentString.split(/[, \t\n]+/g).map(argString => {
434
+ const parsed = argumentString.split(/[, \t\n]+/g).map((argString) => {
431
435
  // Handle trailing spaces/commands
432
436
  if (argString.trim() === '') {
433
437
  return null;
@@ -438,7 +442,7 @@ class Mat33 {
438
442
  argString = argString.substring(0, argString.length - 1);
439
443
  }
440
444
  // Remove trailing px units.
441
- argString = argString.replace(/px$/ig, '');
445
+ argString = argString.replace(/px$/gi, '');
442
446
  const numberExp = /^[-]?\d*(?:\.\d*)?(?:[eE][-+]?\d+)?$/i;
443
447
  if (!numberExp.exec(argString)) {
444
448
  throw new Error(`All arguments to transform functions must be numeric (state: ${JSON.stringify({
@@ -452,7 +456,7 @@ class Mat33 {
452
456
  }
453
457
  return argNumber;
454
458
  });
455
- return parsed.filter(n => n !== null);
459
+ return parsed.filter((n) => n !== null);
456
460
  };
457
461
  const keywordToAction = {
458
462
  matrix: (matrixData) => {
@@ -502,7 +506,7 @@ class Mat33 {
502
506
  };
503
507
  // A command (\w+)
504
508
  // followed by a set of arguments ([ \t\n0-9eE.,\-%]+)
505
- const partRegex = /\s*(\w+)\s*\(([^)]*)\)/ig;
509
+ const partRegex = /\s*(\w+)\s*\(([^)]*)\)/gi;
506
510
  let match;
507
511
  let matrix = null;
508
512
  while ((match = partRegex.exec(cssString)) !== null) {
@@ -150,7 +150,7 @@ export interface Vec3 {
150
150
  map(fn: (component: number, index: number) => number): Vec3;
151
151
  asArray(): [number, number, number];
152
152
  /**
153
- * [fuzz] The maximum difference between two components for this and [other]
153
+ * @param tolerance The maximum difference between two components for this and [other]
154
154
  * to be considered equal.
155
155
  *
156
156
  * @example
@@ -200,12 +200,16 @@ declare class Vec2Impl implements Vec3 {
200
200
  toString(): string;
201
201
  }
202
202
  /**
203
- * A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
203
+ * A `Vec2` is a {@link Vec3} optimized for working in a plane. `Vec2`s have an
204
204
  * always-zero `z` component.
205
205
  *
206
206
  * ```ts,runnable,console
207
207
  * import { Vec2 } from '@js-draw/math';
208
- * console.log(Vec2.of(1, 2));
208
+ *
209
+ * const v = Vec2.of(1, 2);
210
+ * console.log('a Vec2:', v);
211
+ * console.log('x component:', v.x);
212
+ * console.log('z component:', v.z);
209
213
  * ```
210
214
  */
211
215
  export declare namespace Vec2 {
@@ -240,6 +244,7 @@ export declare namespace Vec2 {
240
244
  /** The zero vector: A vector with x=0, y=0. */
241
245
  const zero: Vec2Impl;
242
246
  }
247
+ /** Contains static methods for constructing a {@link Vec3}. */
243
248
  export declare namespace Vec3 {
244
249
  /**
245
250
  * Construct a vector from three components.
@@ -248,11 +253,15 @@ export declare namespace Vec3 {
248
253
  * ```ts,runnable,console
249
254
  * import { Vec3 } from '@js-draw/math';
250
255
  * const v1 = Vec3.of(1, 2, 3);
256
+ * console.log(v1.plus(Vec3.of(0, 100, 0)));
251
257
  * ```
252
258
  */
253
259
  const of: (x: number, y: number, z: number) => Vec3;
260
+ /** A unit vector in the x direction (`[1, 0, 0]`). */
254
261
  const unitX: Vec2Impl;
262
+ /** A unit vector in the y direction (`[0, 1, 0]`). */
255
263
  const unitY: Vec2Impl;
264
+ /** The zero vector (`[0, 0, 0]`). */
256
265
  const zero: Vec2Impl;
257
266
  /** A vector of length 1 in the z direction. */
258
267
  const unitZ: Vec3;
package/dist/cjs/Vec3.js CHANGED
@@ -106,9 +106,9 @@ class Vec3Impl {
106
106
  return [this.x, this.y, this.z];
107
107
  }
108
108
  eq(other, fuzz = defaultEqlTolerance) {
109
- return (Math.abs(other.x - this.x) <= fuzz
110
- && Math.abs(other.y - this.y) <= fuzz
111
- && Math.abs(other.z - this.z) <= fuzz);
109
+ return (Math.abs(other.x - this.x) <= fuzz &&
110
+ Math.abs(other.y - this.y) <= fuzz &&
111
+ Math.abs(other.z - this.z) <= fuzz);
112
112
  }
113
113
  toString() {
114
114
  return `Vec(${this.x}, ${this.y}, ${this.z})`;
@@ -119,7 +119,9 @@ class Vec2Impl {
119
119
  this.x = x;
120
120
  this.y = y;
121
121
  }
122
- get z() { return 0; }
122
+ get z() {
123
+ return 0;
124
+ }
123
125
  get xy() {
124
126
  // Useful for APIs that behave differently if .z is present.
125
127
  return {
@@ -216,21 +218,25 @@ class Vec2Impl {
216
218
  return [this.x, this.y, 0];
217
219
  }
218
220
  eq(other, fuzz = defaultEqlTolerance) {
219
- return (Math.abs(other.x - this.x) <= fuzz
220
- && Math.abs(other.y - this.y) <= fuzz
221
- && Math.abs(other.z) <= fuzz);
221
+ return (Math.abs(other.x - this.x) <= fuzz &&
222
+ Math.abs(other.y - this.y) <= fuzz &&
223
+ Math.abs(other.z) <= fuzz);
222
224
  }
223
225
  toString() {
224
226
  return `Vec(${this.x}, ${this.y})`;
225
227
  }
226
228
  }
227
229
  /**
228
- * A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
230
+ * A `Vec2` is a {@link Vec3} optimized for working in a plane. `Vec2`s have an
229
231
  * always-zero `z` component.
230
232
  *
231
233
  * ```ts,runnable,console
232
234
  * import { Vec2 } from '@js-draw/math';
233
- * console.log(Vec2.of(1, 2));
235
+ *
236
+ * const v = Vec2.of(1, 2);
237
+ * console.log('a Vec2:', v);
238
+ * console.log('x component:', v.x);
239
+ * console.log('z component:', v.z);
234
240
  * ```
235
241
  */
236
242
  var Vec2;
@@ -267,6 +273,7 @@ var Vec2;
267
273
  /** The zero vector: A vector with x=0, y=0. */
268
274
  Vec2.zero = Vec2.of(0, 0);
269
275
  })(Vec2 || (exports.Vec2 = Vec2 = {}));
276
+ /** Contains static methods for constructing a {@link Vec3}. */
270
277
  var Vec3;
271
278
  (function (Vec3) {
272
279
  /**
@@ -276,6 +283,7 @@ var Vec3;
276
283
  * ```ts,runnable,console
277
284
  * import { Vec3 } from '@js-draw/math';
278
285
  * const v1 = Vec3.of(1, 2, 3);
286
+ * console.log(v1.plus(Vec3.of(0, 100, 0)));
279
287
  * ```
280
288
  */
281
289
  Vec3.of = (x, y, z) => {
@@ -286,8 +294,11 @@ var Vec3;
286
294
  return new Vec3Impl(x, y, z);
287
295
  }
288
296
  };
297
+ /** A unit vector in the x direction (`[1, 0, 0]`). */
289
298
  Vec3.unitX = Vec2.unitX;
299
+ /** A unit vector in the y direction (`[0, 1, 0]`). */
290
300
  Vec3.unitY = Vec2.unitY;
301
+ /** The zero vector (`[0, 0, 0]`). */
291
302
  Vec3.zero = Vec2.zero;
292
303
  /** A vector of length 1 in the z direction. */
293
304
  Vec3.unitZ = Vec3.of(0, 0, 1);
package/dist/cjs/lib.d.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
  *
package/dist/cjs/lib.js CHANGED
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
  /**
3
+ * This package contains general math utilities used by `js-draw`.
4
+ * These include 2D and 3D vectors, 2D paths, and 3x3 matrices.
5
+ *
3
6
  * ```ts,runnable,console
4
7
  * import { Vec2, Mat33, Rect2 } from '@js-draw/math';
5
8
  *
@@ -29,8 +29,10 @@ export declare abstract class BezierJSWrapper extends Parameterized2DShape {
29
29
  * @returns the curve evaluated at `t`.
30
30
  */
31
31
  at(t: number): Point2;
32
+ /** @returns the curve's directional derivative at `t`. */
32
33
  derivativeAt(t: number): Point2;
33
34
  secondDerivativeAt(t: number): Point2;
35
+ /** @returns the [normal vector](https://en.wikipedia.org/wiki/Normal_(geometry)) to this curve at `t`. */
34
36
  normal(t: number): Vec2;
35
37
  normalAt(t: number): Vec2;
36
38
  tangentAt(t: number): Vec2;
@@ -40,7 +40,7 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
40
40
  }
41
41
  getBezier() {
42
42
  if (!__classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f")) {
43
- __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new bezier_js_1.Bezier(this.getPoints().map(p => p.xy)), "f");
43
+ __classPrivateFieldSet(this, _BezierJSWrapper_bezierJs, new bezier_js_1.Bezier(this.getPoints().map((p) => p.xy)), "f");
44
44
  }
45
45
  return __classPrivateFieldGet(this, _BezierJSWrapper_bezierJs, "f");
46
46
  }
@@ -63,12 +63,14 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
63
63
  at(t) {
64
64
  return Vec2_1.Vec2.ofXY(this.getBezier().get(t));
65
65
  }
66
+ /** @returns the curve's directional derivative at `t`. */
66
67
  derivativeAt(t) {
67
68
  return Vec2_1.Vec2.ofXY(this.getBezier().derivative(t));
68
69
  }
69
70
  secondDerivativeAt(t) {
70
71
  return Vec2_1.Vec2.ofXY(this.getBezier().dderivative(t));
71
72
  }
73
+ /** @returns the [normal vector](https://en.wikipedia.org/wiki/Normal_(geometry)) to this curve at `t`. */
72
74
  normal(t) {
73
75
  return Vec2_1.Vec2.ofXY(this.getBezier().normal(t));
74
76
  }
@@ -94,10 +96,12 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
94
96
  const asLine = LineSegment2_1.default.ofSmallestContainingPoints(this.getPoints());
95
97
  if (asLine) {
96
98
  const intersection = asLine.intersectsLineSegment(line);
97
- return intersection.map(p => this.nearestPointTo(p).parameterValue);
99
+ return intersection.map((p) => this.nearestPointTo(p).parameterValue);
98
100
  }
99
101
  const bezier = this.getBezier();
100
- return bezier.intersects(line).map(t => {
102
+ return bezier
103
+ .intersects(line)
104
+ .map((t) => {
101
105
  // We're using the .intersects(line) function, which is documented
102
106
  // to always return numbers. However, to satisfy the type checker (and
103
107
  // possibly improperly-defined types),
@@ -106,12 +110,12 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
106
110
  }
107
111
  const point = Vec2_1.Vec2.ofXY(this.at(t));
108
112
  // Ensure that the intersection is on the line segment
109
- if (point.distanceTo(line.p1) > line.length
110
- || point.distanceTo(line.p2) > line.length) {
113
+ if (point.distanceTo(line.p1) > line.length || point.distanceTo(line.p2) > line.length) {
111
114
  return null;
112
115
  }
113
116
  return t;
114
- }).filter(entry => entry !== null);
117
+ })
118
+ .filter((entry) => entry !== null);
115
119
  }
116
120
  splitAt(t) {
117
121
  if (t <= 0 || t >= 1) {
@@ -120,8 +124,8 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
120
124
  const bezier = this.getBezier();
121
125
  const split = bezier.split(t);
122
126
  return [
123
- new BezierJSWrapperImpl(split.left.points.map(point => Vec2_1.Vec2.ofXY(point)), split.left),
124
- new BezierJSWrapperImpl(split.right.points.map(point => Vec2_1.Vec2.ofXY(point)), split.right),
127
+ new BezierJSWrapperImpl(split.left.points.map((point) => Vec2_1.Vec2.ofXY(point)), split.left),
128
+ new BezierJSWrapperImpl(split.right.points.map((point) => Vec2_1.Vec2.ofXY(point)), split.right),
125
129
  ];
126
130
  }
127
131
  nearestPointTo(point) {
@@ -165,16 +169,19 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
165
169
  const b = this.at(t);
166
170
  const bPrime = this.derivativeAt(t);
167
171
  const bPrimePrime = this.secondDerivativeAt(t);
168
- return (2 * bPrime.x * bPrime.x + 2 * b.x * bPrimePrime.x - 2 * point.x * bPrimePrime.x
169
- + 2 * bPrime.y * bPrime.y + 2 * b.y * bPrimePrime.y - 2 * point.y * bPrimePrime.y);
172
+ return (2 * bPrime.x * bPrime.x +
173
+ 2 * b.x * bPrimePrime.x -
174
+ 2 * point.x * bPrimePrime.x +
175
+ 2 * bPrime.y * bPrime.y +
176
+ 2 * b.y * bPrimePrime.y -
177
+ 2 * point.y * bPrimePrime.y);
170
178
  };
171
179
  // Because we're zeroing f'(t), we also need to be able to compute it:
172
180
  const derivativeAt = (t) => {
173
181
  // f'(t) = 2Bₓ(t)Bₓ'(t) - 2pₓBₓ'(t) + 2Bᵧ(t)Bᵧ'(t) - 2pᵧBᵧ'(t)
174
182
  const b = this.at(t);
175
183
  const bPrime = this.derivativeAt(t);
176
- return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x
177
- + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
184
+ return (2 * b.x * bPrime.x - 2 * point.x * bPrime.x + 2 * b.y * bPrime.y - 2 * point.y * bPrime.y);
178
185
  };
179
186
  const iterate = () => {
180
187
  const slope = secondDerivativeAt(t);
@@ -225,7 +232,9 @@ class BezierJSWrapper extends Parameterized2DShape_1.default {
225
232
  return result;
226
233
  }
227
234
  toString() {
228
- return `Bézier(${this.getPoints().map(point => point.toString()).join(', ')})`;
235
+ return `Bézier(${this.getPoints()
236
+ .map((point) => point.toString())
237
+ .join(', ')})`;
229
238
  }
230
239
  }
231
240
  exports.BezierJSWrapper = BezierJSWrapper;
@@ -46,7 +46,7 @@ class LineSegment2 extends Parameterized2DShape_1.default {
46
46
  static ofSmallestContainingPoints(points) {
47
47
  if (points.length <= 1)
48
48
  return null;
49
- const sorted = [...points].sort((a, b) => a.x !== b.x ? a.x - b.x : a.y - b.y);
49
+ const sorted = [...points].sort((a, b) => (a.x !== b.x ? a.x - b.x : a.y - b.y));
50
50
  const line = new LineSegment2(sorted[0], sorted[sorted.length - 1]);
51
51
  for (const point of sorted) {
52
52
  if (!line.containsPoint(point)) {
@@ -96,10 +96,7 @@ class LineSegment2 extends Parameterized2DShape_1.default {
96
96
  if (t <= 0 || t >= 1) {
97
97
  return [this];
98
98
  }
99
- return [
100
- new LineSegment2(this.point1, this.at(t)),
101
- new LineSegment2(this.at(t), this.point2),
102
- ];
99
+ return [new LineSegment2(this.point1, this.at(t)), new LineSegment2(this.at(t), this.point2)];
103
100
  }
104
101
  /**
105
102
  * Returns the intersection of this with another line segment.
@@ -149,18 +146,17 @@ class LineSegment2 extends Parameterized2DShape_1.default {
149
146
  return null;
150
147
  }
151
148
  const xIntersect = this.point1.x;
152
- const yIntersect = (this.point1.x - other.point1.x) * other.direction.y / other.direction.x + other.point1.y;
149
+ const yIntersect = ((this.point1.x - other.point1.x) * other.direction.y) / other.direction.x + other.point1.y;
153
150
  resultPoint = Vec2_1.Vec2.of(xIntersect, yIntersect);
154
151
  resultT = (yIntersect - this.point1.y) / this.direction.y;
155
152
  }
156
153
  else {
157
154
  // From above,
158
155
  // x = ((o₁ᵧ - o₂ᵧ)(d₁ₓd₂ₓ) + (d₂ᵧd₁ₓ)(o₂ₓ) - (d₁ᵧd₂ₓ)(o₁ₓ))/(d₂ᵧd₁ₓ - d₁ᵧd₂ₓ)
159
- const numerator = ((this.point1.y - other.point1.y) * this.direction.x * other.direction.x
160
- + this.direction.x * other.direction.y * other.point1.x
161
- - this.direction.y * other.direction.x * this.point1.x);
162
- const denominator = (other.direction.y * this.direction.x
163
- - this.direction.y * other.direction.x);
156
+ const numerator = (this.point1.y - other.point1.y) * this.direction.x * other.direction.x +
157
+ this.direction.x * other.direction.y * other.point1.x -
158
+ this.direction.y * other.direction.x * this.point1.x;
159
+ const denominator = other.direction.y * this.direction.x - this.direction.y * other.direction.x;
164
160
  // Avoid dividing by zero. It means there is no intersection
165
161
  if (denominator === 0) {
166
162
  return null;
@@ -176,10 +172,10 @@ class LineSegment2 extends Parameterized2DShape_1.default {
176
172
  const resultToP2 = resultPoint.distanceTo(this.point2);
177
173
  const resultToP3 = resultPoint.distanceTo(other.point1);
178
174
  const resultToP4 = resultPoint.distanceTo(other.point2);
179
- if (resultToP1 > this.length
180
- || resultToP2 > this.length
181
- || resultToP3 > other.length
182
- || resultToP4 > other.length) {
175
+ if (resultToP1 > this.length ||
176
+ resultToP2 > this.length ||
177
+ resultToP3 > other.length ||
178
+ resultToP4 > other.length) {
183
179
  return null;
184
180
  }
185
181
  return {
@@ -264,8 +260,8 @@ class LineSegment2 extends Parameterized2DShape_1.default {
264
260
  }
265
261
  const tolerance = options?.tolerance;
266
262
  const ignoreDirection = options?.ignoreDirection ?? true;
267
- return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance))
268
- || (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
263
+ return ((other.p1.eq(this.p1, tolerance) && other.p2.eq(this.p2, tolerance)) ||
264
+ (ignoreDirection && other.p1.eq(this.p2, tolerance) && other.p2.eq(this.p1, tolerance)));
269
265
  }
270
266
  }
271
267
  exports.LineSegment2 = LineSegment2;
@@ -13,7 +13,7 @@ const Abstract2DShape_1 = __importDefault(require("./Abstract2DShape"));
13
13
  */
14
14
  class Parameterized2DShape extends Abstract2DShape_1.default {
15
15
  intersectsLineSegment(line) {
16
- return this.argIntersectsLineSegment(line).map(t => this.at(t));
16
+ return this.argIntersectsLineSegment(line).map((t) => this.at(t));
17
17
  }
18
18
  }
19
19
  exports.Parameterized2DShape = Parameterized2DShape;
@@ -3,6 +3,7 @@ import Mat33 from '../Mat33';
3
3
  import Rect2 from './Rect2';
4
4
  import { Point2 } from '../Vec2';
5
5
  import Parameterized2DShape from './Parameterized2DShape';
6
+ /** Identifiers for different path commands. These commands can make up a {@link Path}. */
6
7
  export declare enum PathCommandType {
7
8
  LineTo = 0,
8
9
  MoveTo = 1,