@benev/math 0.2.0-0 → 0.2.0-2

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.
Files changed (90) hide show
  1. package/README.md +110 -23
  2. package/package.json +5 -4
  3. package/s/{primitives → core}/quat.ts +56 -16
  4. package/s/{primitives → core}/vec2.ts +52 -38
  5. package/s/{primitives → core}/vec3.ts +73 -47
  6. package/s/{primitives → core}/vec4.ts +13 -16
  7. package/s/index.ts +11 -12
  8. package/s/optimizers/hash-map.ts +4 -0
  9. package/s/optimizers/hash-set.ts +4 -0
  10. package/s/optimizers/zen.ts +27 -26
  11. package/s/physics/2d/collide2d.ts +2 -2
  12. package/s/physics/2d/intersect2d.ts +9 -6
  13. package/s/shapes/2d/circle.ts +25 -7
  14. package/s/shapes/2d/rect.ts +48 -19
  15. package/s/shapes/3d/box.ts +65 -20
  16. package/s/shapes/3d/segment.ts +12 -10
  17. package/s/{utils → tools}/angles.ts +7 -1
  18. package/s/{primitives → tools}/circular.ts +5 -3
  19. package/s/{primitives → tools}/scalar.ts +11 -11
  20. package/s/{utils → tools}/spline.ts +12 -11
  21. package/x/{primitives → core}/quat.d.ts +10 -5
  22. package/x/{primitives → core}/quat.js +49 -12
  23. package/x/core/quat.js.map +1 -0
  24. package/x/{primitives → core}/vec2.d.ts +16 -17
  25. package/x/{primitives → core}/vec2.js +38 -22
  26. package/x/core/vec2.js.map +1 -0
  27. package/x/{primitives → core}/vec3.d.ts +23 -20
  28. package/x/{primitives → core}/vec3.js +60 -27
  29. package/x/core/vec3.js.map +1 -0
  30. package/x/{primitives → core}/vec4.d.ts +5 -7
  31. package/x/{primitives → core}/vec4.js +12 -12
  32. package/x/core/vec4.js.map +1 -0
  33. package/x/index.d.ts +10 -10
  34. package/x/index.js +10 -10
  35. package/x/index.js.map +1 -1
  36. package/x/optimizers/hash-map.d.ts +1 -0
  37. package/x/optimizers/hash-map.js +3 -0
  38. package/x/optimizers/hash-map.js.map +1 -1
  39. package/x/optimizers/hash-set.d.ts +1 -0
  40. package/x/optimizers/hash-set.js +3 -0
  41. package/x/optimizers/hash-set.js.map +1 -1
  42. package/x/optimizers/zen.d.ts +14 -13
  43. package/x/optimizers/zen.js +29 -28
  44. package/x/optimizers/zen.js.map +1 -1
  45. package/x/physics/2d/collide2d.d.ts +1 -1
  46. package/x/physics/2d/collide2d.js +2 -2
  47. package/x/physics/2d/collide2d.js.map +1 -1
  48. package/x/physics/2d/intersect2d.d.ts +1 -1
  49. package/x/physics/2d/intersect2d.js +7 -5
  50. package/x/physics/2d/intersect2d.js.map +1 -1
  51. package/x/shapes/2d/circle.d.ts +11 -3
  52. package/x/shapes/2d/circle.js +19 -7
  53. package/x/shapes/2d/circle.js.map +1 -1
  54. package/x/shapes/2d/rect.d.ts +20 -10
  55. package/x/shapes/2d/rect.js +47 -24
  56. package/x/shapes/2d/rect.js.map +1 -1
  57. package/x/shapes/3d/box.d.ts +21 -8
  58. package/x/shapes/3d/box.js +56 -17
  59. package/x/shapes/3d/box.js.map +1 -1
  60. package/x/shapes/3d/segment.d.ts +5 -5
  61. package/x/shapes/3d/segment.js +11 -9
  62. package/x/shapes/3d/segment.js.map +1 -1
  63. package/x/{utils → tools}/angles.d.ts +2 -0
  64. package/x/{utils → tools}/angles.js +7 -1
  65. package/x/tools/angles.js.map +1 -0
  66. package/x/{primitives → tools}/circular.js +4 -3
  67. package/x/tools/circular.js.map +1 -0
  68. package/x/{utils → tools}/noise.js.map +1 -1
  69. package/x/{utils → tools}/randy.js.map +1 -1
  70. package/x/{primitives → tools}/scalar.d.ts +4 -4
  71. package/x/{primitives → tools}/scalar.js +11 -11
  72. package/x/tools/scalar.js.map +1 -0
  73. package/x/{utils → tools}/spline.d.ts +3 -3
  74. package/x/{utils → tools}/spline.js +4 -2
  75. package/x/tools/spline.js.map +1 -0
  76. package/x/primitives/circular.js.map +0 -1
  77. package/x/primitives/quat.js.map +0 -1
  78. package/x/primitives/scalar.js.map +0 -1
  79. package/x/primitives/vec2.js.map +0 -1
  80. package/x/primitives/vec3.js.map +0 -1
  81. package/x/primitives/vec4.js.map +0 -1
  82. package/x/utils/angles.js.map +0 -1
  83. package/x/utils/spline.js.map +0 -1
  84. /package/s/{utils → tools}/noise.ts +0 -0
  85. /package/s/{utils → tools}/randy.ts +0 -0
  86. /package/x/{primitives → tools}/circular.d.ts +0 -0
  87. /package/x/{utils → tools}/noise.d.ts +0 -0
  88. /package/x/{utils → tools}/noise.js +0 -0
  89. /package/x/{utils → tools}/randy.d.ts +0 -0
  90. /package/x/{utils → tools}/randy.js +0 -0
