@inglorious/utils 2.3.0 → 3.1.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 -6
- package/src/math/{geometry/line.test.js → line.test.js} +11 -10
- package/src/math/linear-interpolation.js +0 -1
- 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} +4 -4
- package/src/math/{linear-algebra/quaternion.test.js → quaternion.test.js} +1 -1
- package/src/math/{linear-algebra/quaternions.js → quaternions.js} +7 -4
- package/src/math/{linear-algebra/quaternions.test.js → quaternions.test.js} +1 -1
- package/src/math/{geometry/rectangle.js → rectangle.js} +3 -5
- package/src/math/{geometry/rectangle.test.js → rectangle.test.js} +13 -12
- package/src/math/rng.js +0 -2
- package/src/math/{geometry/segment.js → segment.js} +5 -9
- package/src/math/{geometry/segment.test.js → segment.test.js} +48 -47
- package/src/math/{geometry/triangle.js → triangle.js} +1 -1
- package/src/math/{geometry/types.d.ts → types.d.ts} +10 -0
- package/src/math/{linear-algebra/vector.js → vector.js} +73 -80
- package/src/math/{linear-algebra/vector.test.js → vector.test.js} +73 -63
- package/src/math/{linear-algebra/vectors.js → vectors.js} +18 -13
- package/src/math/{linear-algebra/vectors.test.js → vectors.test.js} +12 -30
- package/src/physics/acceleration.js +5 -5
- package/src/physics/friction.js +2 -3
- 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 -2
- package/src/physics/velocity.js +3 -4
- package/src/v.js +17 -0
- package/src/v.test.js +13 -0
- package/src/math/linear-algebra/types.d.ts +0 -5
- /package/src/math/{geometry/hitmask.js → hitmask.js} +0 -0
- /package/src/math/{geometry/triangle.test.js → triangle.test.js} +0 -0
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ const result = calculate(10) // 40
|
|
|
43
43
|
Perform vector operations on plain objects.
|
|
44
44
|
|
|
45
45
|
```javascript
|
|
46
|
-
import { add } from "@inglorious/utils/math/
|
|
46
|
+
import { add } from "@inglorious/utils/math/vector.js"
|
|
47
47
|
|
|
48
48
|
const position = [10, 20]
|
|
49
49
|
const velocity = [2, -1]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A set of general-purpose utility functions designed with functional programming principles in mind.",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import { length } from "../math/
|
|
4
|
-
import { subtract } from "../math/
|
|
3
|
+
import { length } from "../math/vector.js"
|
|
4
|
+
import { subtract } from "../math/vectors.js"
|
|
5
|
+
import { v } from "../v.js"
|
|
5
6
|
import { decide } from "./decision-tree.js"
|
|
6
7
|
|
|
7
8
|
test("it should make a decision based on a binary decision tree", () => {
|
|
8
|
-
const entity = { state: "sleeping", position:
|
|
9
|
-
const target = { position:
|
|
9
|
+
const entity = { state: "sleeping", position: v(0, 0, 0) }
|
|
10
|
+
const target = { position: v(10, 0, 0) }
|
|
10
11
|
const tree = {
|
|
11
12
|
test({ entity }) {
|
|
12
13
|
return entity.state === "idle"
|
|
@@ -83,8 +84,8 @@ test("it should make a decision based on a binary decision tree", () => {
|
|
|
83
84
|
})
|
|
84
85
|
|
|
85
86
|
test("it should make a decision on a multi-child tree", () => {
|
|
86
|
-
const entity = { state: "sleeping", position:
|
|
87
|
-
const target = { position:
|
|
87
|
+
const entity = { state: "sleeping", position: v(0, 0, 0) }
|
|
88
|
+
const target = { position: v(10, 0, 0) }
|
|
88
89
|
const wakeUp = () => ({
|
|
89
90
|
test({ entity, target }) {
|
|
90
91
|
const distance = length(subtract(target.position, entity.position))
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { contains, push, remove, root } from "../data-structures/heap.js"
|
|
7
|
-
import { abs, magnitude } from "../math/
|
|
8
|
-
import { subtract } from "../math/
|
|
7
|
+
import { abs, magnitude } from "../math/vector.js"
|
|
8
|
+
import { subtract } from "../math/vectors.js"
|
|
9
9
|
|
|
10
10
|
const NO_COST = 0
|
|
11
11
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as array from "./array.js"
|
|
2
|
+
import * as board from "./board.js"
|
|
3
|
+
import * as boolean from "./boolean.js"
|
|
4
|
+
import * as heap from "./heap.js"
|
|
5
|
+
import * as object from "./object.js"
|
|
6
|
+
import * as objects from "./objects.js"
|
|
7
|
+
import * as set from "./set.js"
|
|
8
|
+
import * as tree from "./tree.js"
|
|
9
|
+
|
|
10
|
+
export { array, board, boolean, heap, object, objects, set, tree }
|
package/src/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as algorithms from "./algorithms/index.js"
|
|
2
|
+
import * as dataStructures from "./data-structures/index.js"
|
|
3
|
+
import * as functions from "./functions/index.js"
|
|
4
|
+
import * as math from "./math/index.js"
|
|
5
|
+
import * as physics from "./physics/index.js"
|
|
6
|
+
|
|
7
|
+
export { algorithms, dataStructures, functions, math, physics }
|
|
8
|
+
export { v } from "./v.js"
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("./types").Point} Point
|
|
3
|
-
* @typedef {import("./types").Circle} Circle
|
|
4
|
-
* @typedef {import("./types").Rectangle} Rectangle
|
|
5
|
-
* @typedef {import("./types").Platform} Platform
|
|
2
|
+
* @typedef {import("./geometry/types.js").Point} Point
|
|
3
|
+
* @typedef {import("./geometry/types.js").Circle} Circle
|
|
4
|
+
* @typedef {import("./geometry/types.js").Rectangle} Rectangle
|
|
5
|
+
* @typedef {import("./geometry/types.js").Platform} Platform
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { clamp } from "../linear-algebra/vector.js"
|
|
9
|
-
import { subtract } from "../linear-algebra/vectors.js"
|
|
10
8
|
import { intersectsCircle as pointIntersectsCircle } from "./point.js"
|
|
11
9
|
import { hypothenuse } from "./triangle.js"
|
|
10
|
+
import { clamp } from "./vector.js"
|
|
11
|
+
import { subtract } from "./vectors.js"
|
|
12
12
|
|
|
13
13
|
const HALF = 2
|
|
14
14
|
const SQUARED = 2
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
+
import { v } from "../v.js"
|
|
3
4
|
import {
|
|
4
5
|
intersectsCircle,
|
|
5
6
|
intersectsPoint,
|
|
@@ -8,50 +9,50 @@ import {
|
|
|
8
9
|
|
|
9
10
|
test("it should prove that a circle around a point intersects with it", () => {
|
|
10
11
|
const circle = {
|
|
11
|
-
position:
|
|
12
|
+
position: v(1, 1, 0),
|
|
12
13
|
radius: 1,
|
|
13
14
|
}
|
|
14
|
-
const point =
|
|
15
|
+
const point = v(1.5, 1.5, 0)
|
|
15
16
|
|
|
16
17
|
expect(intersectsPoint(circle, point)).toBe(true)
|
|
17
18
|
})
|
|
18
19
|
|
|
19
20
|
test("it should prove that two equal circles intersect", () => {
|
|
20
|
-
const circle1 = { position:
|
|
21
|
-
const circle2 = { position:
|
|
21
|
+
const circle1 = { position: v(1, 1, 0), radius: 1 }
|
|
22
|
+
const circle2 = { position: v(1, 1, 0), radius: 1 }
|
|
22
23
|
|
|
23
24
|
expect(intersectsCircle(circle1, circle2)).toBe(true)
|
|
24
25
|
})
|
|
25
26
|
|
|
26
27
|
test("it should prove that two circles shifted by a small x intersect", () => {
|
|
27
|
-
const circle1 = { position:
|
|
28
|
-
const circle2 = { position:
|
|
28
|
+
const circle1 = { position: v(1, 1, 0), radius: 1 }
|
|
29
|
+
const circle2 = { position: v(2, 1, 0), radius: 1 }
|
|
29
30
|
|
|
30
31
|
expect(intersectsCircle(circle1, circle2)).toBe(true)
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
test("it should prove that two touching circles intersect", () => {
|
|
34
|
-
const circle1 = { position:
|
|
35
|
-
const circle2 = { position:
|
|
35
|
+
const circle1 = { position: v(1, 1, 0), radius: 1 }
|
|
36
|
+
const circle2 = { position: v(3, 1, 0), radius: 1 }
|
|
36
37
|
|
|
37
38
|
expect(intersectsCircle(circle1, circle2)).toBe(true)
|
|
38
39
|
})
|
|
39
40
|
|
|
40
41
|
test("it should prove that two non-touching circles do not intersect", () => {
|
|
41
|
-
const circle1 = { position:
|
|
42
|
-
const circle2 = { position:
|
|
42
|
+
const circle1 = { position: v(1, 1, 0), radius: 1 }
|
|
43
|
+
const circle2 = { position: v(4, 1, 0), radius: 1 }
|
|
43
44
|
|
|
44
45
|
expect(intersectsCircle(circle1, circle2)).toBe(false)
|
|
45
46
|
})
|
|
46
47
|
|
|
47
48
|
test("it should prove that a circle inside of a rectangle intersects with it", () => {
|
|
48
49
|
const circle = {
|
|
49
|
-
position:
|
|
50
|
+
position: v(1, 1, 0),
|
|
50
51
|
radius: 1,
|
|
51
52
|
}
|
|
52
53
|
const rectangle = {
|
|
53
|
-
position:
|
|
54
|
-
size:
|
|
54
|
+
position: v(-1, -1, 0),
|
|
55
|
+
size: v(4, 4, 0),
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
expect(intersectsRectangle(circle, rectangle)).toBe(true)
|
|
@@ -59,12 +60,12 @@ test("it should prove that a circle inside of a rectangle intersects with it", (
|
|
|
59
60
|
|
|
60
61
|
test("it should prove that a circle touching the border of a rectangle intersects with it", () => {
|
|
61
62
|
const circle = {
|
|
62
|
-
position:
|
|
63
|
+
position: v(1, 1, 0),
|
|
63
64
|
radius: 1,
|
|
64
65
|
}
|
|
65
66
|
const rectangle = {
|
|
66
|
-
position:
|
|
67
|
-
size:
|
|
67
|
+
position: v(-1, 1, 0), // Rectangle's right edge is at x=0, touching the circle's left edge.
|
|
68
|
+
size: v(2, 2, 0),
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
expect(intersectsRectangle(circle, rectangle)).toBe(true)
|
|
@@ -72,12 +73,12 @@ test("it should prove that a circle touching the border of a rectangle intersect
|
|
|
72
73
|
|
|
73
74
|
test("it should prove that a circle crossing a rectangle intersects with it", () => {
|
|
74
75
|
const circle = {
|
|
75
|
-
position:
|
|
76
|
+
position: v(1, 1, 0),
|
|
76
77
|
radius: 1,
|
|
77
78
|
}
|
|
78
79
|
const rectangle = {
|
|
79
|
-
position:
|
|
80
|
-
size:
|
|
80
|
+
position: v(0, 0, 0),
|
|
81
|
+
size: v(2, 2, 0),
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
expect(intersectsRectangle(circle, rectangle)).toBe(true)
|
|
@@ -85,12 +86,12 @@ test("it should prove that a circle crossing a rectangle intersects with it", ()
|
|
|
85
86
|
|
|
86
87
|
test("it should prove that a circle outside of a rectangle does not intersect with it", () => {
|
|
87
88
|
const circle = {
|
|
88
|
-
position:
|
|
89
|
+
position: v(1, 1, 0),
|
|
89
90
|
radius: 1,
|
|
90
91
|
}
|
|
91
92
|
const rectangle = {
|
|
92
|
-
position:
|
|
93
|
-
size:
|
|
93
|
+
position: v(-3, 0, 0),
|
|
94
|
+
size: v(2, 2, 0),
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
expect(intersectsRectangle(circle, rectangle)).toBe(false)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { v } from "../v.js"
|
|
4
|
+
import { findCollisions } from "./hitmask.js"
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Given a rectangle located at (x=1.5, y=0, z=2.5) with a size of (1, 1, 1),
|
|
@@ -17,7 +18,7 @@ import { findCollisions } from "./hitmask"
|
|
|
17
18
|
*/
|
|
18
19
|
test("it should prove that a rectangle touching a wall intersects with it", () => {
|
|
19
20
|
const hitmask = {
|
|
20
|
-
position:
|
|
21
|
+
position: v(2, 0, 1.5),
|
|
21
22
|
tileSize: [1, 1],
|
|
22
23
|
columns: 4,
|
|
23
24
|
// The top row (indices 0, 1, 2, 3) now has the walls.
|
|
@@ -25,8 +26,8 @@ test("it should prove that a rectangle touching a wall intersects with it", () =
|
|
|
25
26
|
}
|
|
26
27
|
const rectangle = {
|
|
27
28
|
shape: "rectangle",
|
|
28
|
-
position:
|
|
29
|
-
size:
|
|
29
|
+
position: v(1.5, 0, 2.5),
|
|
30
|
+
size: v(1, 1, 1),
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
expect(findCollisions(hitmask, rectangle)).toBe(true)
|
|
@@ -57,8 +58,8 @@ test("it should prove that shifting operands does not change the outcome", () =>
|
|
|
57
58
|
}
|
|
58
59
|
const rectangle = {
|
|
59
60
|
shape: "rectangle",
|
|
60
|
-
position:
|
|
61
|
-
size:
|
|
61
|
+
position: v(11.5, 0, 12.5),
|
|
62
|
+
size: v(1, 1, 1),
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
expect(findCollisions(hitmask, rectangle)).toBe(true)
|
|
@@ -79,7 +80,7 @@ test("it should prove that shifting operands does not change the outcome", () =>
|
|
|
79
80
|
*/
|
|
80
81
|
test("it should prove that a rectangle not touching a wall does not intersect with it", () => {
|
|
81
82
|
const hitmask = {
|
|
82
|
-
position:
|
|
83
|
+
position: v(2, 0, 1.5),
|
|
83
84
|
tileSize: [1, 1],
|
|
84
85
|
columns: 4,
|
|
85
86
|
// The top row (indices 0, 1, 2, 3) now has the walls.
|
|
@@ -87,8 +88,8 @@ test("it should prove that a rectangle not touching a wall does not intersect wi
|
|
|
87
88
|
}
|
|
88
89
|
const rectangle = {
|
|
89
90
|
shape: "rectangle",
|
|
90
|
-
position:
|
|
91
|
-
size:
|
|
91
|
+
position: v(0.5, 0, 0.5),
|
|
92
|
+
size: v(1, 1, 1),
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
expect(findCollisions(hitmask, rectangle)).toBe(false)
|
|
@@ -109,7 +110,7 @@ test("it should prove that a rectangle not touching a wall does not intersect wi
|
|
|
109
110
|
*/
|
|
110
111
|
test("it should prove that a rectangle above the tile of a hitmask does not intersect with it", () => {
|
|
111
112
|
const hitmask = {
|
|
112
|
-
position:
|
|
113
|
+
position: v(2, 0, 1.5),
|
|
113
114
|
tileSize: [1, 1],
|
|
114
115
|
columns: 4,
|
|
115
116
|
// The top row (indices 0, 1, 2, 3) now has the walls.
|
|
@@ -117,8 +118,8 @@ test("it should prove that a rectangle above the tile of a hitmask does not inte
|
|
|
117
118
|
}
|
|
118
119
|
const rectangle = {
|
|
119
120
|
shape: "rectangle",
|
|
120
|
-
position:
|
|
121
|
-
size:
|
|
121
|
+
position: v(1.5, 1.6, 2.5),
|
|
122
|
+
size: v(1, 1, 1),
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
expect(findCollisions(hitmask, rectangle)).toBe(false)
|
|
@@ -139,7 +140,7 @@ test("it should prove that a rectangle above the tile of a hitmask does not inte
|
|
|
139
140
|
*/
|
|
140
141
|
test("it should prove that a rectangle outside of a hitmask does not intersect with it", () => {
|
|
141
142
|
const hitmask = {
|
|
142
|
-
position:
|
|
143
|
+
position: v(2, 0, 1.5),
|
|
143
144
|
tileSize: [1, 1],
|
|
144
145
|
columns: 4,
|
|
145
146
|
// The top row (indices 0, 1, 2, 3) now has the walls.
|
|
@@ -147,8 +148,8 @@ test("it should prove that a rectangle outside of a hitmask does not intersect w
|
|
|
147
148
|
}
|
|
148
149
|
const rectangle = {
|
|
149
150
|
shape: "rectangle",
|
|
150
|
-
position:
|
|
151
|
-
size:
|
|
151
|
+
position: v(5.5, 0.5, 1.5),
|
|
152
|
+
size: v(1, 1, 1),
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
expect(findCollisions(hitmask, rectangle)).toBe(false)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as circle from "./circle.js"
|
|
2
|
+
import * as hitmask from "./hitmask.js"
|
|
3
|
+
import * as line from "./line.js"
|
|
4
|
+
import * as linearInterpolation from "./linear-interpolation.js"
|
|
5
|
+
import * as numbers from "./numbers.js"
|
|
6
|
+
import * as point from "./point.js"
|
|
7
|
+
import * as quaternion from "./quaternion.js"
|
|
8
|
+
import * as quaternions from "./quaternions.js"
|
|
9
|
+
import * as rectangle from "./rectangle.js"
|
|
10
|
+
import * as rng from "./rng.js"
|
|
11
|
+
import * as segment from "./segment.js"
|
|
12
|
+
import * as statistics from "./statistics.js"
|
|
13
|
+
import * as triangle from "./triangle.js"
|
|
14
|
+
import * as trigonometry from "./trigonometry.js"
|
|
15
|
+
import * as vector from "./vector.js"
|
|
16
|
+
import * as vectors from "./vectors.js"
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
circle,
|
|
20
|
+
hitmask,
|
|
21
|
+
line,
|
|
22
|
+
linearInterpolation,
|
|
23
|
+
numbers,
|
|
24
|
+
point,
|
|
25
|
+
quaternion,
|
|
26
|
+
quaternions,
|
|
27
|
+
rectangle,
|
|
28
|
+
rng,
|
|
29
|
+
segment,
|
|
30
|
+
statistics,
|
|
31
|
+
triangle,
|
|
32
|
+
trigonometry,
|
|
33
|
+
vector,
|
|
34
|
+
vectors,
|
|
35
|
+
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("./types").Line} Line
|
|
3
|
-
* @typedef {import("./types").Point} Point
|
|
4
|
-
* @typedef {import("./types").Circle} Circle
|
|
2
|
+
* @typedef {import("./geometry/types.js").Line} Line
|
|
3
|
+
* @typedef {import("./geometry/types.js").Point} Point
|
|
4
|
+
* @typedef {import("./geometry/types.js").Circle} Circle
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { abs } from "
|
|
7
|
+
import { abs } from "./numbers.js"
|
|
8
8
|
import { hypothenuse } from "./triangle.js"
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Calculates the shortest distance from a point to a line in 2D space.
|
|
12
|
-
*
|
|
13
12
|
* @param {Line} line - The line represented by the equation ax + bz + c = 0, where `line` is [a, b, c].
|
|
14
13
|
* @param {Point} point - The point in 3D space represented as [x, y, z].
|
|
15
14
|
* @returns {number} The shortest distance from the point to the line.
|
|
@@ -24,7 +23,6 @@ export function distanceFromPoint(line, point) {
|
|
|
24
23
|
// @see https://math.stackexchange.com/questions/275529/check-if-line-intersects-with-circles-perimeter
|
|
25
24
|
/**
|
|
26
25
|
* Determines whether a line intersects with the perimeter of a circle.
|
|
27
|
-
*
|
|
28
26
|
* @param {Line} line - The line represented by the equation ax + bz + c = 0, where `line` is [a, b, c].
|
|
29
27
|
* @param {Circle} circle - The circle defined by its position (center) and radius.
|
|
30
28
|
* @returns {boolean} `true` if the line intersects the circle's perimeter, otherwise `false`.
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
+
import { v } from "../v.js"
|
|
3
4
|
import { distanceFromPoint, intersectsCircle } from "./line.js"
|
|
4
5
|
|
|
5
6
|
test("it should compute the distance between a line and a point", () => {
|
|
6
|
-
const line =
|
|
7
|
-
const point =
|
|
7
|
+
const line = v(-4, 3, 0)
|
|
8
|
+
const point = v(5, 0, 0)
|
|
8
9
|
const expectedResult = 4
|
|
9
10
|
|
|
10
11
|
expect(distanceFromPoint(line, point)).toBe(expectedResult)
|
|
11
12
|
})
|
|
12
13
|
|
|
13
14
|
test("it should not compute the distance between a line and a point", () => {
|
|
14
|
-
const line =
|
|
15
|
-
const point =
|
|
15
|
+
const line = v(-1, 1, 0)
|
|
16
|
+
const point = v(2, 0, 2)
|
|
16
17
|
const expectedResult = 0
|
|
17
18
|
|
|
18
19
|
expect(distanceFromPoint(line, point)).toBe(expectedResult)
|
|
19
20
|
})
|
|
20
21
|
|
|
21
22
|
test("it should prove that a line that crosses a circle intersects with it", () => {
|
|
22
|
-
const line =
|
|
23
|
+
const line = v(-2, 2, 0)
|
|
23
24
|
const circle = {
|
|
24
|
-
position:
|
|
25
|
+
position: v(1, 1, 0),
|
|
25
26
|
radius: 1,
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -29,9 +30,9 @@ test("it should prove that a line that crosses a circle intersects with it", ()
|
|
|
29
30
|
})
|
|
30
31
|
|
|
31
32
|
test("it should prove that a line tangent to a circle intersects with it", () => {
|
|
32
|
-
const line =
|
|
33
|
+
const line = v(-2, 0, 0)
|
|
33
34
|
const circle = {
|
|
34
|
-
position:
|
|
35
|
+
position: v(1, 0, 1),
|
|
35
36
|
radius: 1,
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -39,9 +40,9 @@ test("it should prove that a line tangent to a circle intersects with it", () =>
|
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
test("it should prove that a line that does not cross a circle does not intersect with it", () => {
|
|
42
|
-
const line =
|
|
43
|
+
const line = v(1, 1, 0)
|
|
43
44
|
const circle = {
|
|
44
|
-
position:
|
|
45
|
+
position: v(1, 0, 1),
|
|
45
46
|
radius: 1,
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @typedef {import("./types").Point} Point
|
|
3
|
-
* @typedef {import("./types").Line} Line
|
|
4
|
-
* @typedef {import("./types").Circle} Circle
|
|
5
|
-
* @typedef {import("./types").Rectangle} Rectangle
|
|
2
|
+
* @typedef {import("./geometry/types.js").Point} Point
|
|
3
|
+
* @typedef {import("./geometry/types.js").Line} Line
|
|
4
|
+
* @typedef {import("./geometry/types.js").Circle} Circle
|
|
5
|
+
* @typedef {import("./geometry/types.js").Rectangle} Rectangle
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const SQUARED = 2
|
|
9
9
|
const HALF = 2
|
|
10
10
|
|
|
11
|
-
import { isVector } from "../linear-algebra/vector.js"
|
|
12
11
|
import { distanceFromPoint } from "./line.js"
|
|
12
|
+
import { isVector } from "./vector.js"
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Calculates the distance from a point to a line.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
+
import { v } from "../v.js"
|
|
3
4
|
import {
|
|
4
5
|
intersectsCircle,
|
|
5
6
|
intersectsPoint,
|
|
@@ -7,23 +8,23 @@ import {
|
|
|
7
8
|
} from "./point.js"
|
|
8
9
|
|
|
9
10
|
test("it should prove that two equal points intersect", () => {
|
|
10
|
-
const point1 =
|
|
11
|
-
const point2 =
|
|
11
|
+
const point1 = v(1.5, 1.5, 0)
|
|
12
|
+
const point2 = v(1.5, 1.5, 0)
|
|
12
13
|
|
|
13
14
|
expect(intersectsPoint(point1, point2)).toBe(true)
|
|
14
15
|
})
|
|
15
16
|
|
|
16
17
|
test("it should prove that two different points do not intersect", () => {
|
|
17
|
-
const point1 =
|
|
18
|
-
const point2 =
|
|
18
|
+
const point1 = v(1.5, 1.5, 0)
|
|
19
|
+
const point2 = v(2, 1, 0)
|
|
19
20
|
|
|
20
21
|
expect(intersectsPoint(point1, point2)).toBe(false)
|
|
21
22
|
})
|
|
22
23
|
|
|
23
24
|
test("it should prove that a point inside of a circle intersects with it", () => {
|
|
24
|
-
const point =
|
|
25
|
+
const point = v(1.5, 1.5, 0)
|
|
25
26
|
const circle = {
|
|
26
|
-
position:
|
|
27
|
+
position: v(1, 1, 0),
|
|
27
28
|
radius: 1,
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -31,9 +32,9 @@ test("it should prove that a point inside of a circle intersects with it", () =>
|
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
test("it should prove that a point on the border of a circle intersects with it", () => {
|
|
34
|
-
const point =
|
|
35
|
+
const point = v(2, 1, 0)
|
|
35
36
|
const circle = {
|
|
36
|
-
position:
|
|
37
|
+
position: v(1, 1, 0),
|
|
37
38
|
radius: 1,
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -41,9 +42,9 @@ test("it should prove that a point on the border of a circle intersects with it"
|
|
|
41
42
|
})
|
|
42
43
|
|
|
43
44
|
test("it should prove that a point outside of a circle does not intersect with it", () => {
|
|
44
|
-
const point =
|
|
45
|
+
const point = v(2, 2, 0)
|
|
45
46
|
const circle = {
|
|
46
|
-
position:
|
|
47
|
+
position: v(1, 1, 0),
|
|
47
48
|
radius: 1,
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -51,30 +52,30 @@ test("it should prove that a point outside of a circle does not intersect with i
|
|
|
51
52
|
})
|
|
52
53
|
|
|
53
54
|
test("it should prove that a point inside of a rectangle intersects with it", () => {
|
|
54
|
-
const point =
|
|
55
|
+
const point = v(1.5, 1.5, 0)
|
|
55
56
|
const rectangle = {
|
|
56
|
-
position:
|
|
57
|
-
size:
|
|
57
|
+
position: v(1, 1, 0),
|
|
58
|
+
size: v(2, 2, 0),
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
expect(intersectsRectangle(point, rectangle)).toBe(true)
|
|
61
62
|
})
|
|
62
63
|
|
|
63
64
|
test("it should prove that a point on the border of a rectangle intersects with it", () => {
|
|
64
|
-
const point =
|
|
65
|
+
const point = v(2, 1, 0)
|
|
65
66
|
const rectangle = {
|
|
66
|
-
position:
|
|
67
|
-
size:
|
|
67
|
+
position: v(1, 1, 0),
|
|
68
|
+
size: v(2, 2, 0),
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
expect(intersectsRectangle(point, rectangle)).toBe(true)
|
|
71
72
|
})
|
|
72
73
|
|
|
73
74
|
test("it should prove that a point outside of a rectangle does not intersect with it", () => {
|
|
74
|
-
const point =
|
|
75
|
+
const point = v(2.5, 2.5, 0)
|
|
75
76
|
const rectangle = {
|
|
76
|
-
position:
|
|
77
|
-
size:
|
|
77
|
+
position: v(1, 1, 0),
|
|
78
|
+
size: v(2, 2, 0),
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
expect(intersectsRectangle(point, rectangle)).toBe(false)
|
|
@@ -82,11 +83,11 @@ test("it should prove that a point outside of a rectangle does not intersect wit
|
|
|
82
83
|
|
|
83
84
|
test("it should work even if the point is an object with a position", () => {
|
|
84
85
|
const point = {
|
|
85
|
-
position:
|
|
86
|
+
position: v(1.5, 1.5, 0),
|
|
86
87
|
}
|
|
87
88
|
const rectangle = {
|
|
88
|
-
position:
|
|
89
|
-
size:
|
|
89
|
+
position: v(1, 1, 0),
|
|
90
|
+
size: v(2, 2, 0),
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
expect(intersectsRectangle(point, rectangle)).toBe(true)
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
* @typedef {import('../../../types').Quaternion} Quaternion
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { v } from "../v.js"
|
|
7
|
+
import { cos, sin } from "./trigonometry.js"
|
|
7
8
|
|
|
8
9
|
const DEFAULT_ANGLE = 0
|
|
9
10
|
const HALF = 2 // Constant representing the divisor for halving an angle.
|
|
10
11
|
// eslint-disable-next-line no-magic-numbers
|
|
11
|
-
const Y_AXIS =
|
|
12
|
+
const Y_AXIS = v(0, 1, 0) // Default axis of rotation (Y-axis).
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Computes a quaternion representing a rotation around a given axis.
|
|
15
|
-
*
|
|
16
16
|
* @param {number} [angle=0] - The angle of rotation in radians. Defaults to 0.
|
|
17
17
|
* @param {Vector3} [axis=Y_AXIS] - The axis of rotation as a 3D vector Defaults to the Y-axis.
|
|
18
18
|
* @returns {Quaternion} The quaternion as an array [w, x, y, z].
|
|
19
19
|
*/
|
|
20
20
|
export function quaternion(angle = DEFAULT_ANGLE, axis = Y_AXIS) {
|
|
21
|
-
return
|
|
21
|
+
return v(cos(angle / HALF), ...axis.map((coord) => coord * sin(angle / HALF)))
|
|
22
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import { cos, pi, sin } from "../trigonometry.js"
|
|
4
3
|
import { quaternion } from "./quaternion.js"
|
|
4
|
+
import { cos, pi, sin } from "./trigonometry.js"
|
|
5
5
|
|
|
6
6
|
test("it should return the quaternion for no rotation", () => {
|
|
7
7
|
const angle = 0
|
|
@@ -2,19 +2,22 @@
|
|
|
2
2
|
* @typedef {import('./types').Quaternion} Quaternion
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { v } from "../v.js"
|
|
5
6
|
import { times } from "./vector.js"
|
|
6
7
|
import { cross, dot, sum } from "./vectors.js"
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Combines two quaternions using the Hamilton product.
|
|
10
|
-
*
|
|
11
11
|
* @param {Quaternion} q1 - The first quaternion.
|
|
12
12
|
* @param {Quaternion} q2 - The second quaternion.
|
|
13
13
|
* @returns {Quaternion} - The resulting quaternion after combining q1 and q2.
|
|
14
14
|
*/
|
|
15
15
|
export function combine(q1, q2) {
|
|
16
|
-
const [
|
|
17
|
-
const [
|
|
16
|
+
const [s1, ...v1] = q1
|
|
17
|
+
const [s2, ...v2] = q2
|
|
18
18
|
|
|
19
|
-
return
|
|
19
|
+
return v(
|
|
20
|
+
s1 * s2 - dot(v1, v2),
|
|
21
|
+
...sum(times(v2, s1), times(v1, s2), cross(v1, v2)),
|
|
22
|
+
)
|
|
20
23
|
}
|