@inglorious/utils 2.2.0 → 3.0.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/README.md +1 -1
- package/package.json +1 -1
- package/src/algorithms/decision-tree.test.js +7 -6
- package/src/algorithms/index.js +4 -0
- package/src/algorithms/path-finding.js +2 -2
- package/src/data-structures/index.js +10 -0
- package/src/functions/index.js +4 -0
- package/src/index.js +8 -0
- package/src/math/{geometry/circle.js → circle.js} +6 -6
- package/src/math/{geometry/circle.test.js → circle.test.js} +23 -22
- package/src/math/{geometry/hitmask.test.js → hitmask.test.js} +16 -15
- package/src/math/index.js +35 -0
- package/src/math/{geometry/line.js → line.js} +4 -4
- package/src/math/{geometry/line.test.js → line.test.js} +11 -10
- package/src/math/{geometry/point.js → point.js} +5 -5
- package/src/math/{geometry/point.test.js → point.test.js} +23 -22
- package/src/math/{linear-algebra/quaternion.js → quaternion.js} +3 -2
- package/src/math/{linear-algebra/quaternion.test.js → quaternion.test.js} +1 -1
- package/src/math/{linear-algebra/quaternions.test.js → quaternions.test.js} +1 -1
- package/src/math/{geometry/rectangle.js → rectangle.js} +3 -3
- package/src/math/{geometry/rectangle.test.js → rectangle.test.js} +13 -12
- package/src/math/{geometry/segment.js → segment.js} +5 -5
- package/src/math/{geometry/segment.test.js → segment.test.js} +48 -47
- package/src/math/{geometry/types.d.ts → types.d.ts} +10 -0
- package/src/math/{linear-algebra/vector.js → vector.js} +113 -65
- package/src/math/{linear-algebra/vector.test.js → vector.test.js} +80 -29
- package/src/math/{linear-algebra/vectors.test.js → vectors.test.js} +12 -30
- package/src/physics/acceleration.js +3 -3
- package/src/physics/friction.js +2 -2
- package/src/physics/friction.test.js +7 -6
- package/src/physics/gravity.js +2 -2
- package/src/physics/gravity.test.js +10 -9
- package/src/physics/index.js +7 -0
- package/src/physics/jump.js +1 -1
- package/src/physics/velocity.js +3 -3
- package/src/v.js +18 -0
- package/src/math/linear-algebra/2d.js +0 -28
- package/src/math/linear-algebra/2d.test.js +0 -17
- package/src/math/linear-algebra/types.d.ts +0 -4
- /package/src/math/{geometry/hitmask.js → hitmask.js} +0 -0
- /package/src/math/{linear-algebra/quaternions.js → quaternions.js} +0 -0
- /package/src/math/{geometry/triangle.js → triangle.js} +0 -0
- /package/src/math/{geometry/triangle.test.js → triangle.test.js} +0 -0
- /package/src/math/{linear-algebra/vectors.js → vectors.js} +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
+
import { v } from "../v.js"
|
|
3
4
|
import { intersectsRectangle } from "./rectangle.js"
|
|
4
5
|
|
|
5
6
|
test("it should prove that a rectangle crossing another one intersects with it", () => {
|
|
6
7
|
const rectangle1 = {
|
|
7
|
-
position:
|
|
8
|
-
size:
|
|
8
|
+
position: v(0, 0, 0),
|
|
9
|
+
size: v(2, 2, 2),
|
|
9
10
|
}
|
|
10
11
|
const rectangle2 = {
|
|
11
|
-
position:
|
|
12
|
-
size:
|
|
12
|
+
position: v(1, 1, 1),
|
|
13
|
+
size: v(2, 2, 2),
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
expect(intersectsRectangle(rectangle1, rectangle2)).toBe(true)
|
|
@@ -17,12 +18,12 @@ test("it should prove that a rectangle crossing another one intersects with it",
|
|
|
17
18
|
|
|
18
19
|
test("it should prove that a rectangle right on top of another intersects with it", () => {
|
|
19
20
|
const rectangle1 = {
|
|
20
|
-
position:
|
|
21
|
-
size:
|
|
21
|
+
position: v(0, 0, 0),
|
|
22
|
+
size: v(2, 2, 2),
|
|
22
23
|
}
|
|
23
24
|
const rectangle2 = {
|
|
24
|
-
position:
|
|
25
|
-
size:
|
|
25
|
+
position: v(0, 0, 0),
|
|
26
|
+
size: v(2, 0, 2),
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
expect(intersectsRectangle(rectangle1, rectangle2)).toBe(true)
|
|
@@ -30,12 +31,12 @@ test("it should prove that a rectangle right on top of another intersects with i
|
|
|
30
31
|
|
|
31
32
|
test("it should prove that a rectangle not crossing another one does not intersect with it", () => {
|
|
32
33
|
const rectangle1 = {
|
|
33
|
-
position:
|
|
34
|
-
size:
|
|
34
|
+
position: v(0, 0, 0),
|
|
35
|
+
size: v(2, 2, 2),
|
|
35
36
|
}
|
|
36
37
|
const rectangle2 = {
|
|
37
|
-
position:
|
|
38
|
-
size:
|
|
38
|
+
position: v(3, 3, 3),
|
|
39
|
+
size: v(2, 2, 2),
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
expect(intersectsRectangle(rectangle1, rectangle2)).toBe(false)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("./types").Segment} Segment
|
|
3
|
-
* @typedef {import("./types").Point} Point
|
|
4
|
-
* @typedef {import("./types").Circle} Circle
|
|
2
|
+
* @typedef {import("./geometry/types.js").Segment} Segment
|
|
3
|
+
* @typedef {import("./geometry/types.js").Point} Point
|
|
4
|
+
* @typedef {import("./geometry/types.js").Circle} Circle
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { magnitude, setMagnitude } from "
|
|
8
|
-
import { distance, dot, subtract, sum } from "
|
|
7
|
+
import { magnitude, setMagnitude } from "./vector.js"
|
|
8
|
+
import { distance, dot, subtract, sum } from "./vectors.js"
|
|
9
9
|
|
|
10
10
|
const BEFORE_SEGMENT = 0
|
|
11
11
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { v } from "../v.js"
|
|
4
|
+
import { isClose } from "./numbers.js"
|
|
4
5
|
import {
|
|
5
6
|
closestPoint,
|
|
6
7
|
coefficients,
|
|
@@ -21,64 +22,64 @@ expect.extend({
|
|
|
21
22
|
|
|
22
23
|
test("it should retrieve values of *a*, *b*, and *c* from a segment, so it looks like a line in the form *ax + by + c = 0*", () => {
|
|
23
24
|
const segment = {
|
|
24
|
-
from:
|
|
25
|
-
to:
|
|
25
|
+
from: v(0, 0, 0),
|
|
26
|
+
to: v(1, 0, 2),
|
|
26
27
|
}
|
|
27
|
-
const expectedResult =
|
|
28
|
+
const expectedResult = v(-2, 1, 0)
|
|
28
29
|
|
|
29
30
|
expect(coefficients(segment)).toStrictEqual(expectedResult)
|
|
30
31
|
})
|
|
31
32
|
|
|
32
33
|
test("it should find the closest point in a segment to a point projectable on it", () => {
|
|
33
34
|
const segment = {
|
|
34
|
-
from:
|
|
35
|
-
to:
|
|
35
|
+
from: v(0, 0, 0),
|
|
36
|
+
to: v(2, 0, 2),
|
|
36
37
|
}
|
|
37
|
-
const point =
|
|
38
|
-
const expectedResult =
|
|
38
|
+
const point = v(2, 0, 0)
|
|
39
|
+
const expectedResult = v(1, 0, 1)
|
|
39
40
|
|
|
40
41
|
expect(closestPoint(segment, point)).toStrictEqualVector(expectedResult)
|
|
41
42
|
})
|
|
42
43
|
|
|
43
44
|
test("it should find the closest point as the point itself when resting on the segment", () => {
|
|
44
45
|
const segment = {
|
|
45
|
-
from:
|
|
46
|
-
to:
|
|
46
|
+
from: v(0, 0, 0),
|
|
47
|
+
to: v(2, 0, 2),
|
|
47
48
|
}
|
|
48
|
-
const point =
|
|
49
|
-
const expectedResult =
|
|
49
|
+
const point = v(1, 0, 1)
|
|
50
|
+
const expectedResult = v(1, 0, 1)
|
|
50
51
|
|
|
51
52
|
expect(closestPoint(segment, point)).toStrictEqualVector(expectedResult)
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
test("it return the start of a segment when the point is close to its start", () => {
|
|
55
56
|
const segment = {
|
|
56
|
-
from:
|
|
57
|
-
to:
|
|
57
|
+
from: v(0, 0, 0),
|
|
58
|
+
to: v(3, 0, 4),
|
|
58
59
|
}
|
|
59
|
-
const point =
|
|
60
|
-
const expectedResult =
|
|
60
|
+
const point = v(-2, 0, 0)
|
|
61
|
+
const expectedResult = v(0, 0, 0)
|
|
61
62
|
|
|
62
63
|
expect(closestPoint(segment, point)).toStrictEqualVector(expectedResult)
|
|
63
64
|
})
|
|
64
65
|
|
|
65
66
|
test("it should return the end of a segment when the point is close to its end", () => {
|
|
66
67
|
const segment = {
|
|
67
|
-
from:
|
|
68
|
-
to:
|
|
68
|
+
from: v(0, 0, 0),
|
|
69
|
+
to: v(3, 0, 4),
|
|
69
70
|
}
|
|
70
|
-
const point =
|
|
71
|
-
const expectedResult =
|
|
71
|
+
const point = v(5, 0, 4)
|
|
72
|
+
const expectedResult = v(3, 0, 4)
|
|
72
73
|
|
|
73
74
|
expect(closestPoint(segment, point)).toStrictEqualVector(expectedResult)
|
|
74
75
|
})
|
|
75
76
|
|
|
76
77
|
test("it should compute the distance between a segment and a point projectable on it", () => {
|
|
77
78
|
const segment = {
|
|
78
|
-
from:
|
|
79
|
-
to:
|
|
79
|
+
from: v(0, 0, 0),
|
|
80
|
+
to: v(3, 0, 4),
|
|
80
81
|
}
|
|
81
|
-
const point =
|
|
82
|
+
const point = v(5, 0, 0)
|
|
82
83
|
const expectedResult = 4
|
|
83
84
|
|
|
84
85
|
expect(distanceFromPoint(segment, point)).toBe(expectedResult)
|
|
@@ -86,10 +87,10 @@ test("it should compute the distance between a segment and a point projectable o
|
|
|
86
87
|
|
|
87
88
|
test("it should compute the distance between a segment and a point resting on it", () => {
|
|
88
89
|
const segment = {
|
|
89
|
-
from:
|
|
90
|
-
to:
|
|
90
|
+
from: v(0, 0, 0),
|
|
91
|
+
to: v(2, 0, 2),
|
|
91
92
|
}
|
|
92
|
-
const point =
|
|
93
|
+
const point = v(1, 0, 1)
|
|
93
94
|
const expectedResult = 0
|
|
94
95
|
|
|
95
96
|
expect(distanceFromPoint(segment, point)).toBeCloseTo(expectedResult)
|
|
@@ -97,10 +98,10 @@ test("it should compute the distance between a segment and a point resting on it
|
|
|
97
98
|
|
|
98
99
|
test("it should compute the distance between a segment and a point close to the start", () => {
|
|
99
100
|
const segment = {
|
|
100
|
-
from:
|
|
101
|
-
to:
|
|
101
|
+
from: v(0, 0, 0),
|
|
102
|
+
to: v(3, 0, 4),
|
|
102
103
|
}
|
|
103
|
-
const point =
|
|
104
|
+
const point = v(-2, 0, 0)
|
|
104
105
|
const expectedResult = 2
|
|
105
106
|
|
|
106
107
|
expect(distanceFromPoint(segment, point)).toBe(expectedResult)
|
|
@@ -108,10 +109,10 @@ test("it should compute the distance between a segment and a point close to the
|
|
|
108
109
|
|
|
109
110
|
test("it should compute the distance between a segment and a point close to the end", () => {
|
|
110
111
|
const segment = {
|
|
111
|
-
from:
|
|
112
|
-
to:
|
|
112
|
+
from: v(0, 0, 0),
|
|
113
|
+
to: v(3, 0, 4),
|
|
113
114
|
}
|
|
114
|
-
const point =
|
|
115
|
+
const point = v(5, 0, 4)
|
|
115
116
|
const expectedResult = 2
|
|
116
117
|
|
|
117
118
|
expect(distanceFromPoint(segment, point)).toBeCloseTo(expectedResult)
|
|
@@ -119,11 +120,11 @@ test("it should compute the distance between a segment and a point close to the
|
|
|
119
120
|
|
|
120
121
|
test("it should prove that a segment that crosses a circle intersects with it", () => {
|
|
121
122
|
const segment = {
|
|
122
|
-
from:
|
|
123
|
-
to:
|
|
123
|
+
from: v(0, 0, 0),
|
|
124
|
+
to: v(2, 0, 2),
|
|
124
125
|
}
|
|
125
126
|
const circle = {
|
|
126
|
-
position:
|
|
127
|
+
position: v(1, 0, 1),
|
|
127
128
|
radius: 1,
|
|
128
129
|
}
|
|
129
130
|
|
|
@@ -132,11 +133,11 @@ test("it should prove that a segment that crosses a circle intersects with it",
|
|
|
132
133
|
|
|
133
134
|
test("it should prove that a segment tangent to a circle intersects with it", () => {
|
|
134
135
|
const segment = {
|
|
135
|
-
from:
|
|
136
|
-
to:
|
|
136
|
+
from: v(0, 0, 0),
|
|
137
|
+
to: v(0, 0, 2),
|
|
137
138
|
}
|
|
138
139
|
const circle = {
|
|
139
|
-
position:
|
|
140
|
+
position: v(1, 0, 1),
|
|
140
141
|
radius: 1,
|
|
141
142
|
}
|
|
142
143
|
|
|
@@ -145,11 +146,11 @@ test("it should prove that a segment tangent to a circle intersects with it", ()
|
|
|
145
146
|
|
|
146
147
|
test("it should prove that a segment inside of a circle intersects with it", () => {
|
|
147
148
|
const segment = {
|
|
148
|
-
from:
|
|
149
|
-
to:
|
|
149
|
+
from: v(0.5, 0, 0.5),
|
|
150
|
+
to: v(1.5, 0, 1.5),
|
|
150
151
|
}
|
|
151
152
|
const circle = {
|
|
152
|
-
position:
|
|
153
|
+
position: v(1, 0, 1),
|
|
153
154
|
radius: 1,
|
|
154
155
|
}
|
|
155
156
|
|
|
@@ -158,11 +159,11 @@ test("it should prove that a segment inside of a circle intersects with it", ()
|
|
|
158
159
|
|
|
159
160
|
test("it should prove that a segment that does not cross a circle does not intersect with it", () => {
|
|
160
161
|
const segment = {
|
|
161
|
-
from:
|
|
162
|
-
to:
|
|
162
|
+
from: v(0, 0, 0),
|
|
163
|
+
to: v(-2, 0, 2),
|
|
163
164
|
}
|
|
164
165
|
const circle = {
|
|
165
|
-
position:
|
|
166
|
+
position: v(1, 0, 1),
|
|
166
167
|
radius: 1,
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -171,11 +172,11 @@ test("it should prove that a segment that does not cross a circle does not inter
|
|
|
171
172
|
|
|
172
173
|
test("it should prove that a segment that reaches outside of a circle does not intersect with it", () => {
|
|
173
174
|
const segment = {
|
|
174
|
-
from:
|
|
175
|
-
to:
|
|
175
|
+
from: v(0, 0, 0),
|
|
176
|
+
to: v(-1, 0, -2),
|
|
176
177
|
}
|
|
177
178
|
const circle = {
|
|
178
|
-
position:
|
|
179
|
+
position: v(1, 0, 1),
|
|
179
180
|
radius: 1,
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// geometry
|
|
2
|
+
|
|
1
3
|
export type Point = [number, number, number] // [x, y, z]
|
|
2
4
|
export type Size = [number, number, number] // [width, height, depth]
|
|
3
5
|
export type Line = [number, number, number] // [a, b, c]
|
|
@@ -21,3 +23,11 @@ export interface Segment {
|
|
|
21
23
|
from: Point
|
|
22
24
|
to: Point
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
// linear algebra
|
|
28
|
+
|
|
29
|
+
export type Vector = number[]
|
|
30
|
+
export type Vector2 = [number, number]
|
|
31
|
+
export type Vector3 = [number, number, number]
|
|
32
|
+
export type Quaternion = [number, number, number, number]
|
|
33
|
+
export type Vector7 = [number, number, number, number, number, number, number]
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* @typedef {import('./types').Vector} Vector
|
|
2
3
|
* @typedef {import('./types').Vector2} Vector2
|
|
3
4
|
* @typedef {import('./types').Vector3} Vector3
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import { isArray } from "
|
|
7
|
-
import {
|
|
7
|
+
import { isArray } from "../data-structures/array.js"
|
|
8
|
+
import { v } from "../v.js"
|
|
8
9
|
import {
|
|
9
10
|
abs as nAbs,
|
|
10
11
|
clamp as nClamp,
|
|
11
12
|
mod as nMod,
|
|
12
13
|
snap as nSnap,
|
|
13
|
-
} from "
|
|
14
|
-
import { atan2, cos, sin } from "../trigonometry.js"
|
|
15
|
-
import { from2D, to2D } from "./2d.js"
|
|
14
|
+
} from "./numbers.js"
|
|
16
15
|
import { quaternion } from "./quaternion.js"
|
|
16
|
+
import { hypothenuse } from "./triangle.js"
|
|
17
|
+
import { atan2, cos, sin } from "./trigonometry.js"
|
|
17
18
|
import { cross, sum } from "./vectors.js"
|
|
18
19
|
|
|
19
|
-
const ZERO_VECTOR =
|
|
20
|
-
const UNIT_VECTOR =
|
|
20
|
+
const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
|
|
21
|
+
const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
|
|
21
22
|
|
|
22
23
|
const X = 0
|
|
23
24
|
const Y = 1
|
|
@@ -30,8 +31,9 @@ const DEFAULT_DECIMALS = 0
|
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Returns the absolute value of each component in the vector.
|
|
33
|
-
*
|
|
34
|
-
* @
|
|
34
|
+
*
|
|
35
|
+
* @param {Vector} vector - The input vector.
|
|
36
|
+
* @returns {Vector} The vector with absolute values.
|
|
35
37
|
*/
|
|
36
38
|
export function abs(vector) {
|
|
37
39
|
return vector.map(nAbs)
|
|
@@ -39,8 +41,9 @@ export function abs(vector) {
|
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* Calculates the angle of the vector in radians.
|
|
42
|
-
*
|
|
43
|
-
* @
|
|
44
|
+
*
|
|
45
|
+
* @param {Vector} vector - The input vector.
|
|
46
|
+
* @returns {number} The angle of the vector in the XZ plane (for 3D) or XY plane (for 2D), in radians.
|
|
44
47
|
*/
|
|
45
48
|
export function angle(vector) {
|
|
46
49
|
return atan2(vector[vector.length - LAST_COORDINATE], vector[X])
|
|
@@ -48,10 +51,11 @@ export function angle(vector) {
|
|
|
48
51
|
|
|
49
52
|
/**
|
|
50
53
|
* Clamps the magnitude of the vector between the given min and max values.
|
|
51
|
-
*
|
|
52
|
-
* @param {
|
|
53
|
-
* @param {number}
|
|
54
|
-
* @
|
|
54
|
+
*
|
|
55
|
+
* @param {Vector} vector - The input vector.
|
|
56
|
+
* @param {number|Vector} min - The minimum magnitude or a vector representing the lower bounds for each component.
|
|
57
|
+
* @param {number|Vector} max - The maximum magnitude or a vector representing the upper bounds for each component.
|
|
58
|
+
* @returns {Vector} The clamped vector.
|
|
55
59
|
*/
|
|
56
60
|
export function clamp(vector, min, max) {
|
|
57
61
|
const length = magnitude(vector)
|
|
@@ -75,18 +79,20 @@ export function clamp(vector, min, max) {
|
|
|
75
79
|
|
|
76
80
|
/**
|
|
77
81
|
* Returns the conjugate of the vector.
|
|
78
|
-
*
|
|
79
|
-
* @
|
|
82
|
+
*
|
|
83
|
+
* @param {Vector} vector - The input vector.
|
|
84
|
+
* @returns {Vector} The conjugated vector.
|
|
80
85
|
*/
|
|
81
86
|
export function conjugate(vector) {
|
|
82
87
|
return vector.map((coordinate, index) => (index ? -coordinate : coordinate))
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
/**
|
|
86
|
-
* Creates a vector with the given magnitude and angle.
|
|
91
|
+
* Creates a 3D vector with the given magnitude and angle.
|
|
92
|
+
*
|
|
87
93
|
* @param {number} magnitude - The magnitude of the vector.
|
|
88
94
|
* @param {number} angle - The angle of the vector in radians.
|
|
89
|
-
* @returns {Vector3} The created vector.
|
|
95
|
+
* @returns {Vector3} The created 3D vector.
|
|
90
96
|
*/
|
|
91
97
|
export function createVector(magnitude, angle) {
|
|
92
98
|
return multiply(fromAngle(angle), magnitude)
|
|
@@ -94,16 +100,28 @@ export function createVector(magnitude, angle) {
|
|
|
94
100
|
|
|
95
101
|
/**
|
|
96
102
|
* Divides each component of the vector by the given scalar.
|
|
97
|
-
*
|
|
103
|
+
*
|
|
104
|
+
* @param {Vector} vector - The input vector.
|
|
98
105
|
* @param {number} scalar - The scalar value.
|
|
99
|
-
* @returns {
|
|
106
|
+
* @returns {Vector} The resulting vector.
|
|
100
107
|
*/
|
|
101
108
|
export function divide(vector, scalar) {
|
|
102
109
|
return vector.map((coordinate) => coordinate / scalar)
|
|
103
110
|
}
|
|
104
111
|
|
|
105
112
|
/**
|
|
106
|
-
*
|
|
113
|
+
* Converts a 2D vector [x, z] into a 3D vector [x, 0, z].
|
|
114
|
+
*
|
|
115
|
+
* @param {Vector2} vector - A 2D vector represented as [x, z].
|
|
116
|
+
* @returns {Vector3} A 3D vector represented as [x, 0, z].
|
|
117
|
+
*/
|
|
118
|
+
export function from2D(vector) {
|
|
119
|
+
const [x, z] = vector
|
|
120
|
+
return [x, NO_Y, z]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a 3D unit vector from the given angle in the XZ plane.
|
|
107
125
|
* @param {number} angle - The angle in radians.
|
|
108
126
|
* @returns {Vector3} The unit vector.
|
|
109
127
|
*/
|
|
@@ -111,35 +129,42 @@ export function fromAngle(angle) {
|
|
|
111
129
|
return rotate(UNIT_VECTOR, angle)
|
|
112
130
|
}
|
|
113
131
|
|
|
114
|
-
export const length = magnitude
|
|
115
|
-
|
|
116
132
|
/**
|
|
117
133
|
* Checks if a value is a vector.
|
|
134
|
+
* A vector is an array of numbers. For performance, vectors created with `v()`
|
|
135
|
+
* are tagged and can be identified more quickly.
|
|
118
136
|
*
|
|
119
137
|
* @param {*} value - The value to check.
|
|
120
138
|
* @returns {boolean} True if the value is a vector, false otherwise.
|
|
121
139
|
*/
|
|
122
140
|
export function isVector(value) {
|
|
123
141
|
return (
|
|
124
|
-
|
|
125
|
-
|
|
142
|
+
value?.__isVector__ ||
|
|
143
|
+
(isArray(value) &&
|
|
144
|
+
value.every((coordinate) => typeof coordinate === "number"))
|
|
126
145
|
)
|
|
127
146
|
}
|
|
128
147
|
|
|
129
148
|
/**
|
|
130
|
-
* Calculates the magnitude of the vector.
|
|
131
|
-
*
|
|
149
|
+
* Calculates the magnitude (length) of the vector.
|
|
150
|
+
* Alias: `length`.
|
|
151
|
+
*
|
|
152
|
+
* @param {Vector} vector - The input vector.
|
|
132
153
|
* @returns {number} The magnitude of the vector.
|
|
133
154
|
*/
|
|
134
155
|
export function magnitude(vector) {
|
|
135
156
|
return hypothenuse(...vector)
|
|
136
157
|
}
|
|
137
158
|
|
|
159
|
+
export const length = magnitude
|
|
160
|
+
|
|
138
161
|
/**
|
|
139
162
|
* Calculates the modulus of each component in the vector with the given divisor.
|
|
140
|
-
*
|
|
163
|
+
* Alias: `remainder`.
|
|
164
|
+
*
|
|
165
|
+
* @param {Vector} vector - The input vector.
|
|
141
166
|
* @param {number} divisor - The divisor value.
|
|
142
|
-
* @returns {
|
|
167
|
+
* @returns {Vector} The resulting vector.
|
|
143
168
|
*/
|
|
144
169
|
export function mod(vector, divisor) {
|
|
145
170
|
return vector.map((coordinate) => nMod(coordinate, divisor))
|
|
@@ -147,18 +172,25 @@ export function mod(vector, divisor) {
|
|
|
147
172
|
|
|
148
173
|
/**
|
|
149
174
|
* Multiplies each component of the vector by the given scalar.
|
|
150
|
-
*
|
|
175
|
+
* Aliases: `scale`, `times`.
|
|
176
|
+
*
|
|
177
|
+
* @param {Vector} vector - The input vector.
|
|
151
178
|
* @param {number} scalar - The scalar value.
|
|
152
|
-
* @returns {
|
|
179
|
+
* @returns {Vector} The resulting vector.
|
|
153
180
|
*/
|
|
154
181
|
export function multiply(vector, scalar) {
|
|
155
182
|
return vector.map((coordinate) => coordinate * scalar)
|
|
156
183
|
}
|
|
157
184
|
|
|
185
|
+
export const scale = multiply
|
|
186
|
+
|
|
187
|
+
export const times = multiply
|
|
188
|
+
|
|
158
189
|
/**
|
|
159
190
|
* Normalizes the vector to have a magnitude of 1.
|
|
160
|
-
*
|
|
161
|
-
* @
|
|
191
|
+
*
|
|
192
|
+
* @param {Vector} vector - The input vector.
|
|
193
|
+
* @returns {Vector} The normalized vector.
|
|
162
194
|
*/
|
|
163
195
|
export function normalize(vector) {
|
|
164
196
|
const length = magnitude(vector)
|
|
@@ -168,10 +200,12 @@ export function normalize(vector) {
|
|
|
168
200
|
export const remainder = mod
|
|
169
201
|
|
|
170
202
|
/**
|
|
171
|
-
* Rotates the vector by the given angle.
|
|
172
|
-
*
|
|
203
|
+
* Rotates the vector by the given angle. Handles 2D and 3D vectors.
|
|
204
|
+
* For 3D vectors, rotation is around the Y-axis.
|
|
205
|
+
*
|
|
206
|
+
* @param {Vector} vector - The input vector (2D or 3D).
|
|
173
207
|
* @param {number} angle - The angle in radians.
|
|
174
|
-
* @returns {
|
|
208
|
+
* @returns {Vector} The rotated vector.
|
|
175
209
|
*/
|
|
176
210
|
export function rotate(vector, angle) {
|
|
177
211
|
const is2D = vector.length === TWO_COORDINATES
|
|
@@ -184,16 +218,9 @@ export function rotate(vector, angle) {
|
|
|
184
218
|
}
|
|
185
219
|
|
|
186
220
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* @param {
|
|
190
|
-
* @returns {Vector3} The resulting vector.
|
|
191
|
-
*/
|
|
192
|
-
export const scale = multiply
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Sets the angle of the vector while maintaining its magnitude.
|
|
196
|
-
* @param {Vector3} vector - The input vector.
|
|
221
|
+
* Sets the angle of the vector in the XZ plane while maintaining its magnitude.
|
|
222
|
+
*
|
|
223
|
+
* @param {Vector} vector - The input vector.
|
|
197
224
|
* @param {number} angle - The new angle in radians.
|
|
198
225
|
* @returns {Vector3} The vector with the updated angle.
|
|
199
226
|
*/
|
|
@@ -205,14 +232,17 @@ export function setAngle(vector, angle) {
|
|
|
205
232
|
|
|
206
233
|
/**
|
|
207
234
|
* Sets the length of the vector while maintaining its direction. Alias of `setMagnitude`.
|
|
235
|
+
* Alias: `setLength`.
|
|
208
236
|
*/
|
|
209
237
|
export const setLength = setMagnitude
|
|
210
238
|
|
|
211
239
|
/**
|
|
212
240
|
* Sets the magnitude of the vector while maintaining its direction.
|
|
213
|
-
*
|
|
241
|
+
* Alias: `setLength`.
|
|
242
|
+
*
|
|
243
|
+
* @param {Vector} vector - The input vector.
|
|
214
244
|
* @param {number} length - The new magnitude.
|
|
215
|
-
* @returns {
|
|
245
|
+
* @returns {Vector} The vector with the updated magnitude.
|
|
216
246
|
*/
|
|
217
247
|
export function setMagnitude(vector, length) {
|
|
218
248
|
const normalized = normalize(vector)
|
|
@@ -221,9 +251,10 @@ export function setMagnitude(vector, length) {
|
|
|
221
251
|
|
|
222
252
|
/**
|
|
223
253
|
* Shifts the components of the vector by the given index.
|
|
224
|
-
*
|
|
254
|
+
*
|
|
255
|
+
* @param {Vector} vector - The input vector.
|
|
225
256
|
* @param {number} index - The index to shift by.
|
|
226
|
-
* @returns {
|
|
257
|
+
* @returns {Vector} The shifted vector.
|
|
227
258
|
*/
|
|
228
259
|
export function shift(vector, index) {
|
|
229
260
|
return [...vector.slice(index), ...vector.slice(X, index)]
|
|
@@ -231,18 +262,29 @@ export function shift(vector, index) {
|
|
|
231
262
|
|
|
232
263
|
/**
|
|
233
264
|
* Snaps each component of the vector to the nearest multiple of the given precision.
|
|
234
|
-
*
|
|
265
|
+
*
|
|
266
|
+
* @param {Vector} vector - The input vector.
|
|
235
267
|
* @param {number} [precision=DEFAULT_PRECISION] - The precision value.
|
|
236
|
-
* @returns {
|
|
268
|
+
* @returns {Vector} The snapped vector.
|
|
237
269
|
*/
|
|
238
270
|
export function snap(vector, precision = DEFAULT_PRECISION) {
|
|
239
271
|
return vector.map((coordinate) => nSnap(coordinate, -precision, precision))
|
|
240
272
|
}
|
|
241
273
|
|
|
242
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Converts a 3D vector [x, y, z] into a 2D vector [x, z].
|
|
276
|
+
*
|
|
277
|
+
* @param {Vector3} vector - A 3D vector represented as [x, y, z].
|
|
278
|
+
* @returns {Vector2} A 2D vector represented as [x, z].
|
|
279
|
+
*/
|
|
280
|
+
export function to2D(vector) {
|
|
281
|
+
const [x, , z] = vector
|
|
282
|
+
return [x, z]
|
|
283
|
+
}
|
|
243
284
|
|
|
244
285
|
/**
|
|
245
|
-
* Converts polar coordinates to Cartesian coordinates.
|
|
286
|
+
* Converts 2D polar coordinates to 2D Cartesian coordinates.
|
|
287
|
+
*
|
|
246
288
|
* @param {Vector2} vector - The polar coordinates [magnitude, angle].
|
|
247
289
|
* @returns {Vector2} The Cartesian coordinates [x, y].
|
|
248
290
|
*/
|
|
@@ -251,9 +293,10 @@ export function toCartesian([magnitude, angle]) {
|
|
|
251
293
|
}
|
|
252
294
|
|
|
253
295
|
/**
|
|
254
|
-
* Converts a vector to cylindrical coordinates.
|
|
255
|
-
*
|
|
256
|
-
* @
|
|
296
|
+
* Converts a 3D cartesian vector to cylindrical coordinates.
|
|
297
|
+
*
|
|
298
|
+
* @param {Vector3} vector - The input vector [x, y, z].
|
|
299
|
+
* @returns {Vector3} The cylindrical coordinates [radius, theta, z].
|
|
257
300
|
*/
|
|
258
301
|
export function toCylindrical(vector) {
|
|
259
302
|
const radius = magnitude(vector)
|
|
@@ -262,8 +305,9 @@ export function toCylindrical(vector) {
|
|
|
262
305
|
}
|
|
263
306
|
|
|
264
307
|
/**
|
|
265
|
-
* Converts a vector to polar coordinates.
|
|
266
|
-
*
|
|
308
|
+
* Converts a 2D cartesian vector to 2D polar coordinates.
|
|
309
|
+
*
|
|
310
|
+
* @param {Vector2} vector - The input vector [x, y].
|
|
267
311
|
* @returns {Vector2} The polar coordinates [magnitude, angle].
|
|
268
312
|
*/
|
|
269
313
|
export function toPolar(vector) {
|
|
@@ -272,7 +316,8 @@ export function toPolar(vector) {
|
|
|
272
316
|
|
|
273
317
|
/**
|
|
274
318
|
* Converts a vector to a string representation.
|
|
275
|
-
*
|
|
319
|
+
*
|
|
320
|
+
* @param {Vector} vector - The input vector.
|
|
276
321
|
* @param {number} [decimals=DEFAULT_DECIMALS] - The number of decimal places.
|
|
277
322
|
* @returns {string} The string representation of the vector.
|
|
278
323
|
*/
|
|
@@ -309,8 +354,9 @@ export function toSpherical(vector) {
|
|
|
309
354
|
}
|
|
310
355
|
|
|
311
356
|
/**
|
|
312
|
-
* Creates a unit vector with the given angle.
|
|
313
|
-
*
|
|
357
|
+
* Creates a 3D unit vector in the XZ plane with the given angle.
|
|
358
|
+
*
|
|
359
|
+
* @param {number} [angle=0] - The angle in radians.
|
|
314
360
|
* @returns {Vector3} The unit vector.
|
|
315
361
|
*/
|
|
316
362
|
export function unit(angle) {
|
|
@@ -322,7 +368,8 @@ export function unit(angle) {
|
|
|
322
368
|
}
|
|
323
369
|
|
|
324
370
|
/**
|
|
325
|
-
* Creates a zero vector.
|
|
371
|
+
* Creates a zero vector of 3 dimensions.
|
|
372
|
+
*
|
|
326
373
|
* @returns {Vector3} The zero vector.
|
|
327
374
|
*/
|
|
328
375
|
export function zero() {
|
|
@@ -330,7 +377,8 @@ export function zero() {
|
|
|
330
377
|
}
|
|
331
378
|
|
|
332
379
|
/**
|
|
333
|
-
* Rotates
|
|
380
|
+
* Rotates a 3D vector around the Y-axis using a quaternion.
|
|
381
|
+
*
|
|
334
382
|
* @param {Vector3} vector - The input vector.
|
|
335
383
|
* @param {number} angle - The angle in radians.
|
|
336
384
|
* @returns {Vector3} The rotated vector.
|