@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.
- package/build-config.json +1 -1
- package/dist/cjs/Color4.d.ts +24 -1
- package/dist/cjs/Color4.js +35 -3
- package/dist/cjs/Mat33.d.ts +21 -11
- package/dist/cjs/Mat33.js +28 -24
- package/dist/cjs/Vec3.d.ts +12 -3
- package/dist/cjs/Vec3.js +20 -9
- package/dist/cjs/lib.d.ts +3 -0
- package/dist/cjs/lib.js +3 -0
- package/dist/cjs/shapes/BezierJSWrapper.d.ts +2 -0
- package/dist/cjs/shapes/BezierJSWrapper.js +22 -13
- package/dist/cjs/shapes/LineSegment2.js +13 -17
- package/dist/cjs/shapes/Parameterized2DShape.js +1 -1
- package/dist/cjs/shapes/Path.d.ts +1 -0
- package/dist/cjs/shapes/Path.js +50 -47
- package/dist/cjs/shapes/QuadraticBezier.d.ts +19 -2
- package/dist/cjs/shapes/QuadraticBezier.js +26 -3
- package/dist/cjs/shapes/Rect2.d.ts +13 -0
- package/dist/cjs/shapes/Rect2.js +35 -16
- package/dist/cjs/shapes/Triangle.js +4 -5
- package/dist/cjs/utils/convexHull2Of.js +3 -3
- package/dist/mjs/Color4.d.ts +24 -1
- package/dist/mjs/Color4.mjs +35 -3
- package/dist/mjs/Mat33.d.ts +21 -11
- package/dist/mjs/Mat33.mjs +28 -24
- package/dist/mjs/Vec3.d.ts +12 -3
- package/dist/mjs/Vec3.mjs +20 -9
- package/dist/mjs/lib.d.ts +3 -0
- package/dist/mjs/lib.mjs +3 -0
- package/dist/mjs/shapes/BezierJSWrapper.d.ts +2 -0
- package/dist/mjs/shapes/BezierJSWrapper.mjs +22 -13
- package/dist/mjs/shapes/LineSegment2.mjs +13 -17
- package/dist/mjs/shapes/Parameterized2DShape.mjs +1 -1
- package/dist/mjs/shapes/Path.d.ts +1 -0
- package/dist/mjs/shapes/Path.mjs +50 -47
- package/dist/mjs/shapes/QuadraticBezier.d.ts +19 -2
- package/dist/mjs/shapes/QuadraticBezier.mjs +26 -3
- package/dist/mjs/shapes/Rect2.d.ts +13 -0
- package/dist/mjs/shapes/Rect2.mjs +35 -16
- package/dist/mjs/shapes/Triangle.mjs +4 -5
- package/dist/mjs/utils/convexHull2Of.mjs +3 -3
- package/dist-test/test_imports/test-require.cjs +1 -1
- package/package.json +3 -3
- package/src/Color4.test.ts +21 -21
- package/src/Color4.ts +61 -18
- package/src/Mat33.fromCSSMatrix.test.ts +32 -46
- package/src/Mat33.test.ts +64 -102
- package/src/Mat33.ts +81 -104
- package/src/Vec2.test.ts +3 -3
- package/src/Vec3.test.ts +2 -3
- package/src/Vec3.ts +46 -61
- package/src/lib.ts +3 -2
- package/src/polynomial/solveQuadratic.test.ts +39 -13
- package/src/polynomial/solveQuadratic.ts +5 -6
- package/src/rounding/cleanUpNumber.test.ts +1 -1
- package/src/rounding/constants.ts +1 -3
- package/src/rounding/getLenAfterDecimal.ts +1 -2
- package/src/rounding/lib.ts +1 -2
- package/src/rounding/toRoundedString.test.ts +1 -1
- package/src/rounding/toStringOfSamePrecision.test.ts +1 -2
- package/src/rounding/toStringOfSamePrecision.ts +1 -1
- package/src/shapes/BezierJSWrapper.ts +56 -37
- package/src/shapes/CubicBezier.ts +3 -3
- package/src/shapes/LineSegment2.test.ts +24 -17
- package/src/shapes/LineSegment2.ts +26 -29
- package/src/shapes/Parameterized2DShape.ts +5 -4
- package/src/shapes/Path.fromString.test.ts +5 -5
- package/src/shapes/Path.test.ts +122 -120
- package/src/shapes/Path.toString.test.ts +7 -7
- package/src/shapes/Path.ts +379 -352
- package/src/shapes/PointShape2D.ts +3 -3
- package/src/shapes/QuadraticBezier.test.ts +27 -21
- package/src/shapes/QuadraticBezier.ts +26 -11
- package/src/shapes/Rect2.test.ts +44 -75
- package/src/shapes/Rect2.ts +47 -35
- package/src/shapes/Triangle.test.ts +31 -29
- package/src/shapes/Triangle.ts +17 -18
- package/src/utils/convexHull2Of.test.ts +54 -15
- package/src/utils/convexHull2Of.ts +9 -7
- package/tsconfig.json +1 -3
- 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
|
-
|
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,
|
223
|
-
this.
|
224
|
-
this.
|
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),
|
260
|
-
at(
|
261
|
-
at(
|
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 = [
|
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]),
|
419
|
-
mapping(this.
|
420
|
-
mapping(this.
|
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$/
|
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
|
-
|
560
|
-
|
561
|
-
|
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(
|
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*\(([^)]*)\)/
|
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(
|
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
|
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
|
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
|
-
*
|
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,
|
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(): [
|
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
|
-
|
342
|
-
|
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() {
|
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,
|
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(): [
|
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
|
-
|
498
|
-
|
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
|
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
|
-
*
|
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
|
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`.
|