@js-draw/math 1.18.0 → 1.21.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.
package/src/Vec3.ts CHANGED
@@ -19,49 +19,25 @@
19
19
  * console.log('As an array:', Vec3.unitZ.asArray());
20
20
  * ```
21
21
  */
22
- export class Vec3 {
23
- private constructor(
24
- public readonly x: number,
25
- public readonly y: number,
26
- public readonly z: number
27
- ) {
28
- }
29
-
30
- /** Returns the x, y components of this. */
31
- public get xy(): { x: number; y: number } {
32
- // Useful for APIs that behave differently if .z is present.
33
- return {
34
- x: this.x,
35
- y: this.y,
36
- };
37
- }
22
+ export interface Vec3 {
23
+ readonly x: number;
24
+ readonly y: number;
25
+ readonly z: number;
38
26
 
39
- /** Construct a vector from three components. */
40
- public static of(x: number, y: number, z: number): Vec3 {
41
- return new Vec3(x, y, z);
42
- }
43
-
44
- /** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
45
- public at(idx: number): number {
46
- if (idx === 0) return this.x;
47
- if (idx === 1) return this.y;
48
- if (idx === 2) return this.z;
49
-
50
- throw new Error(`${idx} out of bounds!`);
51
- }
52
-
53
- /** Alias for this.magnitude. */
54
- public length(): number {
55
- return this.magnitude();
56
- }
27
+ /**
28
+ * Returns the x, y components of this.
29
+ * May be implemented as a getter method.
30
+ */
31
+ readonly xy: { x: number, y: number };
57
32
 
58
- public magnitude(): number {
59
- return Math.sqrt(this.dot(this));
60
- }
33
+ /** Returns the vector's `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) 2`. */
34
+ at(i: number): number;
61
35
 
62
- public magnitudeSquared(): number {
63
- return this.dot(this);
64
- }
36
+ /** Alias for `.magnitude`. */
37
+ length(): number;
38
+ /** Returns the length of this vector in ℝ^3. */
39
+ magnitude(): number;
40
+ magnitudeSquared(): number;
65
41
 
66
42
  /**
67
43
  * Interpreting this vector as a point in ℝ^3, computes the square distance
@@ -69,12 +45,7 @@ export class Vec3 {
69
45
  *
70
46
  * Equivalent to `.minus(p).magnitudeSquared()`.
71
47
  */
72
- public squareDistanceTo(p: Vec3) {
73
- const dx = this.x - p.x;
74
- const dy = this.y - p.y;
75
- const dz = this.z - p.z;
76
- return dx * dx + dy * dy + dz * dz;
77
- }
48
+ squareDistanceTo(other: Vec3): number;
78
49
 
79
50
  /**
80
51
  * Interpreting this vector as a point in ℝ³, returns the distance to the point
@@ -82,9 +53,7 @@ export class Vec3 {
82
53
  *
83
54
  * Equivalent to `.minus(p).magnitude()`.
84
55
  */
85
- public distanceTo(p: Vec3) {
86
- return Math.sqrt(this.squareDistanceTo(p));
87
- }
56
+ distanceTo(p: Vec3): number;
88
57
 
89
58
  /**
90
59
  * Returns the entry of this with the greatest magnitude.
@@ -98,9 +67,7 @@ export class Vec3 {
98
67
  * console.log(Vec3.of(-1, -10, 8).maximumEntryMagnitude()); // -> 10
99
68
  * ```
100
69
  */
101
- public maximumEntryMagnitude(): number {
102
- return Math.max(Math.abs(this.x), Math.max(Math.abs(this.y), Math.abs(this.z)));
103
- }
70
+ maximumEntryMagnitude(): number;
104
71
 
105
72
  /**
106
73
  * Return this' angle in the XY plane (treats this as a Vec2).
@@ -117,23 +84,175 @@ export class Vec3 {
117
84
  * console.log(Vec2.of(-1, 0).angle()); // atan2(0, -1)
118
85
  * ```
119
86
  */
120
- public angle(): number {
121
- return Math.atan2(this.y, this.x);
122
- }
87
+ angle(): number;
123
88
 