package/README.md CHANGED
@@ -1,26 +1,113 @@
1
1
 
2
2
  # @benev/math
3
- > benevolent's game math library.
4
-
5
- ***TODO*** actual documentation coming soon.
6
-
7
- ### numeric primitives
8
- - [Scalar](./s/concepts/scalar.ts)
9
- - [Vec2](./s/concepts/vec2.ts)
10
- - [Vec3](./s/concepts/vec3.ts)
11
- - [Vec4](./s/concepts/vec4.ts)
12
- - [Quat](./s/concepts/quat.ts)
13
-
14
- ### cool utilities
15
- - [Randy](./s/concepts/randy.ts)
16
- - [Circular](./s/concepts/circular.ts)
17
- - [Noise](./s/concepts/noise.ts)
18
- - [spline](./s/concepts/spline.ts)
19
-
20
- ### angular stuff
21
- - [angles.ts](./s/concepts/angles.ts)
22
- - Radians
23
- - Arcseconds
24
- - Turns
25
- - Degrees
3
+ > benevolent's typescript math library for games
4
+
5
+ <br/>
6
+
7
+ ## 🍋 CORE
8
+ > common numerical structures
9
+
10
+ > [!TIP]
11
+ > until real docs are written, see the relevant sourcecode in [s/core/](./s/core/)
12
+
13
+ ### 🍏 conventions for all core classes
14
+ - **mutable by default.**
15
+ operations happen in-place, for efficiency (we're trying to reduce gc churn).
16
+ ```ts
17
+ // allocate a single vector instance
18
+ const vector = new Vec2(0, 0)
19
+ .add({x: 1, y: 2})
20
+ .multiplyBy(2)
21
+ ```
22
+ - **explicit cloning.**
23
+ use `.clone()` to avoid mutating the original.
24
+ ```ts
25
+ // modify a clone (not the original)
26
+ const vector2 = vector
27
+ .clone()
28
+ .normalize()
29
+ ```
30
+ - **underscore-suffixed methods take direct args.**
31
+ - methods normally take in other class instances:
32
+ ```ts
33
+ vectorA.add(vectorB)
34
+ ```
35
+ - but underscore-suffixed methods take raw naked args (helping you avoid making instances)
36
+ ```ts
37
+ vectorA.add_(x, y)
38
+ ```
39
+
40
+ ### 🍏 Vec2
41
+ ### 🍏 Vec3
42
+ ### 🍏 Vec4
43
+ ### 🍏 Quat
44
+
45
+ <br/>
46
+
47
+ ## 🍋 TOOLS
48
+ > handy utilities
49
+
50
+ > [!TIP]
51
+ > until real docs are written, see the relevant sourcecode in [s/tools/](./s/tools/)
52
+
53
+ ### 🍏 Scalar
54
+ ### 🍏 Circular
55
+ ### 🍏 Randy
56
+ ### 🍏 Noise
57
+ ### 🍏 Spline
58
+ ### 🍏 Angles
59
+ - **Radians**
60
+ - **Degrees**
61
+ - **Turns**
62
+ - **Arcseconds**
63
+
64
+ <br/>
65
+
66
+ ## 🍋 SHAPES
67
+ > geometric concepts
68
+
69
+ > [!TIP]
70
+ > until real docs are written, see the relevant sourcecode in [s/shapes/](./s/shapes/)
71
+
72
+ ### 🍏 2d shapes
73
+ - **Edge** — a line segment
74
+ - **Pill** — a fat line segment (like a sausage)
75
+ - **Rect** — a rectangle
76
+ - **Circle** — a point with a radius
77
+
78
+ ### 🍏 3d shapes
79
+ - **Segment** — a line segment
80
+ - **Capsule** — a fat line segment (like a hoagie)
81
+ - **Box** — a cuboid
82
+ - **Sphere** — a point with a radius
83
+
84
+ <br/>
85
+
86
+ ## 🍋 OPTIMIZERS
87
+ > spatial optimization data structures
88
+
89
+ > [!TIP]
90
+ > until real docs are written, see the relevant sourcecode in [s/optimizers/](./s/optimizers/)
91
+
92
+ ### 🍏 HashMap
93
+ ### 🍏 HashSet
94
+ ### 🍏 ZenGrid
95
+
96
+ <br/>
97
+
98
+ ## 🍋 PHYSICS
99
+ > functionality for doing basic physics
100
+
101
+ > [!TIP]
102
+ > until real docs are written, see the relevant sourcecode in [s/physics/](./s/physics/)
103
+
104
+ ### 🍏 collide2d
105
+ ### 🍏 collide3d
106
+ ### 🍏 intersect2d
107
+ ### 🍏 intersect3d
108
+
109
+ <br/>
110
+
111
+ ## 👼 https://benevolent.games/
112
+ star this on github if you use it 👍
26
113
 
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@benev/math",
3
- "version": "0.2.0-0",
3
+ "version": "0.2.0-2",
4
4
  "description": "game math toolkit",
5
5
  "license": "MIT",
6
6
  "author": "Chase Moskal <chasemoskal@gmail.com>",
7
7
  "type": "module",
8
+ "sideEffects": false,
8
9
  "main": "./x/index.js",
9
10
  "exports": {
10
11
  ".": "./x/index.js"
@@ -21,12 +22,12 @@
21
22
  "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +"
22
23
  },
23
24
  "dependencies": {
24
- "@e280/stz": "^0.1.0",
25
+ "@e280/stz": "^0.2.0",
25
26
  "simplex-noise": "^4.0.3"
26
27
  },
27
28
  "devDependencies": {
28
- "@e280/science": "^0.1.0",
29
- "@e280/scute": "^0.0.0",
29
+ "@e280/science": "^0.1.2",
30
+ "@e280/scute": "^0.1.0",
30
31
  "npm-run-all": "^4.1.5",
31
32
  "typescript": "^5.9.2"
32
33
  },
@@ -1,7 +1,7 @@
1
1
 
2
2
  import {Xyz} from "./vec3.js"
3
3
 
4
- export type QuatArray = [number, number, number, number]
4
+ export type XyzwArray = [x: number, y: number, z: number, w: number]
5
5
  export type Xyzw = {x: number, y: number, z: number, w: number}
6
6
 
7
7
  export class Quat {
@@ -20,18 +20,10 @@ export class Quat {
20
20
  return new this(0, 0, 0, 1)
21
21
  }
22
22
 
23
- static array(q: QuatArray) {
24
- return new this(...q)
25
- }
26
-
27
- static import({x, y, z, w}: Xyzw) {
28
- return new this(x, y, z, w)
29
- }
30
-
31
- static from(q: QuatArray | Xyzw) {
23
+ static from(q: XyzwArray | Xyzw) {
32
24
  return Array.isArray(q)
33
- ? this.array(q)
34
- : this.import(q)
25
+ ? new this(...q)
26
+ : new this(q.x, q.y, q.z, q.w)
35
27
  }
36
28
 
37
29
  static rotate_(pitch: number, yaw: number, roll: number) {
@@ -42,7 +34,7 @@ export class Quat {
42
34
  return this.identity().rotate(vec)
43
35
  }
44
36
 
45
- array(): QuatArray {
37
+ toJSON(): XyzwArray {
46
38
  const {x, y, z, w} = this
47
39
  return [x, y, z, w]
48
40
  }
@@ -52,13 +44,61 @@ export class Quat {
52
44
  }
53
45
 
54
46
  clone() {
55
- return new Quat(...this.array())
47
+ return new Quat(...this.toJSON())
48
+ }
49
+
50
+ lengthSquared() {
51
+ return this.x*this.x + this.y*this.y + this.z*this.z + this.w*this.w
52
+ }
53
+
54
+ length() {
55
+ return Math.sqrt(this.lengthSquared())
56
+ }
57
+
58
+ isUnit(epsilon=1e-6) {
59
+ return Math.abs(this.length() - 1) <= epsilon
60
+ }
61
+
62
+ ensureUnit(){
63
+ if (!this.isUnit()) this.normalize()
64
+ return this
65
+ }
66
+
67
+ normalize(){
68
+ const m = this.length()
69
+ if (!m) {
70
+ this.x = this.y = this.z = 0
71
+ this.w = 1
72
+ return this
73
+ }
74
+ this.x /= m
75
+ this.y /= m
76
+ this.z /= m
77
+ this.w /= m
78
+ return this
79
+ }
80
+
81
+ conjugate() {
82
+ this.x *= -1
83
+ this.y *= -1
84
+ this.z *= -1
85
+ return this
86
+ }
87
+
88
+ invert() {
89
+ const len2 = this.lengthSquared()
90
+ if (!len2) return this.set_(0, 0, 0, 1)
91
+ this.x = -this.x / len2
92
+ this.y = -this.y / len2
93
+ this.z = -this.z / len2
94
+ this.w = this.w / len2
95
+ return this
56
96
  }
57
97
 
58
98
  transform_(x: number, y: number, z: number, w: number, global = false) {
59
99
  if (global) {
60
- const original = this.array()
61
- return this.set_(x, y, z, w).multiply_(...original)
100
+ const original = this.clone()
101
+ return this.set_(x, y, z, w).multiply(original)
62
102
  }
63
103
  else {
64
104
  return this.multiply_(x, y, z, w)
@@ -1,44 +1,31 @@
1
1
 
2
- import {Scalar} from "./scalar.js"
2
+ import {Scalar} from "../tools/scalar.js"
3
3
 
4
- export type Vec2Array = [number, number]
4
+ export type XyArray = [x: number, y: number]
5
5
  export type Xy = {x: number, y: number}
6
6
 
7
- /** https://github.com/microsoft/TypeScript/issues/5863 */
8
- type TsHack<T> = {new(...a: ConstructorParameters<typeof Vec2>): T}
9
-
10
7
  export class Vec2 implements Xy {
11
8
  constructor(
12
9
  public x: number,
13
10
  public y: number,
14
11
  ) {}
15
12
 
16
- ///////////////////////////////////////////////////////////////////////
17
-
18
- static new<T extends Vec2>(this: TsHack<T>, x: number, y: number): T {
13
+ static new(x: number, y: number) {
19
14
  return new this(x, y)
20
15
  }
21
16
 
22
- static zero<T extends Vec2>(this: TsHack<T>) {
17
+ static zero() {
23
18
  return new this(0, 0)
24
19
  }
25
20
 
26
- static all<T extends Vec2>(this: TsHack<T>, value: number) {
21
+ static all(value: number) {
27
22
  return new this(value, value)
28
23
  }
29
24
 
30
- static array<T extends Vec2>(this: TsHack<T>, v: Vec2Array) {
31
- return new this(...v)
32
- }
33
-
34
- static import<T extends Vec2>(this: TsHack<T>, {x, y}: Xy) {
35
- return new this(x, y)
36
- }
37
-
38
- static from(v: Vec2Array | Xy) {
25
+ static from(v: XyArray | Xy) {
39
26
  return Array.isArray(v)
40
- ? this.array(v)
41
- : this.import(v)
27
+ ? new this(...v)
28
+ : new this(v.x, v.y)
42
29
  }
43
30
 
44
31
  static magnitudeSquared(x: number, y: number) {
@@ -55,27 +42,37 @@ export class Vec2 implements Xy {
55
42
  .divideBy(vectors.length)
56
43
  }
57
44
 
58
- static min(...vecs: Vec2[]) {
59
- return new Vec2(
45
+ static min(...vecs: Xy[]) {
46
+ return new this(
60
47
  Math.min(...vecs.map(v => v.x)),
61
48
  Math.min(...vecs.map(v => v.y)),
62
49
  )
63
50
  }
64
51
 
65
- static max(...vecs: Vec2[]) {
66
- return new Vec2(
52
+ static max(...vecs: Xy[]) {
53
+ return new this(
67
54
  Math.max(...vecs.map(v => v.x)),
68
55
  Math.max(...vecs.map(v => v.y)),
69
56
  )
70
57
  }
71
58
 
72
- ///////////////////////////////////////////////////////////////////////
59
+ static fromAngle(radians: number) {
60
+ return new this(
61
+ Math.cos(radians),
62
+ Math.sin(radians),
63
+ )
64
+ }
73
65
 
74
66
  clone() {
75
67
  return new Vec2(this.x, this.y)
76
68
  }
77
69
 
78
- array(): Vec2Array {
70
+ *[Symbol.iterator]() {
71
+ yield this.x
72
+ yield this.y
73
+ }
74
+
75
+ toJSON(): XyArray {
79
76
  return [this.x, this.y]
80
77
  }
81
78
 
@@ -97,8 +94,6 @@ export class Vec2 implements Xy {
97
94
  return this
98
95
  }
99
96
 
100
- ///////////////////////////////////////////////////////////////////////
101
-
102
97
  magnitudeSquared() {
103
98
  return Vec2.magnitudeSquared(this.x, this.y)
104
99
  }
@@ -122,6 +117,17 @@ export class Vec2 implements Xy {
122
117
  return vecs.every(({x, y}) => this.equals_(x, y))
123
118
  }
124
119
 
120
+ near_(x: number, y: number, epsilon = 1e-6) {
121
+ return (
122
+ Math.abs(this.x - x) <= epsilon &&
123
+ Math.abs(this.y - y) <= epsilon
124
+ )
125
+ }
126
+
127
+ near({x, y}: Xy, epsilon = 1e-6) {
128
+ return this.near_(x, y, epsilon)
129
+ }
130
+
125
131
  dot_(x: number, y: number) {
126
132
  return (this.x * x) + (this.y * y)
127
133
  }
@@ -151,15 +157,15 @@ export class Vec2 implements Xy {
151
157
  angleBetween_(x: number, y: number) {
152
158
  const dot = this.dot_(x, y)
153
159
  const magnitudes = this.magnitude() * Vec2.magnitude(x, y)
154
- return Math.acos(dot / magnitudes)
160
+ if (magnitudes === 0) return 0
161
+ const ratio = Scalar.clamp(dot / magnitudes, -1, 1)
162
+ return Math.acos(ratio)
155
163
  }
156
164
 
157
165
  angleBetween({x, y}: Xy) {
158
166
  return this.angleBetween_(x, y)
159
167
  }
160
168
 
161
- ///////////////////////////////////////////////////////////////////////
162
-
163
169
  /** mutator */
164
170
  normalize() {
165
171
  return this.divideBy(this.magnitude())
@@ -233,9 +239,17 @@ export class Vec2 implements Xy {
233
239
  }
234
240
 
235
241
  /** mutator */
236
- clamp(min: number, max: number) {
237
- const clamp = (val: number) => Math.max(min, Math.min(max, val))
238
- return this.map(clamp)
242
+ clamp(min: Xy = {x: 0, y: 0}, max: Xy = {x: 1, y: 1}) {
243
+ this.x = Scalar.clamp(this.x, min.x, max.x)
244
+ this.y = Scalar.clamp(this.y, min.y, max.y)
245
+ return this
246
+ }
247
+
248
+ /** mutator */
249
+ clampBy(min = 0, max = 1) {
250
+ this.x = Scalar.clamp(this.x, min, max)
251
+ this.y = Scalar.clamp(this.y, min, max)
252
+ return this
239
253
  }
240
254
 
241
255
  /** mutator */
@@ -315,8 +329,8 @@ export class Vec2 implements Xy {
315
329
 
316
330
  /** mutator */
317
331
  divide_(x: number, y: number) {
318
- this.x /= x
319
- this.y /= y
332
+ if (x !== 0) this.x /= x
333
+ if (y !== 0) this.y /= y
320
334
  return this
321
335
  }
322
336
 
@@ -373,7 +387,7 @@ export class Vec2 implements Xy {
373
387
  }
374
388
 
375
389
  /** mutator */
376
- rotateAroundPoint({x, y}: Vec2, radians: number) {
390
+ rotateAroundPoint({x, y}: Xy, radians: number) {
377
391
  return this.rotateAroundPoint_(x, y, radians)
378
392
  }
379
393