@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.
- package/README.md +110 -23
- package/package.json +5 -4
- package/s/{primitives → core}/quat.ts +56 -16
- package/s/{primitives → core}/vec2.ts +52 -38
- package/s/{primitives → core}/vec3.ts +73 -47
- package/s/{primitives → core}/vec4.ts +13 -16
- package/s/index.ts +11 -12
- package/s/optimizers/hash-map.ts +4 -0
- package/s/optimizers/hash-set.ts +4 -0
- package/s/optimizers/zen.ts +27 -26
- package/s/physics/2d/collide2d.ts +2 -2
- package/s/physics/2d/intersect2d.ts +9 -6
- package/s/shapes/2d/circle.ts +25 -7
- package/s/shapes/2d/rect.ts +48 -19
- package/s/shapes/3d/box.ts +65 -20
- package/s/shapes/3d/segment.ts +12 -10
- package/s/{utils → tools}/angles.ts +7 -1
- package/s/{primitives → tools}/circular.ts +5 -3
- package/s/{primitives → tools}/scalar.ts +11 -11
- package/s/{utils → tools}/spline.ts +12 -11
- package/x/{primitives → core}/quat.d.ts +10 -5
- package/x/{primitives → core}/quat.js +49 -12
- package/x/core/quat.js.map +1 -0
- package/x/{primitives → core}/vec2.d.ts +16 -17
- package/x/{primitives → core}/vec2.js +38 -22
- package/x/core/vec2.js.map +1 -0
- package/x/{primitives → core}/vec3.d.ts +23 -20
- package/x/{primitives → core}/vec3.js +60 -27
- package/x/core/vec3.js.map +1 -0
- package/x/{primitives → core}/vec4.d.ts +5 -7
- package/x/{primitives → core}/vec4.js +12 -12
- package/x/core/vec4.js.map +1 -0
- package/x/index.d.ts +10 -10
- package/x/index.js +10 -10
- package/x/index.js.map +1 -1
- package/x/optimizers/hash-map.d.ts +1 -0
- package/x/optimizers/hash-map.js +3 -0
- package/x/optimizers/hash-map.js.map +1 -1
- package/x/optimizers/hash-set.d.ts +1 -0
- package/x/optimizers/hash-set.js +3 -0
- package/x/optimizers/hash-set.js.map +1 -1
- package/x/optimizers/zen.d.ts +14 -13
- package/x/optimizers/zen.js +29 -28
- package/x/optimizers/zen.js.map +1 -1
- package/x/physics/2d/collide2d.d.ts +1 -1
- package/x/physics/2d/collide2d.js +2 -2
- package/x/physics/2d/collide2d.js.map +1 -1
- package/x/physics/2d/intersect2d.d.ts +1 -1
- package/x/physics/2d/intersect2d.js +7 -5
- package/x/physics/2d/intersect2d.js.map +1 -1
- package/x/shapes/2d/circle.d.ts +11 -3
- package/x/shapes/2d/circle.js +19 -7
- package/x/shapes/2d/circle.js.map +1 -1
- package/x/shapes/2d/rect.d.ts +20 -10
- package/x/shapes/2d/rect.js +47 -24
- package/x/shapes/2d/rect.js.map +1 -1
- package/x/shapes/3d/box.d.ts +21 -8
- package/x/shapes/3d/box.js +56 -17
- package/x/shapes/3d/box.js.map +1 -1
- package/x/shapes/3d/segment.d.ts +5 -5
- package/x/shapes/3d/segment.js +11 -9
- package/x/shapes/3d/segment.js.map +1 -1
- package/x/{utils → tools}/angles.d.ts +2 -0
- package/x/{utils → tools}/angles.js +7 -1
- package/x/tools/angles.js.map +1 -0
- package/x/{primitives → tools}/circular.js +4 -3
- package/x/tools/circular.js.map +1 -0
- package/x/{utils → tools}/noise.js.map +1 -1
- package/x/{utils → tools}/randy.js.map +1 -1
- package/x/{primitives → tools}/scalar.d.ts +4 -4
- package/x/{primitives → tools}/scalar.js +11 -11
- package/x/tools/scalar.js.map +1 -0
- package/x/{utils → tools}/spline.d.ts +3 -3
- package/x/{utils → tools}/spline.js +4 -2
- package/x/tools/spline.js.map +1 -0
- package/x/primitives/circular.js.map +0 -1
- package/x/primitives/quat.js.map +0 -1
- package/x/primitives/scalar.js.map +0 -1
- package/x/primitives/vec2.js.map +0 -1
- package/x/primitives/vec3.js.map +0 -1
- package/x/primitives/vec4.js.map +0 -1
- package/x/utils/angles.js.map +0 -1
- package/x/utils/spline.js.map +0 -1
- /package/s/{utils → tools}/noise.ts +0 -0
- /package/s/{utils → tools}/randy.ts +0 -0
- /package/x/{primitives → tools}/circular.d.ts +0 -0
- /package/x/{utils → tools}/noise.d.ts +0 -0
- /package/x/{utils → tools}/noise.js +0 -0
- /package/x/{utils → tools}/randy.d.ts +0 -0
- /package/x/{utils → tools}/randy.js +0 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {Scalar} from "
|
|
2
|
+
import {Scalar} from "../tools/scalar.js"
|
|
3
3
|
|
|
4
|
-
export type
|
|
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
|
|
18
|
+
static zero() {
|
|
24
19
|
return new this(0, 0, 0)
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
static all
|
|
22
|
+
static all(value: number) {
|
|
28
23
|
return new this(value, value, value)
|
|
29
24
|
}
|
|
30
25
|
|
|
31
|
-
static
|
|
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
|
|
42
|
-
: this
|
|
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:
|
|
60
|
-
return new
|
|
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:
|
|
68
|
-
return new
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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(
|
|
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.
|
|
183
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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}:
|
|
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
|
|
23
|
-
return
|
|
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
|
-
|
|
27
|
-
return new this
|
|
26
|
+
clone() {
|
|
27
|
+
return new Vec4(this.x, this.y, this.z, this.w)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
*[Symbol.iterator]() {
|
|
31
|
+
yield this.x
|
|
32
|
+
yield this.y
|
|
33
|
+
yield this.z
|
|
34
|
+
yield this.w
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
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 "./
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
|
|
7
|
-
export * from "./
|
|
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
|
-
|
package/s/optimizers/hash-map.ts
CHANGED
package/s/optimizers/hash-set.ts
CHANGED
package/s/optimizers/zen.ts
CHANGED
|
@@ -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
|
|
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>
|
|
25
|
+
export class ZenZone<X> {
|
|
26
|
+
rect: Rect
|
|
26
27
|
zens = new Set<Zen<X>>()
|
|
27
28
|
|
|
28
|
-
constructor(public hash: string, center: Vec2,
|
|
29
|
-
|
|
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(
|
|
46
|
-
const zen = new Zen<X>(this,
|
|
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.
|
|
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(
|
|
85
|
-
const zones = this.#selectZones(
|
|
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(
|
|
90
|
+
if (rectVsRect(rect, zen.rect))
|
|
90
91
|
return true
|
|
91
92
|
|
|
92
93
|
return false
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
/** return
|
|
96
|
-
query(
|
|
97
|
-
const zones = this.#selectZones(
|
|
98
|
-
const selected
|
|
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 (
|
|
103
|
-
selected.
|
|
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
|
|
109
|
-
queryItems(
|
|
110
|
-
return this.query(
|
|
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
|
|
114
|
-
|
|
115
|
-
return this.query(
|
|
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(
|
|
139
|
+
#selectZones(rect: Rect) {
|
|
139
140
|
const zones = new Set<ZenZone<X>>()
|
|
140
|
-
const minZoneCorner = this.#calculateZoneCorner(
|
|
141
|
-
const maxZoneCorner = this.#calculateZoneCorner(
|
|
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 "../../
|
|
2
|
+
import {Vec2} from "../../core/vec2.js"
|
|
3
3
|
import {Rect} from "../../shapes/2d/rect.js"
|
|
4
|
-
import {Scalar} from "../../
|
|
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 "../../
|
|
2
|
+
import {Vec2} from "../../core/vec2.js"
|
|
3
3
|
import {Rect} from "../../shapes/2d/rect.js"
|
|
4
|
-
import {Scalar} from "../../
|
|
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((
|
|
26
|
-
Scalar.clamp((
|
|
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(
|
|
31
|
-
: new Vec2(0,
|
|
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
|
|
package/s/shapes/2d/circle.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import {Rect} from "./rect.js"
|
|
3
|
-
import {Vec2} from "../../
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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
|
|
package/s/shapes/2d/rect.ts
CHANGED
|
@@ -1,36 +1,65 @@
|
|
|
1
1
|
|
|
2
|
-
import {Vec2} from "../../
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
return this.
|
|
20
|
-
.subtract(this.extent.clone().half())
|
|
36
|
+
toJSON(): RectJson {
|
|
37
|
+
return [this.min.toJSON(), this.max.toJSON()]
|
|
21
38
|
}
|
|
22
39
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
set(rect: RectLike) {
|
|
41
|
+
this.min.set(rect.min)
|
|
42
|
+
this.max.set(rect.max)
|
|
26
43
|
}
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
this
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
return
|
|
70
|
+
boundingBox() {
|
|
71
|
+
return this.clone()
|
|
43
72
|
}
|
|
44
73
|
}
|
|
45
74
|
|