124
89
  /**
125
90
  * Returns a unit vector in the same direction as this.
126
91
  *
127
92
  * If `this` has zero length, the resultant vector has `NaN` components.
128
93
  */
94
+ normalized(): Vec3;
95
+
96
+ /**
97
+ * Like {@link normalized}, except returns zero if this has zero magnitude.
98
+ */
99
+ normalizedOrZero(): Vec3;
100
+
101
+ /** @returns A copy of `this` multiplied by a scalar. */
102
+ times(c: number): Vec3;
103
+
104
+ /** Performs vector addition. */
105
+ plus(v: Vec3): Vec3;
106
+ minus(v: Vec3): Vec3;
107
+
108
+ /**
109
+ * Computes the scalar product between this and `v`.
110
+ *
111
+ * In particular, `a.dot(b)` is equivalent to `a.x * b.x + a.y * b.y + a.z * b.z`.
112
+ */
113
+ dot(v: Vec3): number;
114
+
115
+ /** Computes the cross product between this and `v` */
116
+ cross(v: Vec3): Vec3;
117
+
118
+ /**
119
+ * If `other` is a `Vec3`, multiplies `this` component-wise by `other`. Otherwise,
120
+ * if `other is a `number`, returns the result of scalar multiplication.
121
+ *
122
+ * @example
123
+ * ```
124
+ * Vec3.of(1, 2, 3).scale(Vec3.of(2, 4, 6)); // → Vec3(2, 8, 18)
125
+ * ```
126
+ */
127
+ scale(other: Vec3|number): Vec3;
128
+
129
+ /**
130
+ * Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
131
+ * 90 degrees counter-clockwise.
132
+ */
133
+ orthog(): Vec3;
134
+
135
+ /** Returns this plus a vector of length `distance` in `direction`. */
136
+ extend(distance: number, direction: Vec3): Vec3;
137
+
138
+ /** Returns a vector `fractionTo` of the way to target from this. */
139
+ lerp(target: Vec3, fractionTo: number): Vec3;
140
+
141
+ /**
142
+ * `zip` Maps a component of this and a corresponding component of
143
+ * `other` to a component of the output vector.
144
+ *
145
+ * @example
146
+ * ```
147
+ * const a = Vec3.of(1, 2, 3);
148
+ * const b = Vec3.of(0.5, 2.1, 2.9);
149
+ *
150
+ * const zipped = a.zip(b, (aComponent, bComponent) => {
151
+ * return Math.min(aComponent, bComponent);
152
+ * });
153
+ *
154
+ * console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
155
+ * ```
156
+ */
157
+ zip(
158
+ other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
159
+ ): Vec3;
160
+
161
+ /**
162
+ * Returns a vector with each component acted on by `fn`.
163
+ *
164
+ * @example
165
+ * ```ts,runnable,console
166
+ * import { Vec3 } from '@js-draw/math';
167
+ * console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
168
+ * ```
169
+ */
170
+ map(fn: (component: number, index: number)=> number): Vec3;
171
+
172
+ asArray(): [ number, number, number ];
173
+
174
+
175
+ /**
176
+ * [fuzz] The maximum difference between two components for this and [other]
177
+ * to be considered equal.
178
+ *
179
+ * @example
180
+ * ```
181
+ * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 100); // → true
182
+ * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 0.1); // → false
183
+ * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3); // → true
184
+ * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3.01); // → true
185
+ * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
186
+ * ```
187
+ */
188
+ eq(other: Vec3, tolerance?: number): boolean;
189
+
190
+ toString(): string;
191
+ }
192
+
193
+ const defaultEqlTolerance = 1e-10;
194
+
195
+ class Vec3Impl implements Vec3 {
196
+ public constructor(
197
+ public readonly x: number,
198
+ public readonly y: number,
199
+ public readonly z: number
200
+ ) {
201
+ }
202
+
203
+ public get xy(): { x: number; y: number } {
204
+ // Useful for APIs that behave differently if .z is present.
205
+ return {
206
+ x: this.x,
207
+ y: this.y,
208
+ };
209
+ }
210
+
211
+ /** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
212
+ public at(idx: number): number {
213
+ if (idx === 0) return this.x;
214
+ if (idx === 1) return this.y;
215
+ if (idx === 2) return this.z;
216
+
217
+ throw new Error(`${idx} out of bounds!`);
218
+ }
219
+
220
+ public length(): number {
221
+ return this.magnitude();
222
+ }
223
+
224
+ public magnitude(): number {
225
+ return Math.sqrt(this.magnitudeSquared());
226
+ }
227
+
228
+ public magnitudeSquared(): number {
229
+ return this.x * this.x + this.y * this.y + this.z * this.z;
230
+ }
231
+
232
+ public squareDistanceTo(p: Vec3) {
233
+ const dx = this.x - p.x;
234
+ const dy = this.y - p.y;
235
+ const dz = this.z - p.z;
236
+ return dx * dx + dy * dy + dz * dz;
237
+ }
238
+
239
+ public distanceTo(p: Vec3) {
240
+ return Math.sqrt(this.squareDistanceTo(p));
241
+ }
242
+
243
+ public maximumEntryMagnitude(): number {
244
+ return Math.max(Math.abs(this.x), Math.max(Math.abs(this.y), Math.abs(this.z)));
245
+ }
246
+
247
+ public angle(): number {
248
+ return Math.atan2(this.y, this.x);
249
+ }
250
+
129
251
  public normalized(): Vec3 {
130
252
  const norm = this.magnitude();
131
253
  return Vec3.of(this.x / norm, this.y / norm, this.z / norm);
132
254
  }
133
255
 
134
- /**
135
- * Like {@link normalized}, except returns zero if this has zero magnitude.
136
- */
137
256
  public normalizedOrZero(): Vec3 {
138
257
  if (this.eq(Vec3.zero)) {
139
258
  return Vec3.zero;
@@ -142,7 +261,6 @@ export class Vec3 {
142
261
  return this.normalized();
143
262
  }
144
263
 
145
- /** @returns A copy of `this` multiplied by a scalar. */
146
264
  public times(c: number): Vec3 {
147
265
  return Vec3.of(this.x * c, this.y * c, this.z * c);
148
266
  }
@@ -166,19 +284,10 @@ export class Vec3 {
166
284
  return Vec3.of(
167
285
  this.y * other.z - other.y * this.z,
168
286
  other.x * this.z - this.x * other.z,
169
- this.x * other.y - other.x * this.y
287
+ this.x * other.y - other.x * this.y,
170
288
  );
171
289
  }
172
290
 
173
- /**
174
- * If `other` is a `Vec3`, multiplies `this` component-wise by `other`. Otherwise,
175
- * if `other is a `number`, returns the result of scalar multiplication.
176
- *
177
- * @example
178
- * ```
179
- * Vec3.of(1, 2, 3).scale(Vec3.of(2, 4, 6)); // → Vec3(2, 8, 18)
180
- * ```
181
- */
182
291
  public scale(other: Vec3|number): Vec3 {
183
292
  if (typeof other === 'number') {
184
293
  return this.times(other);
@@ -191,10 +300,6 @@ export class Vec3 {
191
300
  );
192
301
  }
193
302
 
194
- /**
195
- * Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
196
- * 90 degrees counter-clockwise.
197
- */
198
303
  public orthog(): Vec3 {
199
304
  // If parallel to the z-axis
200
305
  if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
@@ -204,32 +309,14 @@ export class Vec3 {
204
309
  return this.cross(Vec3.unitZ.times(-1)).normalized();
205
310
  }
206
311
 
207
- /** Returns this plus a vector of length `distance` in `direction`. */
208
312
  public extend(distance: number, direction: Vec3): Vec3 {
209
313
  return this.plus(direction.normalized().times(distance));
210
314
  }
211
315
 
212
- /** Returns a vector `fractionTo` of the way to target from this. */
213
316
  public lerp(target: Vec3, fractionTo: number): Vec3 {
214
317
  return this.times(1 - fractionTo).plus(target.times(fractionTo));
215
318
  }
216
319
 
217
- /**
218
- * `zip` Maps a component of this and a corresponding component of
219
- * `other` to a component of the output vector.
220
- *
221
- * @example
222
- * ```
223
- * const a = Vec3.of(1, 2, 3);
224
- * const b = Vec3.of(0.5, 2.1, 2.9);
225
- *
226
- * const zipped = a.zip(b, (aComponent, bComponent) => {
227
- * return Math.min(aComponent, bComponent);
228
- * });
229
- *
230
- * console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
231
- * ```
232
- */
233
320
  public zip(
234
321
  other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
235
322
  ): Vec3 {
@@ -240,39 +327,15 @@ export class Vec3 {
240
327
  );
241
328
  }
242
329
 
243
- /**
244
- * Returns a vector with each component acted on by `fn`.
245
- *
246
- * @example
247
- * ```ts,runnable,console
248
- * import { Vec3 } from '@js-draw/math';
249
- * console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
250
- * ```
251
- */
252
330
  public map(fn: (component: number, index: number)=> number): Vec3 {
253
- return Vec3.of(
254
- fn(this.x, 0), fn(this.y, 1), fn(this.z, 2)
255
- );
331
+ return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(this.z, 2));
256
332
  }
257
333
 
258
334
  public asArray(): [ number, number, number ] {
259
335
  return [this.x, this.y, this.z];
260
336
  }
261
337
 
262
- /**
263
- * [fuzz] The maximum difference between two components for this and [other]
264
- * to be considered equal.
265
- *
266
- * @example
267
- * ```
268
- * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 100); // → true
269
- * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 0.1); // → false
270
- * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3); // → true
271
- * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3.01); // → true
272
- * Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
273
- * ```
274
- */
275
- public eq(other: Vec3, fuzz: number = 1e-10): boolean {
338
+ public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
276
339
  return (
277
340
  Math.abs(other.x - this.x) <= fuzz
278
341
  && Math.abs(other.y - this.y) <= fuzz
@@ -283,11 +346,235 @@ export class Vec3 {
283
346
  public toString(): string {
284
347
  return `Vec(${this.x}, ${this.y}, ${this.z})`;
285
348
  }
349
+ }
350
+
351
+ class Vec2Impl implements Vec3 {
352
+ public constructor(
353
+ public readonly x: number,
354
+ public readonly y: number,
355
+ ) {
356
+ }
357
+
358
+ public get z() { return 0; }
359
+
360
+ public get xy(): { x: number; y: number } {
361
+ // Useful for APIs that behave differently if .z is present.
362
+ return {
363
+ x: this.x,
364
+ y: this.y,
365
+ };
366
+ }
367
+
368
+ public at(idx: number): number {
369
+ if (idx === 0) return this.x;
370
+ if (idx === 1) return this.y;
371
+ if (idx === 2) return 0;
372
+
373
+ throw new Error(`${idx} out of bounds!`);
374
+ }
375
+
376
+ public length(): number {
377
+ return this.magnitude();
378
+ }
379
+
380
+ public magnitude(): number {
381
+ return Math.sqrt(this.x * this.x + this.y * this.y);
382
+ }
383
+
384
+ public magnitudeSquared(): number {
385
+ return this.x * this.x + this.y * this.y;
386
+ }
387
+
388
+ public squareDistanceTo(p: Vec3) {
389
+ const dx = this.x - p.x;
390
+ const dy = this.y - p.y;
391
+ return dx * dx + dy * dy + p.z * p.z;
392
+ }
286
393
 
394
+ public distanceTo(p: Vec3) {
395
+ return Math.sqrt(this.squareDistanceTo(p));
396
+ }
397
+
398
+ public maximumEntryMagnitude(): number {
399
+ return Math.max(Math.abs(this.x), Math.abs(this.y));
400
+ }
401
+
402
+ public angle(): number {
403
+ return Math.atan2(this.y, this.x);
404
+ }
405
+
406
+ public normalized(): Vec3 {
407
+ const norm = this.magnitude();
408
+ return Vec2.of(this.x / norm, this.y / norm);
409
+ }
410
+
411
+ public normalizedOrZero(): Vec3 {
412
+ if (this.eq(Vec3.zero)) {
413
+ return Vec3.zero;
414
+ }
415
+
416
+ return this.normalized();
417
+ }
418
+
419
+ public times(c: number): Vec3 {
420
+ return Vec2.of(this.x * c, this.y * c);
421
+ }
422
+
423
+ public plus(v: Vec3): Vec3 {
424
+ return Vec3.of(this.x + v.x, this.y + v.y, v.z);
425
+ }
426
+
427
+ public minus(v: Vec3): Vec3 {
428
+ return Vec3.of(this.x - v.x, this.y - v.y, -v.z);
429
+ }
287
430
 
288
- public static unitX = Vec3.of(1, 0, 0);
289
- public static unitY = Vec3.of(0, 1, 0);
290
- public static unitZ = Vec3.of(0, 0, 1);
291
- public static zero = Vec3.of(0, 0, 0);
431
+ public dot(other: Vec3): number {
432
+ return this.x * other.x + this.y * other.y;
433
+ }
434
+
435
+ public cross(other: Vec3): Vec3 {
436
+ // | i j k |
437
+ // | x1 y1 z1| = (i)(y1z2 - y2z1) - (j)(x1z2 - x2z1) + (k)(x1y2 - x2y1)
438
+ // | 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
+ );
444
+ }
445
+
446
+ public scale(other: Vec3|number): Vec3 {
447
+ if (typeof other === 'number') {
448
+ return this.times(other);
449
+ }
450
+
451
+ return Vec2.of(
452
+ this.x * other.x,
453
+ this.y * other.y,
454
+ );
455
+ }
456
+
457
+ public orthog(): Vec3 {
458
+ // If parallel to the z-axis
459
+ if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
460
+ return this.dot(Vec3.unitX) === 0 ? Vec3.unitX : this.cross(Vec3.unitX).normalized();
461
+ }
462
+
463
+ return this.cross(Vec3.unitZ.times(-1)).normalized();
464
+ }
465
+
466
+ public extend(distance: number, direction: Vec3): Vec3 {
467
+ return this.plus(direction.normalized().times(distance));
468
+ }
469
+
470
+ public lerp(target: Vec3, fractionTo: number): Vec3 {
471
+ return this.times(1 - fractionTo).plus(target.times(fractionTo));
472
+ }
473
+
474
+ public zip(
475
+ other: Vec3, zip: (componentInThis: number, componentInOther: number)=> number
476
+ ): Vec3 {
477
+ return Vec3.of(
478
+ zip(other.x, this.x),
479
+ zip(other.y, this.y),
480
+ zip(other.z, 0),
481
+ );
482
+ }
483
+
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
+ );
488
+ }
489
+
490
+ public asArray(): [ number, number, number ] {
491
+ return [this.x, this.y, 0];
492
+ }
493
+
494
+ public eq(other: Vec3, fuzz: number = defaultEqlTolerance): boolean {
495
+ return (
496
+ Math.abs(other.x - this.x) <= fuzz
497
+ && Math.abs(other.y - this.y) <= fuzz
498
+ && Math.abs(other.z) <= fuzz
499
+ );
500
+ }
501
+
502
+ public toString(): string {
503
+ return `Vec(${this.x}, ${this.y})`;
504
+ }
505
+ }
506
+
507
+ /**
508
+ * A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
509
+ * always-zero `z` component.
510
+ *
511
+ * ```ts,runnable,console
512
+ * import { Vec2 } from '@js-draw/math';
513
+ * console.log(Vec2.of(1, 2));
514
+ * ```
515
+ */
516
+ export namespace Vec2 {
517
+ /**
518
+ * Creates a `Vec2` from an x and y coordinate.
519
+ *
520
+ * @example
521
+ * ```ts,runnable,console
522
+ * import { Vec2 } from '@js-draw/math';
523
+ * const v = Vec2.of(3, 4); // x=3, y=4.
524
+ * ```
525
+ */
526
+ export const of = (x: number, y: number) => {
527
+ return new Vec2Impl(x, y);
528
+ };
529
+
530
+ /**
531
+ * Creates a `Vec2` from an object containing `x` and `y` coordinates.
532
+ *
533
+ * @example
534
+ * ```ts,runnable,console
535
+ * import { Vec2 } from '@js-draw/math';
536
+ * const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
537
+ * const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
538
+ * ```
539
+ */
540
+ export const ofXY = ({x, y}: {x: number, y: number}) => {
541
+ return Vec2.of(x, y);
542
+ };
543
+
544
+ /** A vector of length 1 in the X direction (→). */
545
+ export const unitX = Vec2.of(1, 0);
546
+
547
+ /** A vector of length 1 in the Y direction (↑). */
548
+ export const unitY = Vec2.of(0, 1);
549
+
550
+ /** The zero vector: A vector with x=0, y=0. */
551
+ export const zero = Vec2.of(0, 0);
292
552
  }
553
+
554
+ export namespace Vec3 {
555
+ /**
556
+ * Construct a vector from three components.
557
+ *
558
+ * @example
559
+ * ```ts,runnable,console
560
+ * import { Vec3 } from '@js-draw/math';
561
+ * const v1 = Vec3.of(1, 2, 3);
562
+ * ```
563
+ */
564
+ export const of = (x: number, y: number, z: number): Vec3 => {
565
+ if (z === 0) {
566
+ return Vec2.of(x, y);
567
+ } else {
568
+ return new Vec3Impl(x, y, z);
569
+ }
570
+ };
571
+
572
+ export const unitX = Vec2.unitX;
573
+ export const unitY = Vec2.unitY;
574
+ export const zero = Vec2.zero;
575
+
576
+ /** A vector of length 1 in the z direction. */
577
+ export const unitZ = Vec3.of(0, 0, 1);
578
+ }
579
+
293
580
  export default Vec3;
@@ -118,7 +118,7 @@ export abstract class BezierJSWrapper extends Parameterized2DShape {
118
118
  }
119
119
 
120
120
  return t;
121
- }).filter(entry => entry !== null) as number[];
121
+ }).filter(entry => entry !== null);
122
122
  }
