@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
@@ -1,12 +1,9 @@
1
1
 
2
- import {Scalar} from "./scalar.js"
2
+ import {Scalar} from "../tools/scalar.js"
3
3
 
4
- export type Vec3Array = [number, number, number]
4
+ export type XyzArray = [x: number, y: number, z: number]
5
5
  export type Xyz = {x: number, y: number, z: number}
6
6
 
7
- /** https://github.com/microsoft/TypeScript/issues/5863 */
8
- type TsHack<T> = {new(...a: ConstructorParameters<typeof Vec3>): T}
9
-
10
7
  export class Vec3 {
11
8
  constructor(
12
9
  public x: number,
@@ -14,32 +11,22 @@ export class Vec3 {
14
11
  public z: number,
15
12
  ) {}
16
13
 
17
- ///////////////////////////////////////////////////////////////////////
18
-
19
- static new<T extends Vec3>(this: TsHack<T>, x: number, y: number, z: number) {
14
+ static new(x: number, y: number, z: number) {
20
15
  return new this(x, y, z)
21
16
  }
22
17
 
23
- static zero<T extends Vec3>(this: TsHack<T>) {
18
+ static zero() {
24
19
  return new this(0, 0, 0)
25
20
  }
26
21
 
27
- static all<T extends Vec3>(this: TsHack<T>, value: number) {
22
+ static all(value: number) {
28
23
  return new this(value, value, value)
29
24
  }
30
25
 
31
- static array<T extends Vec3>(this: TsHack<T>, v: Vec3Array) {
32
- return new this(...v)
33
- }
34
-
35
- static import<T extends Vec3>(this: TsHack<T>, {x, y, z}: Xyz): Vec3 {
36
- return new this(x, y, z)
37
- }
38
-
39
- static from(v: Vec3Array | Xyz) {
26
+ static from(v: XyzArray | Xyz) {
40
27
  return Array.isArray(v)
41
- ? this.array(v)
42
- : this.import(v)
28
+ ? new this(...v)
29
+ : new this(v.x, v.y, v.z)
43
30
  }
44
31
 
45
32
  static magnitudeSquared(x: number, y: number, z: number) {
@@ -56,23 +43,23 @@ export class Vec3 {
56
43
  .divideBy(vecs.length)
57
44
  }
58
45
 
59
- static min(...vecs: Vec3[]) {
60
- return new Vec3(
46
+ static min(...vecs: Xyz[]) {
47
+ return new this(
61
48
  Math.min(...vecs.map(v => v.x)),
62
49
  Math.min(...vecs.map(v => v.y)),
63
50
  Math.min(...vecs.map(v => v.z)),
64
51
  )
65
52
  }
66
53
 
67
- static max(...vecs: Vec3[]) {
68
- return new Vec3(
54
+ static max(...vecs: Xyz[]) {
55
+ return new this(
69
56
  Math.max(...vecs.map(v => v.x)),
70
57
  Math.max(...vecs.map(v => v.y)),
71
58
  Math.max(...vecs.map(v => v.z)),
72
59
  )
73
60
  }
74
61
 
75
- static hexColor(hex: string): Vec3 {
62
+ static fromHex(hex: string): Vec3 {
76
63
  if (hex.startsWith("#") && hex.length === 7) {
77
64
  const r = parseInt(hex.slice(1, 3), 16) / 255
78
65
  const g = parseInt(hex.slice(3, 5), 16) / 255
@@ -83,13 +70,17 @@ export class Vec3 {
83
70
  }
84
71
  }
85
72
 
86
- ///////////////////////////////////////////////////////////////////////
87
-
88
73
  clone() {
89
74
  return new Vec3(this.x, this.y, this.z)
90
75
  }
91
76
 
92
- array(): Vec3Array {
77
+ *[Symbol.iterator]() {
78
+ yield this.x
79
+ yield this.y
80
+ yield this.z
81
+ }
82
+
83
+ toJSON(): XyzArray {
93
84
  return [this.x, this.y, this.z]
94
85
  }
95
86
 
@@ -111,8 +102,6 @@ export class Vec3 {
111
102
  return this
112
103
  }
113
104
 
114
- ///////////////////////////////////////////////////////////////////////
115
-
116
105
  magnitudeSquared() {
117
106
  return Vec3.magnitudeSquared(this.x, this.y, this.z)
118
107
  }
@@ -121,14 +110,13 @@ export class Vec3 {
121
110
  return Vec3.magnitude(this.x, this.y, this.z)
122
111
  }
123
112
 
124
- hexColor() {
125
- const to255 = (val: number) => Math.round(val * 255)
113
+ /** rgb values from 0-1 */
114
+ toHex() {
115
+ const to255 = (val: number) => Math.round(Scalar.clamp(val * 255, 0, 255))
126
116
  const toHex = (val: number) => to255(val).toString(16).padStart(2, '0')
127
117
  return `#${toHex(this.x)}${toHex(this.y)}${toHex(this.z)}`
128
118
  }
129
119
 
130
- ///////////////////////////////////////////////////////////////////////
131
-
132
120
  equals_(x: number, y: number, z: number) {
133
121
  return (
134
122
  this.x === x &&
@@ -138,7 +126,19 @@ export class Vec3 {
138
126
  }
139
127
 
140
128
  equals(...vecs: Xyz[]) {
141
- return vecs.every(v => this.equals_(v.x, v.y, v.z))
129
+ return vecs.every(({x, y, z}) => this.equals_(x, y, z))
130
+ }
131
+
132
+ near_(x: number, y: number, z: number, epsilon = 1e-6) {
133
+ return (
134
+ Math.abs(this.x - x) <= epsilon &&
135
+ Math.abs(this.y - y) <= epsilon &&
136
+ Math.abs(this.z - z) <= epsilon
137
+ )
138
+ }
139
+
140
+ near({x, y, z}: Xyz, epsilon = 1e-6) {
141
+ return this.near_(x, y, z, epsilon)
142
142
  }
143
143
 
144
144
  distanceSquared_(x: number, y: number, z: number) {
@@ -179,16 +179,16 @@ export class Vec3 {
179
179
 
180
180
  angleBetween_(x: number, y: number, z: number) {
181
181
  const dotProduct = this.dot_(x, y, z)
182
- const magnitudes = this.magnitude() * Vec3.new(x, y, z).magnitude()
183
- return Math.acos(dotProduct / magnitudes)
182
+ const magnitudes = this.magnitude() * Vec3.magnitude(x, y, z)
183
+ if (magnitudes === 0) return 0
184
+ const ratio = Scalar.clamp(dotProduct / magnitudes, -1, 1)
185
+ return Math.acos(ratio)
184
186
  }
185
187
 
186
188
  angleBetween({x, y, z}: Xyz) {
187
189
  return this.angleBetween_(x, y, z)
188
190
  }
189
191
 
190
- ///////////////////////////////////////////////////////////////////////
191
-
192
192
  /** mutator */
193
193
  add_(x: number, y: number, z: number) {
194
194
  this.x += x
@@ -226,21 +226,21 @@ export class Vec3 {
226
226
  }
227
227
 
228
228
  /** mutator */
229
- multiply(...vecs: Vec3[]) {
229
+ multiply(...vecs: Xyz[]) {
230
230
  for (const {x, y, z} of vecs) this.multiply_(x, y, z)
231
231
  return this
232
232
  }
233
233
 
234
234
  /** mutator */
235
235
  divide_(x: number, y: number, z: number) {
236
- this.x /= x
237
- this.y /= y
238
- this.z /= z
236
+ if (x !== 0) this.x /= x
237
+ if (y !== 0) this.y /= y
238
+ if (z !== 0) this.z /= z
239
239
  return this
240
240
  }
241
241
 
242
242
  /** mutator */
243
- divide(...vecs: Vec3[]) {
243
+ divide(...vecs: Xyz[]) {
244
244
  for (const {x, y, z} of vecs) this.divide_(x, y, z)
245
245
  return this
246
246
  }
@@ -278,6 +278,22 @@ export class Vec3 {
278
278
  return this
279
279
  }
280
280
 
281
+ /** mutator */
282
+ clamp(min: Xyz = {x: 0, y: 0, z: 0}, max: Xyz = {x: 1, y: 1, z: 1}) {
283
+ this.x = Scalar.clamp(this.x, min.x, max.x)
284
+ this.y = Scalar.clamp(this.y, min.y, max.y)
285
+ this.z = Scalar.clamp(this.z, min.z, max.z)
286
+ return this
287
+ }
288
+
289
+ /** mutator */
290
+ clampBy(min = 0, max = 1) {
291
+ this.x = Scalar.clamp(this.x, min, max)
292
+ this.y = Scalar.clamp(this.y, min, max)
293
+ this.z = Scalar.clamp(this.z, min, max)
294
+ return this
295
+ }
296
+
281
297
  /** mutator */
282
298
  addBy(delta: number) {
283
299
  this.x += delta
@@ -286,6 +302,14 @@ export class Vec3 {
286
302
  return this
287
303
  }
288
304
 
305
+ /** mutator */
306
+ subtractBy(delta: number) {
307
+ this.x -= delta
308
+ this.y -= delta
309
+ this.z -= delta
310
+ return this
311
+ }
312
+
289
313
  /** mutator */
290
314
  multiplyBy(delta: number) {
291
315
  this.x *= delta
@@ -381,7 +405,9 @@ export class Vec3 {
381
405
 
382
406
  /** mutator */
383
407
  projectOnto_(x: number, y: number, z: number) {
384
- const scalar = this.dot_(x, y, z) / Vec3.magnitudeSquared(x, y, z)
408
+ const m2 = Vec3.magnitudeSquared(x, y, z)
409
+ if (!m2) return this
410
+ const scalar = this.dot_(x, y, z) / m2
385
411
  this.x = scalar * x
386
412
  this.y = scalar * y
387
413
  this.z = scalar * z
@@ -389,7 +415,7 @@ export class Vec3 {
389
415
  }
390
416
 
391
417
  /** mutator */
392
- projectOnto({x, y, z}: Vec3) {
418
+ projectOnto({x, y, z}: Xyz) {
393
419
  return this.projectOnto_(x, y, z)
394
420
  }
395
421
 
@@ -1,7 +1,5 @@
1
1
 
2
- import {Xyzw} from "./quat.js"
3
-
4
- export type Vec4Array = [number, number, number, number]
2
+ import {Xyzw, XyzwArray} from "./quat.js"
5
3
 
6
4
  export class Vec4 {
7
5
  constructor(
@@ -19,21 +17,24 @@ export class Vec4 {
19
17
  return new this(0, 0, 0, 0)
20
18
  }
21
19
 
22
- static array(v: Vec4Array) {
23
- return new this(...v)
20
+ static from(v: XyzwArray | Xyzw) {
21
+ return Array.isArray(v)
22
+ ? new this(...v)
23
+ : new this(v.x, v.y, v.z, v.w)
24
24
  }
25
25
 
26
- static import({x, y, z, w}: Xyzw) {
27
- return new this(x, y, z, w)
26
+ clone() {
27
+ return new Vec4(this.x, this.y, this.z, this.w)
28
28
  }
29
29
 
30
- static from(v: Vec4Array | Xyzw) {
31
- return Array.isArray(v)
32
- ? this.array(v)
33
- : this.import(v)
30
+ *[Symbol.iterator]() {
31
+ yield this.x
32
+ yield this.y
33
+ yield this.z
34
+ yield this.w
34
35
  }
35
36
 
36
- array(): Vec4Array {
37
+ toJSON(): XyzwArray {
37
38
  const {x, y, z, w} = this
38
39
  return [x, y, z, w]
39
40
  }
@@ -42,10 +43,6 @@ export class Vec4 {
42
43
  return `(Vec4 x${this.x.toFixed(2)}, y${this.y.toFixed(2)}, z${this.z.toFixed(2)}, w${this.w.toFixed(2)})`
43
44
  }
44
45
 
45
- clone() {
46
- return new Vec4(...this.array())
47
- }
48
-
49
46
  set_(x: number, y: number, z: number, w: number) {
50
47
  this.x = x
51
48
  this.y = y
package/s/index.ts CHANGED
@@ -1,10 +1,15 @@
1
1
 
2
- export * from "./primitives/circular.js"
3
- export * from "./primitives/quat.js"
4
- export * from "./primitives/scalar.js"
5
- export * from "./primitives/vec2.js"
6
- export * from "./primitives/vec3.js"
7
- export * from "./primitives/vec4.js"
2
+ export * from "./core/quat.js"
3
+ export * from "./core/vec2.js"
4
+ export * from "./core/vec3.js"
5
+ export * from "./core/vec4.js"
6
+
7
+ export * from "./tools/angles.js"
8
+ export * from "./tools/circular.js"
9
+ export * from "./tools/noise.js"
10
+ export * from "./tools/randy.js"
11
+ export * from "./tools/scalar.js"
12
+ export * as spline from "./tools/spline.js"
8
13
 
9
14
  export * from "./optimizers/hash-map.js"
10
15
  export * from "./optimizers/hash-set.js"
@@ -17,12 +22,6 @@ export * as intersect2d from "./physics/2d/intersect2d.js"
17
22
 
18
23
  export * from "./shapes/2d/index.js"
19
24
  export * as shapes2d from "./shapes/2d/index.js"
20
-
21
25
  export * from "./shapes/3d/index.js"
22
26
  export * as shapes3d from "./shapes/3d/index.js"
23
27
 
24
- export * from "./utils/angles.js"
25
- export * from "./utils/noise.js"
26
- export * from "./utils/randy.js"
27
- export * as spline from "./utils/spline.js"
28
-
@@ -45,6 +45,10 @@ export class HashMap<Key, Value> {
45
45
  return this.#map.values()
46
46
  }
47
47
 
48
+ [Symbol.iterator]() {
49
+ return this.entries()
50
+ }
51
+
48
52
  *keys() {
49
53
  for (const [key] of this.#map.values())
50
54
  yield key
@@ -42,5 +42,9 @@ export class HashSet<Value> {
42
42
  values() {
43
43
  return this.#map.values()
44
44
  }
45
+
46
+ [Symbol.iterator]() {
47
+ return this.values()
48
+ }
45
49
  }
46
50
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  import {MapG} from "@e280/stz"
3
+ import {Vec2} from "../core/vec2.js"
3
4
  import {Rect} from "../shapes/2d/rect.js"
4
- import {Vec2} from "../primitives/vec2.js"
5
5
  import {rectVsRect} from "../physics/2d/collide2d.js"
6
6
 
7
7
  export class Zen<X> {
@@ -9,7 +9,7 @@ export class Zen<X> {
9
9
 
10
10
  constructor(
11
11
  public grid: ZenGrid<X>,
12
- public box: Rect,
12
+ public rect: Rect,
13
13
  public item: X,
14
14
  ) {}
15
15
 
@@ -22,11 +22,12 @@ export class Zen<X> {
22
22
  }
23
23
  }
24
24
 
25
- export class ZenZone<X> extends Rect {
25
+ export class ZenZone<X> {
26
+ rect: Rect
26
27
  zens = new Set<Zen<X>>()
27
28
 
28
- constructor(public hash: string, center: Vec2, extent: Vec2) {
29
- super(center, extent)
29
+ constructor(public hash: string, center: Vec2, size: Vec2) {
30
+ this.rect = Rect.fromCenter(center, size)
30
31
  }
31
32
  }
32
33
 
@@ -42,14 +43,14 @@ export class ZenGrid<X> {
42
43
  return n
43
44
  }
44
45
 
45
- create(box: Rect, item: X) {
46
- const zen = new Zen<X>(this, box, item)
46
+ create(rect: Rect, item: X) {
47
+ const zen = new Zen<X>(this, rect, item)
47
48
  this.update(zen)
48
49
  return zen
49
50
  }
50
51
 
51
52
  update(zen: Zen<X>) {
52
- const wantedZones = this.#selectZones(zen.box)
53
+ const wantedZones = this.#selectZones(zen.rect)
53
54
 
54
55
  // delete stale zones
55
56
  for (const zone of zen.zones) {
@@ -81,38 +82,38 @@ export class ZenGrid<X> {
81
82
  this.#zones.delete(emptyZone.hash)
82
83
  }
83
84
 
84
- check(box: Rect) {
85
- const zones = this.#selectZones(box)
85
+ check(rect: Rect) {
86
+ const zones = this.#selectZones(rect)
86
87
 
87
88
  for (const zone of zones)
88
89
  for (const zen of zone.zens)
89
- if (rectVsRect(box, zen.box))
90
+ if (rectVsRect(rect, zen.rect))
90
91
  return true
91
92
 
92
93
  return false
93
94
  }
94
95
 
95
- /** return all zens that touch the given box */
96
- query(box: Rect) {
97
- const zones = this.#selectZones(box)
98
- const selected: Zen<X>[] = []
96
+ /** return set of zens that touch the given rect */
97
+ query(rect: Rect) {
98
+ const zones = this.#selectZones(rect)
99
+ const selected = new Set<Zen<X>>()
99
100
 
100
101
  for (const zone of zones)
101
102
  for (const zen of zone.zens)
102
- if (rectVsRect(box, zen.box) && !selected.includes(zen))
103
- selected.push(zen)
103
+ if (!selected.has(zen) && rectVsRect(rect, zen.rect))
104
+ selected.add(zen)
104
105
 
105
106
  return selected
106
107
  }
107
108
 
108
- /** return all zen items that touch the given box */
109
- queryItems(box: Rect) {
110
- return this.query(box).map(zen => zen.item)
109
+ /** return all zen items that touch the given rect */
110
+ queryItems(rect: Rect) {
111
+ return [...this.query(rect)].map(zen => zen.item)
111
112
  }
112
113
 
113
- /** return all zen boxes that touch the given box */
114
- queryBoxes(box: Rect) {
115
- return this.query(box).map(zen => zen.box)
114
+ /** return all zen rects that touch the given rect */
115
+ queryRects(rect: Rect) {
116
+ return [...this.query(rect)].map(zen => zen.rect)
116
117
  }
117
118
 
118
119
  #hash(v: Vec2) {
@@ -135,10 +136,10 @@ export class ZenGrid<X> {
135
136
  ))
136
137
  }
137
138
 
138
- #selectZones(box: Rect) {
139
+ #selectZones(rect: Rect) {
139
140
  const zones = new Set<ZenZone<X>>()
140
- const minZoneCorner = this.#calculateZoneCorner(box.min)
141
- const maxZoneCorner = this.#calculateZoneCorner(box.max)
141
+ const minZoneCorner = this.#calculateZoneCorner(rect.min)
142
+ const maxZoneCorner = this.#calculateZoneCorner(rect.max)
142
143
 
143
144
  for (let x = minZoneCorner.x; x <= maxZoneCorner.x; x += this.zoneExtent.x)
144
145
  for (let y = minZoneCorner.y; y <= maxZoneCorner.y; y += this.zoneExtent.y)
@@ -1,7 +1,7 @@
1
1
 
2
- import {Vec2} from "../../primitives/vec2.js"
2
+ import {Vec2} from "../../core/vec2.js"
3
3
  import {Rect} from "../../shapes/2d/rect.js"
4
- import {Scalar} from "../../primitives/scalar.js"
4
+ import {Scalar} from "../../tools/scalar.js"
5
5
  import {Circle} from "../../shapes/2d/circle.js"
6
6
 
7
7
  export function pointVsRect(point: Vec2, box: Rect) {
@@ -1,7 +1,7 @@
1
1
 
2
- import {Vec2} from "../../primitives/vec2.js"
2
+ import {Vec2} from "../../core/vec2.js"
3
3
  import {Rect} from "../../shapes/2d/rect.js"
4
- import {Scalar} from "../../primitives/scalar.js"
4
+ import {Scalar} from "../../tools/scalar.js"
5
5
  import {Circle} from "../../shapes/2d/circle.js"
6
6
  import {rectVsCircle, rectVsRect} from "./collide2d.js"
7
7
 
@@ -21,14 +21,17 @@ export function intersectRectVsRect(a: Rect, b: Rect) {
21
21
  const overlapY = Math.min(a.max.y - b.min.y, b.max.y - a.min.y)
22
22
  const depth = Math.min(overlapX, overlapY)
23
23
 
24
+ const aCenter = a.center()
25
+ const bCenter = b.center()
26
+
24
27
  const contactPoint = new Vec2(
25
- Scalar.clamp((a.center.x + b.center.x) / 2, b.min.x, b.max.x),
26
- Scalar.clamp((a.center.y + b.center.y) / 2, b.min.y, b.max.y)
28
+ Scalar.clamp((aCenter.x + bCenter.x) / 2, b.min.x, b.max.x),
29
+ Scalar.clamp((aCenter.y + bCenter.y) / 2, b.min.y, b.max.y)
27
30
  )
28
31
 
29
32
  const normalA = depth === overlapX
30
- ? new Vec2(b.center.x > a.center.x ? -1 : 1, 0)
31
- : new Vec2(0, b.center.y > a.center.y ? -1 : 1)
33
+ ? new Vec2(bCenter.x > aCenter.x ? -1 : 1, 0)
34
+ : new Vec2(0, bCenter.y > aCenter.y ? -1 : 1)
32
35
 
33
36
  const normalB = normalA.clone().multiplyBy(-1)
34
37
 
@@ -1,6 +1,9 @@
1
1
 
2
2
  import {Rect} from "./rect.js"
3
- import {Vec2} from "../../primitives/vec2.js"
3
+ import {Vec2, XyArray, Xy} from "../../core/vec2.js"
4
+
5
+ export type CircleJson = [center: XyArray, radius: number]
6
+ export type CircleLike = {center: Xy, radius: number}
4
7
 
5
8
  export class Circle {
6
9
  constructor(
@@ -8,18 +11,33 @@ export class Circle {
8
11
  public radius: number,
9
12
  ) {}
10
13
 
11
- offset(delta: Vec2) {
12
- this.center.add(delta)
13
- return this
14
+ static from(data: CircleJson | CircleLike) {
15
+ return Array.isArray(data)
16
+ ? new this(Vec2.from(data[0]), data[1])
17
+ : new this(Vec2.from(data.center), data.radius)
14
18
  }
15
19
 
16
- boundingBox() {
17
- const extent = Vec2.all(this.radius * 2)
18
- return new Rect(this.center, extent)
20
+ toJSON(): CircleJson {
21
+ return [this.center.clone().toJSON(), this.radius]
19
22
  }
20
23
 
21
24
  clone() {
22
25
  return new Circle(this.center.clone(), this.radius)
23
26
  }
27
+
28
+ set(circle: CircleLike) {
29
+ this.center.set(circle.center)
30
+ this.radius = circle.radius
31
+ }
32
+
33
+ translate(delta: Vec2) {
34
+ this.center.add(delta)
35
+ return this
36
+ }
37
+
38
+ boundingBox() {
39
+ const size = Vec2.all(this.radius * 2)
40
+ return Rect.fromCenter(this.center.clone(), size)
41
+ }
24
42
  }
25
43
 
@@ -1,36 +1,65 @@
1
1
 
2
- import {Vec2} from "../../primitives/vec2.js"
2
+ import {Vec2, XyArray, Xy} from "../../core/vec2.js"
3
3
  import {pointVsRect} from "../../physics/2d/collide2d.js"
4
4
 
5
+ export type RectJson = [min: XyArray, max: XyArray]
6
+ export type RectLike = {min: Xy, max: Xy}
7
+
5
8
  export class Rect {
6
9
  constructor(
7
- public center: Vec2,
8
- public extent: Vec2,
9
- ) {
10
- if (extent.x < 0 || extent.y < 0)
11
- throw new Error(`invalid negative extent, ${extent.toString()}`)
10
+ public min: Vec2,
11
+ public max: Vec2,
12
+ ) {}
13
+
14
+ static from(data: RectJson | RectLike) {
15
+ return Array.isArray(data)
16
+ ? new this(Vec2.from(data[0]), Vec2.from(data[1]))
17
+ : new this(Vec2.from(data.min), Vec2.from(data.max))
18
+ }
19
+
20
+ static fromCorner(min: Vec2, size: Vec2) {
21
+ const max = min.clone().add(size)
22
+ return new this(min, max)
12
23
  }
13
24
 
14
- static fromCorner(min: Vec2, extent: Vec2) {
15
- return new this(min.add(extent.clone().half()), extent)
25
+ static fromCenter(center: Vec2, size: Vec2) {
26
+ const halfSize = size.clone().half()
27
+ const min = center.clone().subtract(halfSize)
28
+ const max = center.clone().add(halfSize)
29
+ return new this(min, max)
30
+ }
31
+
32
+ clone() {
33
+ return new Rect(this.min.clone(), this.max.clone())
16
34
  }
17
35
 
18
- get min() {
19
- return this.center.clone()
20
- .subtract(this.extent.clone().half())
36
+ toJSON(): RectJson {
37
+ return [this.min.toJSON(), this.max.toJSON()]
21
38
  }
22
39
 
23
- get max() {
24
- return this.center.clone()
25
- .add(this.extent.clone().half())
40
+ set(rect: RectLike) {
41
+ this.min.set(rect.min)
42
+ this.max.set(rect.max)
26
43
  }
27
44
 
28
- offset(delta: Vec2) {
29
- this.center.add(delta)
45
+ normalize() {
46
+ const {min, max} = this
47
+ this.min.set(Vec2.min(min, max))
48
+ this.max.set(Vec2.max(min, max))
30
49
  return this
31
50
  }
32
51
 
33
- boundingBox() {
52
+ size() {
53
+ return this.max.clone().subtract(this.min)
54
+ }
55
+
56
+ center() {
57
+ return this.min.clone().add(this.size().half())
58
+ }
59
+
60
+ translate(delta: Vec2) {
61
+ this.min.add(delta)
62
+ this.max.add(delta)
34
63
  return this
35
64
  }
36
65
 
@@ -38,8 +67,8 @@ export class Rect {
38
67
  return pointVsRect(point, this)
39
68
  }
40
69
 
41
- clone() {
42
- return new Rect(this.center.clone(), this.extent.clone())
70
+ boundingBox() {
71
+ return this.clone()
43
72
  }
44
73
  }
45
74