@js-draw/math 1.18.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Vec2.d.ts +3 -40
- package/dist/cjs/Vec2.js +8 -46
- package/dist/cjs/Vec3.d.ts +112 -16
- package/dist/cjs/Vec3.js +184 -136
- package/dist/cjs/shapes/PointShape2D.d.ts +33 -1
- package/dist/cjs/shapes/Rect2.d.ts +35 -3
- package/dist/cjs/shapes/Rect2.js +3 -3
- package/dist/mjs/Vec2.d.ts +3 -40
- package/dist/mjs/Vec2.mjs +6 -42
- package/dist/mjs/Vec3.d.ts +112 -16
- package/dist/mjs/Vec3.mjs +183 -134
- package/dist/mjs/shapes/PointShape2D.d.ts +33 -1
- package/dist/mjs/shapes/Rect2.d.ts +35 -3
- package/dist/mjs/shapes/Rect2.mjs +3 -3
- package/package.json +3 -3
- package/src/Vec2.test.ts +5 -3
- package/src/Vec2.ts +7 -47
- package/src/Vec3.ts +408 -121
- package/src/shapes/Rect2.ts +3 -3
package/dist/cjs/Vec2.d.ts
CHANGED
@@ -1,42 +1,5 @@
|
|
1
|
-
import Vec3 from './Vec3';
|
2
|
-
/**
|
3
|
-
* Utility functions that facilitate treating `Vec3`s as 2D vectors.
|
4
|
-
*
|
5
|
-
* @example
|
6
|
-
* ```ts,runnable,console
|
7
|
-
* import { Vec2 } from '@js-draw/math';
|
8
|
-
* console.log(Vec2.of(1, 2));
|
9
|
-
* ```
|
10
|
-
*/
|
11
|
-
export declare namespace Vec2 {
|
12
|
-
/**
|
13
|
-
* Creates a `Vec2` from an x and y coordinate.
|
14
|
-
*
|
15
|
-
* For example,
|
16
|
-
* ```ts
|
17
|
-
* const v = Vec2.of(3, 4); // x=3, y=4.
|
18
|
-
* ```
|
19
|
-
*/
|
20
|
-
const of: (x: number, y: number) => Vec2;
|
21
|
-
/**
|
22
|
-
* Creates a `Vec2` from an object containing x and y coordinates.
|
23
|
-
*
|
24
|
-
* For example,
|
25
|
-
* ```ts
|
26
|
-
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
|
27
|
-
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
|
28
|
-
* ```
|
29
|
-
*/
|
30
|
-
const ofXY: ({ x, y }: {
|
31
|
-
x: number;
|
32
|
-
y: number;
|
33
|
-
}) => Vec2;
|
34
|
-
/** A vector of length 1 in the X direction (→). */
|
35
|
-
const unitX: Vec3;
|
36
|
-
/** A vector of length 1 in the Y direction (↑). */
|
37
|
-
const unitY: Vec3;
|
38
|
-
/** The zero vector: A vector with x=0, y=0. */
|
39
|
-
const zero: Vec3;
|
40
|
-
}
|
1
|
+
import { Vec3, Vec2 } from './Vec3';
|
41
2
|
export type Point2 = Vec3;
|
42
3
|
export type Vec2 = Vec3;
|
4
|
+
export { Vec3, Vec2 };
|
5
|
+
export default Vec2;
|
package/dist/cjs/Vec2.js
CHANGED
@@ -1,48 +1,10 @@
|
|
1
1
|
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.Vec2 = void 0;
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
* console.log(Vec2.of(1, 2));
|
15
|
-
* ```
|
16
|
-
*/
|
17
|
-
var Vec2;
|
18
|
-
(function (Vec2) {
|
19
|
-
/**
|
20
|
-
* Creates a `Vec2` from an x and y coordinate.
|
21
|
-
*
|
22
|
-
* For example,
|
23
|
-
* ```ts
|
24
|
-
* const v = Vec2.of(3, 4); // x=3, y=4.
|
25
|
-
* ```
|
26
|
-
*/
|
27
|
-
Vec2.of = (x, y) => {
|
28
|
-
return Vec3_1.default.of(x, y, 0);
|
29
|
-
};
|
30
|
-
/**
|
31
|
-
* Creates a `Vec2` from an object containing x and y coordinates.
|
32
|
-
*
|
33
|
-
* For example,
|
34
|
-
* ```ts
|
35
|
-
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
|
36
|
-
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
|
37
|
-
* ```
|
38
|
-
*/
|
39
|
-
Vec2.ofXY = ({ x, y }) => {
|
40
|
-
return Vec3_1.default.of(x, y, 0);
|
41
|
-
};
|
42
|
-
/** A vector of length 1 in the X direction (→). */
|
43
|
-
Vec2.unitX = Vec2.of(1, 0);
|
44
|
-
/** A vector of length 1 in the Y direction (↑). */
|
45
|
-
Vec2.unitY = Vec2.of(0, 1);
|
46
|
-
/** The zero vector: A vector with x=0, y=0. */
|
47
|
-
Vec2.zero = Vec2.of(0, 0);
|
48
|
-
})(Vec2 || (exports.Vec2 = Vec2 = {}));
|
3
|
+
exports.Vec2 = exports.Vec3 = void 0;
|
4
|
+
// Internally, we define Vec2 as a namespace within Vec3 --
|
5
|
+
// this allows referencing Vec2s from Vec3 constructors without
|
6
|
+
// cyclic references.
|
7
|
+
const Vec3_1 = require("./Vec3");
|
8
|
+
Object.defineProperty(exports, "Vec3", { enumerable: true, get: function () { return Vec3_1.Vec3; } });
|
9
|
+
Object.defineProperty(exports, "Vec2", { enumerable: true, get: function () { return Vec3_1.Vec2; } });
|
10
|
+
exports.default = Vec3_1.Vec2;
|
package/dist/cjs/Vec3.d.ts
CHANGED
@@ -17,22 +17,23 @@
|
|
17
17
|
* console.log('As an array:', Vec3.unitZ.asArray());
|
18
18
|
* ```
|
19
19
|
*/
|
20
|
-
export
|
20
|
+
export interface Vec3 {
|
21
21
|
readonly x: number;
|
22
22
|
readonly y: number;
|
23
23
|
readonly z: number;
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
/**
|
25
|
+
* Returns the x, y components of this.
|
26
|
+
* May be implemented as a getter method.
|
27
|
+
*/
|
28
|
+
readonly xy: {
|
27
29
|
x: number;
|
28
30
|
y: number;
|
29
31
|
};
|
30
|
-
/**
|
31
|
-
|
32
|
-
/**
|
33
|
-
at(idx: number): number;
|
34
|
-
/** Alias for this.magnitude. */
|
32
|
+
/** Returns the vector's `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
|
33
|
+
at(i: number): number;
|
34
|
+
/** Alias for `.magnitude`. */
|
35
35
|
length(): number;
|
36
|
+
/** Returns the length of this vector in ℝ^3. */
|
36
37
|
magnitude(): number;
|
37
38
|
magnitudeSquared(): number;
|
38
39
|
/**
|
@@ -41,7 +42,7 @@ export declare class Vec3 {
|
|
41
42
|
*
|
42
43
|
* Equivalent to `.minus(p).magnitudeSquared()`.
|
43
44
|
*/
|
44
|
-
squareDistanceTo(
|
45
|
+
squareDistanceTo(other: Vec3): number;
|
45
46
|
/**
|
46
47
|
* Interpreting this vector as a point in ℝ³, returns the distance to the point
|
47
48
|
* `p`.
|
@@ -90,10 +91,17 @@ export declare class Vec3 {
|
|
90
91
|
normalizedOrZero(): Vec3;
|
91
92
|
/** @returns A copy of `this` multiplied by a scalar. */
|
92
93
|
times(c: number): Vec3;
|
94
|
+
/** Performs vector addition. */
|
93
95
|
plus(v: Vec3): Vec3;
|
94
96
|
minus(v: Vec3): Vec3;
|
95
|
-
|
96
|
-
|
97
|
+
/**
|
98
|
+
* Computes the scalar product between this and `v`.
|
99
|
+
*
|
100
|
+
* In particular, `a.dot(b)` is equivalent to `a.x * b.x + a.y * b.y + a.z * b.z`.
|
101
|
+
*/
|
102
|
+
dot(v: Vec3): number;
|
103
|
+
/** Computes the cross product between this and `v` */
|
104
|
+
cross(v: Vec3): Vec3;
|
97
105
|
/**
|
98
106
|
* If `other` is a `Vec3`, multiplies `this` component-wise by `other`. Otherwise,
|
99
107
|
* if `other is a `number`, returns the result of scalar multiplication.
|
@@ -154,11 +162,99 @@ export declare class Vec3 {
|
|
154
162
|
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
|
155
163
|
* ```
|
156
164
|
*/
|
165
|
+
eq(other: Vec3, tolerance?: number): boolean;
|
166
|
+
toString(): string;
|
167
|
+
}
|
168
|
+
declare class Vec2Impl implements Vec3 {
|
169
|
+
readonly x: number;
|
170
|
+
readonly y: number;
|
171
|
+
constructor(x: number, y: number);
|
172
|
+
get z(): number;
|
173
|
+
get xy(): {
|
174
|
+
x: number;
|
175
|
+
y: number;
|
176
|
+
};
|
177
|
+
at(idx: number): number;
|
178
|
+
length(): number;
|
179
|
+
magnitude(): number;
|
180
|
+
magnitudeSquared(): number;
|
181
|
+
squareDistanceTo(p: Vec3): number;
|
182
|
+
distanceTo(p: Vec3): number;
|
183
|
+
maximumEntryMagnitude(): number;
|
184
|
+
angle(): number;
|
185
|
+
normalized(): Vec3;
|
186
|
+
normalizedOrZero(): Vec3;
|
187
|
+
times(c: number): Vec3;
|
188
|
+
plus(v: Vec3): Vec3;
|
189
|
+
minus(v: Vec3): Vec3;
|
190
|
+
dot(other: Vec3): number;
|
191
|
+
cross(other: Vec3): Vec3;
|
192
|
+
scale(other: Vec3 | number): Vec3;
|
193
|
+
orthog(): Vec3;
|
194
|
+
extend(distance: number, direction: Vec3): Vec3;
|
195
|
+
lerp(target: Vec3, fractionTo: number): Vec3;
|
196
|
+
zip(other: Vec3, zip: (componentInThis: number, componentInOther: number) => number): Vec3;
|
197
|
+
map(fn: (component: number, index: number) => number): Vec3;
|
198
|
+
asArray(): [number, number, number];
|
157
199
|
eq(other: Vec3, fuzz?: number): boolean;
|
158
200
|
toString(): string;
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
201
|
+
}
|
202
|
+
/**
|
203
|
+
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
|
204
|
+
* always-zero `z` component.
|
205
|
+
*
|
206
|
+
* ```ts,runnable,console
|
207
|
+
* import { Vec2 } from '@js-draw/math';
|
208
|
+
* console.log(Vec2.of(1, 2));
|
209
|
+
* ```
|
210
|
+
*/
|
211
|
+
export declare namespace Vec2 {
|
212
|
+
/**
|
213
|
+
* Creates a `Vec2` from an x and y coordinate.
|
214
|
+
*
|
215
|
+
* @example
|
216
|
+
* ```ts,runnable,console
|
217
|
+
* import { Vec2 } from '@js-draw/math';
|
218
|
+
* const v = Vec2.of(3, 4); // x=3, y=4.
|
219
|
+
* ```
|
220
|
+
*/
|
221
|
+
const of: (x: number, y: number) => Vec2Impl;
|
222
|
+
/**
|
223
|
+
* Creates a `Vec2` from an object containing `x` and `y` coordinates.
|
224
|
+
*
|
225
|
+
* @example
|
226
|
+
* ```ts,runnable,console
|
227
|
+
* import { Vec2 } from '@js-draw/math';
|
228
|
+
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
|
229
|
+
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
|
230
|
+
* ```
|
231
|
+
*/
|
232
|
+
const ofXY: ({ x, y }: {
|
233
|
+
x: number;
|
234
|
+
y: number;
|
235
|
+
}) => Vec2Impl;
|
236
|
+
/** A vector of length 1 in the X direction (→). */
|
237
|
+
const unitX: Vec2Impl;
|
238
|
+
/** A vector of length 1 in the Y direction (↑). */
|
239
|
+
const unitY: Vec2Impl;
|
240
|
+
/** The zero vector: A vector with x=0, y=0. */
|
241
|
+
const zero: Vec2Impl;
|
242
|
+
}
|
243
|
+
export declare namespace Vec3 {
|
244
|
+
/**
|
245
|
+
* Construct a vector from three components.
|
246
|
+
*
|
247
|
+
* @example
|
248
|
+
* ```ts,runnable,console
|
249
|
+
* import { Vec3 } from '@js-draw/math';
|
250
|
+
* const v1 = Vec3.of(1, 2, 3);
|
251
|
+
* ```
|
252
|
+
*/
|
253
|
+
const of: (x: number, y: number, z: number) => Vec3;
|
254
|
+
const unitX: Vec2Impl;
|
255
|
+
const unitY: Vec2Impl;
|
256
|
+
const zero: Vec2Impl;
|
257
|
+
/** A vector of length 1 in the z direction. */
|
258
|
+
const unitZ: Vec3;
|
163
259
|
}
|
164
260
|
export default Vec3;
|
package/dist/cjs/Vec3.js
CHANGED
@@ -1,32 +1,13 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.Vec3 = void 0;
|
4
|
-
|
5
|
-
|
6
|
-
* Can also be used to represent a two-component vector.
|
7
|
-
*
|
8
|
-
* A `Vec3` is immutable.
|
9
|
-
*
|
10
|
-
* @example
|
11
|
-
*
|
12
|
-
* ```ts,runnable,console
|
13
|
-
* import { Vec3 } from '@js-draw/math';
|
14
|
-
*
|
15
|
-
* console.log('Vector addition:', Vec3.of(1, 2, 3).plus(Vec3.of(0, 1, 0)));
|
16
|
-
* console.log('Scalar multiplication:', Vec3.of(1, 2, 3).times(2));
|
17
|
-
* console.log('Cross products:', Vec3.unitX.cross(Vec3.unitY));
|
18
|
-
* console.log('Magnitude:', Vec3.of(1, 2, 3).length(), 'or', Vec3.of(1, 2, 3).magnitude());
|
19
|
-
* console.log('Square Magnitude:', Vec3.of(1, 2, 3).magnitudeSquared());
|
20
|
-
* console.log('As an array:', Vec3.unitZ.asArray());
|
21
|
-
* ```
|
22
|
-
*/
|
23
|
-
class Vec3 {
|
3
|
+
exports.Vec3 = exports.Vec2 = void 0;
|
4
|
+
const defaultEqlTolerance = 1e-10;
|
5
|
+
class Vec3Impl {
|
24
6
|
constructor(x, y, z) {
|
25
7
|
this.x = x;
|
26
8
|
this.y = y;
|
27
9
|
this.z = z;
|
28
10
|
}
|
29
|
-
/** Returns the x, y components of this. */
|
30
11
|
get xy() {
|
31
12
|
// Useful for APIs that behave differently if .z is present.
|
32
13
|
return {
|
@@ -34,10 +15,6 @@ class Vec3 {
|
|
34
15
|
y: this.y,
|
35
16
|
};
|
36
17
|
}
|
37
|
-
/** Construct a vector from three components. */
|
38
|
-
static of(x, y, z) {
|
39
|
-
return new Vec3(x, y, z);
|
40
|
-
}
|
41
18
|
/** Returns this' `idx`th component. For example, `Vec3.of(1, 2, 3).at(1) → 2`. */
|
42
19
|
at(idx) {
|
43
20
|
if (idx === 0)
|
@@ -48,89 +25,40 @@ class Vec3 {
|
|
48
25
|
return this.z;
|
49
26
|
throw new Error(`${idx} out of bounds!`);
|
50
27
|
}
|
51
|
-
/** Alias for this.magnitude. */
|
52
28
|
length() {
|
53
29
|
return this.magnitude();
|
54
30
|
}
|
55
31
|
magnitude() {
|
56
|
-
return Math.sqrt(this.
|
32
|
+
return Math.sqrt(this.magnitudeSquared());
|
57
33
|
}
|
58
34
|
magnitudeSquared() {
|
59
|
-
return this.
|
35
|
+
return this.x * this.x + this.y * this.y + this.z * this.z;
|
60
36
|
}
|
61
|
-
/**
|
62
|
-
* Interpreting this vector as a point in ℝ^3, computes the square distance
|
63
|
-
* to another point, `p`.
|
64
|
-
*
|
65
|
-
* Equivalent to `.minus(p).magnitudeSquared()`.
|
66
|
-
*/
|
67
37
|
squareDistanceTo(p) {
|
68
38
|
const dx = this.x - p.x;
|
69
39
|
const dy = this.y - p.y;
|
70
40
|
const dz = this.z - p.z;
|
71
41
|
return dx * dx + dy * dy + dz * dz;
|
72
42
|
}
|
73
|
-
/**
|
74
|
-
* Interpreting this vector as a point in ℝ³, returns the distance to the point
|
75
|
-
* `p`.
|
76
|
-
*
|
77
|
-
* Equivalent to `.minus(p).magnitude()`.
|
78
|
-
*/
|
79
43
|
distanceTo(p) {
|
80
44
|
return Math.sqrt(this.squareDistanceTo(p));
|
81
45
|
}
|
82
|
-
/**
|
83
|
-
* Returns the entry of this with the greatest magnitude.
|
84
|
-
*
|
85
|
-
* In other words, returns $\max \{ |x| : x \in {\bf v} \}$, where ${\bf v}$ is the set of
|
86
|
-
* all entries of this vector.
|
87
|
-
*
|
88
|
-
* **Example**:
|
89
|
-
* ```ts,runnable,console
|
90
|
-
* import { Vec3 } from '@js-draw/math';
|
91
|
-
* console.log(Vec3.of(-1, -10, 8).maximumEntryMagnitude()); // -> 10
|
92
|
-
* ```
|
93
|
-
*/
|
94
46
|
maximumEntryMagnitude() {
|
95
47
|
return Math.max(Math.abs(this.x), Math.max(Math.abs(this.y), Math.abs(this.z)));
|
96
48
|
}
|
97
|
-
/**
|
98
|
-
* Return this' angle in the XY plane (treats this as a Vec2).
|
99
|
-
*
|
100
|
-
* This is equivalent to `Math.atan2(vec.y, vec.x)`.
|
101
|
-
*
|
102
|
-
* As such, observing that `Math.atan2(-0, -1)` $\approx -\pi$ and `Math.atan2(0, -1)`$\approx \pi$
|
103
|
-
* the resultant angle is in the range $[-\pi, pi]$.
|
104
|
-
*
|
105
|
-
* **Example**:
|
106
|
-
* ```ts,runnable,console
|
107
|
-
* import { Vec2 } from '@js-draw/math';
|
108
|
-
* console.log(Vec2.of(-1, -0).angle()); // atan2(-0, -1)
|
109
|
-
* console.log(Vec2.of(-1, 0).angle()); // atan2(0, -1)
|
110
|
-
* ```
|
111
|
-
*/
|
112
49
|
angle() {
|
113
50
|
return Math.atan2(this.y, this.x);
|
114
51
|
}
|
115
|
-
/**
|
116
|
-
* Returns a unit vector in the same direction as this.
|
117
|
-
*
|
118
|
-
* If `this` has zero length, the resultant vector has `NaN` components.
|
119
|
-
*/
|
120
52
|
normalized() {
|
121
53
|
const norm = this.magnitude();
|
122
54
|
return Vec3.of(this.x / norm, this.y / norm, this.z / norm);
|
123
55
|
}
|
124
|
-
/**
|
125
|
-
* Like {@link normalized}, except returns zero if this has zero magnitude.
|
126
|
-
*/
|
127
56
|
normalizedOrZero() {
|
128
57
|
if (this.eq(Vec3.zero)) {
|
129
58
|
return Vec3.zero;
|
130
59
|
}
|
131
60
|
return this.normalized();
|
132
61
|
}
|
133
|
-
/** @returns A copy of `this` multiplied by a scalar. */
|
134
62
|
times(c) {
|
135
63
|
return Vec3.of(this.x * c, this.y * c, this.z * c);
|
136
64
|
}
|
@@ -149,25 +77,12 @@ class Vec3 {
|
|
149
77
|
// | x2 y2 z2|
|
150
78
|
return Vec3.of(this.y * other.z - other.y * this.z, other.x * this.z - this.x * other.z, this.x * other.y - other.x * this.y);
|
151
79
|
}
|
152
|
-
/**
|
153
|
-
* If `other` is a `Vec3`, multiplies `this` component-wise by `other`. Otherwise,
|
154
|
-
* if `other is a `number`, returns the result of scalar multiplication.
|
155
|
-
*
|
156
|
-
* @example
|
157
|
-
* ```
|
158
|
-
* Vec3.of(1, 2, 3).scale(Vec3.of(2, 4, 6)); // → Vec3(2, 8, 18)
|
159
|
-
* ```
|
160
|
-
*/
|
161
80
|
scale(other) {
|
162
81
|
if (typeof other === 'number') {
|
163
82
|
return this.times(other);
|
164
83
|
}
|
165
84
|
return Vec3.of(this.x * other.x, this.y * other.y, this.z * other.z);
|
166
85
|
}
|
167
|
-
/**
|
168
|
-
* Returns a vector orthogonal to this. If this is a Vec2, returns `this` rotated
|
169
|
-
* 90 degrees counter-clockwise.
|
170
|
-
*/
|
171
86
|
orthog() {
|
172
87
|
// If parallel to the z-axis
|
173
88
|
if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
|
@@ -175,62 +90,22 @@ class Vec3 {
|
|
175
90
|
}
|
176
91
|
return this.cross(Vec3.unitZ.times(-1)).normalized();
|
177
92
|
}
|
178
|
-
/** Returns this plus a vector of length `distance` in `direction`. */
|
179
93
|
extend(distance, direction) {
|
180
94
|
return this.plus(direction.normalized().times(distance));
|
181
95
|
}
|
182
|
-
/** Returns a vector `fractionTo` of the way to target from this. */
|
183
96
|
lerp(target, fractionTo) {
|
184
97
|
return this.times(1 - fractionTo).plus(target.times(fractionTo));
|
185
98
|
}
|
186
|
-
/**
|
187
|
-
* `zip` Maps a component of this and a corresponding component of
|
188
|
-
* `other` to a component of the output vector.
|
189
|
-
*
|
190
|
-
* @example
|
191
|
-
* ```
|
192
|
-
* const a = Vec3.of(1, 2, 3);
|
193
|
-
* const b = Vec3.of(0.5, 2.1, 2.9);
|
194
|
-
*
|
195
|
-
* const zipped = a.zip(b, (aComponent, bComponent) => {
|
196
|
-
* return Math.min(aComponent, bComponent);
|
197
|
-
* });
|
198
|
-
*
|
199
|
-
* console.log(zipped.toString()); // → Vec(0.5, 2, 2.9)
|
200
|
-
* ```
|
201
|
-
*/
|
202
99
|
zip(other, zip) {
|
203
100
|
return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, this.z));
|
204
101
|
}
|
205
|
-
/**
|
206
|
-
* Returns a vector with each component acted on by `fn`.
|
207
|
-
*
|
208
|
-
* @example
|
209
|
-
* ```ts,runnable,console
|
210
|
-
* import { Vec3 } from '@js-draw/math';
|
211
|
-
* console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
|
212
|
-
* ```
|
213
|
-
*/
|
214
102
|
map(fn) {
|
215
103
|
return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(this.z, 2));
|
216
104
|
}
|
217
105
|
asArray() {
|
218
106
|
return [this.x, this.y, this.z];
|
219
107
|
}
|
220
|
-
|
221
|
-
* [fuzz] The maximum difference between two components for this and [other]
|
222
|
-
* to be considered equal.
|
223
|
-
*
|
224
|
-
* @example
|
225
|
-
* ```
|
226
|
-
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 100); // → true
|
227
|
-
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 0.1); // → false
|
228
|
-
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3); // → true
|
229
|
-
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 3.01); // → true
|
230
|
-
* Vec3.of(1, 2, 3).eq(Vec3.of(4, 5, 6), 2.99); // → false
|
231
|
-
* ```
|
232
|
-
*/
|
233
|
-
eq(other, fuzz = 1e-10) {
|
108
|
+
eq(other, fuzz = defaultEqlTolerance) {
|
234
109
|
return (Math.abs(other.x - this.x) <= fuzz
|
235
110
|
&& Math.abs(other.y - this.y) <= fuzz
|
236
111
|
&& Math.abs(other.z - this.z) <= fuzz);
|
@@ -239,9 +114,182 @@ class Vec3 {
|
|
239
114
|
return `Vec(${this.x}, ${this.y}, ${this.z})`;
|
240
115
|
}
|
241
116
|
}
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
117
|
+
class Vec2Impl {
|
118
|
+
constructor(x, y) {
|
119
|
+
this.x = x;
|
120
|
+
this.y = y;
|
121
|
+
}
|
122
|
+
get z() { return 0; }
|
123
|
+
get xy() {
|
124
|
+
// Useful for APIs that behave differently if .z is present.
|
125
|
+
return {
|
126
|
+
x: this.x,
|
127
|
+
y: this.y,
|
128
|
+
};
|
129
|
+
}
|
130
|
+
at(idx) {
|
131
|
+
if (idx === 0)
|
132
|
+
return this.x;
|
133
|
+
if (idx === 1)
|
134
|
+
return this.y;
|
135
|
+
if (idx === 2)
|
136
|
+
return 0;
|
137
|
+
throw new Error(`${idx} out of bounds!`);
|
138
|
+
}
|
139
|
+
length() {
|
140
|
+
return this.magnitude();
|
141
|
+
}
|
142
|
+
magnitude() {
|
143
|
+
return Math.sqrt(this.x * this.x + this.y * this.y);
|
144
|
+
}
|
145
|
+
magnitudeSquared() {
|
146
|
+
return this.x * this.x + this.y * this.y;
|
147
|
+
}
|
148
|
+
squareDistanceTo(p) {
|
149
|
+
const dx = this.x - p.x;
|
150
|
+
const dy = this.y - p.y;
|
151
|
+
return dx * dx + dy * dy + p.z * p.z;
|
152
|
+
}
|
153
|
+
distanceTo(p) {
|
154
|
+
return Math.sqrt(this.squareDistanceTo(p));
|
155
|
+
}
|
156
|
+
maximumEntryMagnitude() {
|
157
|
+
return Math.max(Math.abs(this.x), Math.abs(this.y));
|
158
|
+
}
|
159
|
+
angle() {
|
160
|
+
return Math.atan2(this.y, this.x);
|
161
|
+
}
|
162
|
+
normalized() {
|
163
|
+
const norm = this.magnitude();
|
164
|
+
return Vec2.of(this.x / norm, this.y / norm);
|
165
|
+
}
|
166
|
+
normalizedOrZero() {
|
167
|
+
if (this.eq(Vec3.zero)) {
|
168
|
+
return Vec3.zero;
|
169
|
+
}
|
170
|
+
return this.normalized();
|
171
|
+
}
|
172
|
+
times(c) {
|
173
|
+
return Vec2.of(this.x * c, this.y * c);
|
174
|
+
}
|
175
|
+
plus(v) {
|
176
|
+
return Vec3.of(this.x + v.x, this.y + v.y, v.z);
|
177
|
+
}
|
178
|
+
minus(v) {
|
179
|
+
return Vec3.of(this.x - v.x, this.y - v.y, -v.z);
|
180
|
+
}
|
181
|
+
dot(other) {
|
182
|
+
return this.x * other.x + this.y * other.y;
|
183
|
+
}
|
184
|
+
cross(other) {
|
185
|
+
// | i j k |
|
186
|
+
// | x1 y1 z1| = (i)(y1z2 - y2z1) - (j)(x1z2 - x2z1) + (k)(x1y2 - x2y1)
|
187
|
+
// | x2 y2 z2|
|
188
|
+
return Vec3.of(this.y * other.z, -this.x * other.z, this.x * other.y - other.x * this.y);
|
189
|
+
}
|
190
|
+
scale(other) {
|
191
|
+
if (typeof other === 'number') {
|
192
|
+
return this.times(other);
|
193
|
+
}
|
194
|
+
return Vec2.of(this.x * other.x, this.y * other.y);
|
195
|
+
}
|
196
|
+
orthog() {
|
197
|
+
// If parallel to the z-axis
|
198
|
+
if (this.dot(Vec3.unitX) === 0 && this.dot(Vec3.unitY) === 0) {
|
199
|
+
return this.dot(Vec3.unitX) === 0 ? Vec3.unitX : this.cross(Vec3.unitX).normalized();
|
200
|
+
}
|
201
|
+
return this.cross(Vec3.unitZ.times(-1)).normalized();
|
202
|
+
}
|
203
|
+
extend(distance, direction) {
|
204
|
+
return this.plus(direction.normalized().times(distance));
|
205
|
+
}
|
206
|
+
lerp(target, fractionTo) {
|
207
|
+
return this.times(1 - fractionTo).plus(target.times(fractionTo));
|
208
|
+
}
|
209
|
+
zip(other, zip) {
|
210
|
+
return Vec3.of(zip(other.x, this.x), zip(other.y, this.y), zip(other.z, 0));
|
211
|
+
}
|
212
|
+
map(fn) {
|
213
|
+
return Vec3.of(fn(this.x, 0), fn(this.y, 1), fn(0, 2));
|
214
|
+
}
|
215
|
+
asArray() {
|
216
|
+
return [this.x, this.y, 0];
|
217
|
+
}
|
218
|
+
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);
|
222
|
+
}
|
223
|
+
toString() {
|
224
|
+
return `Vec(${this.x}, ${this.y})`;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
/**
|
228
|
+
* A `Vec2` is a `Vec3` optimized for working in a plane. As such, they have an
|
229
|
+
* always-zero `z` component.
|
230
|
+
*
|
231
|
+
* ```ts,runnable,console
|
232
|
+
* import { Vec2 } from '@js-draw/math';
|
233
|
+
* console.log(Vec2.of(1, 2));
|
234
|
+
* ```
|
235
|
+
*/
|
236
|
+
var Vec2;
|
237
|
+
(function (Vec2) {
|
238
|
+
/**
|
239
|
+
* Creates a `Vec2` from an x and y coordinate.
|
240
|
+
*
|
241
|
+
* @example
|
242
|
+
* ```ts,runnable,console
|
243
|
+
* import { Vec2 } from '@js-draw/math';
|
244
|
+
* const v = Vec2.of(3, 4); // x=3, y=4.
|
245
|
+
* ```
|
246
|
+
*/
|
247
|
+
Vec2.of = (x, y) => {
|
248
|
+
return new Vec2Impl(x, y);
|
249
|
+
};
|
250
|
+
/**
|
251
|
+
* Creates a `Vec2` from an object containing `x` and `y` coordinates.
|
252
|
+
*
|
253
|
+
* @example
|
254
|
+
* ```ts,runnable,console
|
255
|
+
* import { Vec2 } from '@js-draw/math';
|
256
|
+
* const v1 = Vec2.ofXY({ x: 3, y: 4.5 });
|
257
|
+
* const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
|
258
|
+
* ```
|
259
|
+
*/
|
260
|
+
Vec2.ofXY = ({ x, y }) => {
|
261
|
+
return Vec2.of(x, y);
|
262
|
+
};
|
263
|
+
/** A vector of length 1 in the X direction (→). */
|
264
|
+
Vec2.unitX = Vec2.of(1, 0);
|
265
|
+
/** A vector of length 1 in the Y direction (↑). */
|
266
|
+
Vec2.unitY = Vec2.of(0, 1);
|
267
|
+
/** The zero vector: A vector with x=0, y=0. */
|
268
|
+
Vec2.zero = Vec2.of(0, 0);
|
269
|
+
})(Vec2 || (exports.Vec2 = Vec2 = {}));
|
270
|
+
var Vec3;
|
271
|
+
(function (Vec3) {
|
272
|
+
/**
|
273
|
+
* Construct a vector from three components.
|
274
|
+
*
|
275
|
+
* @example
|
276
|
+
* ```ts,runnable,console
|
277
|
+
* import { Vec3 } from '@js-draw/math';
|
278
|
+
* const v1 = Vec3.of(1, 2, 3);
|
279
|
+
* ```
|
280
|
+
*/
|
281
|
+
Vec3.of = (x, y, z) => {
|
282
|
+
if (z === 0) {
|
283
|
+
return Vec2.of(x, y);
|
284
|
+
}
|
285
|
+
else {
|
286
|
+
return new Vec3Impl(x, y, z);
|
287
|
+
}
|
288
|
+
};
|
289
|
+
Vec3.unitX = Vec2.unitX;
|
290
|
+
Vec3.unitY = Vec2.unitY;
|
291
|
+
Vec3.zero = Vec2.zero;
|
292
|
+
/** A vector of length 1 in the z direction. */
|
293
|
+
Vec3.unitZ = Vec3.of(0, 0, 1);
|
294
|
+
})(Vec3 || (exports.Vec3 = Vec3 = {}));
|
247
295
|
exports.default = Vec3;
|