123
123
 
124
124
  public override splitAt(t: number): [BezierJSWrapper] | [BezierJSWrapper, BezierJSWrapper] {
@@ -9,7 +9,18 @@ interface IntersectionResult {
9
9
  t: number;
10
10
  }
11
11
 
12
- /** Represents a line segment. A `LineSegment2` is immutable. */
12
+ /**
13
+ * Represents a line segment. A `LineSegment2` is immutable.
14
+ *
15
+ * @example
16
+ * ```ts,runnable,console
17
+ * import {LineSegment2, Vec2} from '@js-draw/math';
18
+ * const l = new LineSegment2(Vec2.of(1, 1), Vec2.of(2, 2));
19
+ * console.log('length: ', l.length);
20
+ * console.log('direction: ', l.direction);
21
+ * console.log('bounding box: ', l.bbox);
22
+ * ```
23
+ */
13
24
  export class LineSegment2 extends Parameterized2DShape {
14
25
  // invariant: ||direction|| = 1
15
26
 
@@ -51,7 +62,7 @@ export class LineSegment2 extends Parameterized2DShape {
51
62
  * if no such line segment exists.
52
63
  *
53
64
  * @example
54
- * ```ts,runnable
65
+ * ```ts,runnable,console
55
66
  * import {LineSegment2, Vec2} from '@js-draw/math';
56
67
  * console.log(LineSegment2.ofSmallestContainingPoints([Vec2.of(1, 0), Vec2.of(0, 1)]));
57
68
  * ```
@@ -298,9 +298,9 @@ export class Rect2 extends Abstract2DShape {
298
298
  return Rect2.bboxOf(this.corners.map(corner => affineTransform.transformVec2(corner)));
299
299
  }
300
300
 
301
- /** @return true iff this is equal to [other] ± fuzz */
302
- public eq(other: Rect2, fuzz: number = 0): boolean {
303
- return this.topLeft.eq(other.topLeft, fuzz) && this.size.eq(other.size, fuzz);
301
+ /** @return true iff this is equal to `other ± tolerance` */
302
+ public eq(other: Rect2, tolerance: number = 0): boolean {
303
+ return this.topLeft.eq(other.topLeft, tolerance) && this.size.eq(other.size, tolerance);
304
304
  }
305
305
 
306
306
  public override toString(): string {
@@ -1,13 +0,0 @@
1
- {
2
- "name": "js-draw-math-test-imports",
3
- "version": "0.0.1",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "js-draw-math-test-imports",
9
- "version": "0.0.1",
10
- "license": "MIT"
11
- }
12
- }
13
- }