@benev/math 0.2.0-0 → 0.2.0-1
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 +2 -1
- package/s/{primitives → core}/quat.ts +56 -16
- package/s/{primitives → core}/vec2.ts +52 -38
- package/s/{primitives → core}/vec3.ts +57 -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 +37 -21
- package/x/core/vec2.js.map +1 -0
- package/x/{primitives → core}/vec3.d.ts +19 -20
- package/x/{primitives → core}/vec3.js +46 -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,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
|
|
package/s/shapes/3d/box.ts
CHANGED
|
@@ -1,38 +1,83 @@
|
|
|
1
1
|
|
|
2
|
-
import {Vec3} from "../../
|
|
2
|
+
import {Vec3, XyzArray, Xyz} from "../../core/vec3.js"
|
|
3
|
+
|
|
4
|
+
export type BoxJson = [min: XyzArray, max: XyzArray]
|
|
5
|
+
export type BoxLike = {min: Xyz, max: Xyz}
|
|
3
6
|
|
|
4
7
|
export class Box {
|
|
5
8
|
constructor(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
public min: Vec3,
|
|
10
|
+
public max: Vec3,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
static from(data: BoxJson | BoxLike) {
|
|
14
|
+
return Array.isArray(data)
|
|
15
|
+
? new this(Vec3.from(data[0]), Vec3.from(data[1]))
|
|
16
|
+
: new this(Vec3.from(data.min), Vec3.from(data.max))
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
static fromCorner(min: Vec3,
|
|
14
|
-
return new this(
|
|
15
|
-
min.clone().add(extent.clone().half()),
|
|
16
|
-
extent,
|
|
17
|
-
)
|
|
19
|
+
static fromCorner(min: Vec3, size: Vec3) {
|
|
20
|
+
return new this(min, min.clone().add(size))
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
static fromCenter(center: Vec3, size: Vec3) {
|
|
24
|
+
const halfSize = size.clone().half()
|
|
25
|
+
const min = center.clone().subtract(halfSize)
|
|
26
|
+
const max = center.clone().add(halfSize)
|
|
27
|
+
return new this(min, max)
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
return this.
|
|
27
|
-
.add(this.extent.clone().half())
|
|
30
|
+
toJSON(): BoxJson {
|
|
31
|
+
return [this.min.toJSON(), this.max.toJSON()]
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
clone() {
|
|
31
|
-
return new Box(this.
|
|
35
|
+
return new Box(this.min.clone(), this.max.clone())
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set(box: BoxLike) {
|
|
39
|
+
this.min.set(box.min)
|
|
40
|
+
this.max.set(box.max)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
size() {
|
|
44
|
+
return this.max.clone().subtract(this.min)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
center() {
|
|
48
|
+
return this.min.clone().add(this.size().half())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
normalize() {
|
|
52
|
+
const {min, max} = this
|
|
53
|
+
this.min.set(Vec3.min(min, max))
|
|
54
|
+
this.max.set(Vec3.max(min, max))
|
|
55
|
+
return this
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
translate_(x: number, y: number, z: number) {
|
|
59
|
+
this.min.add_(x, y, z)
|
|
60
|
+
this.max.add_(x, y, z)
|
|
61
|
+
return this
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
translate(delta: Vec3) {
|
|
65
|
+
this.min.add(delta)
|
|
66
|
+
this.max.add(delta)
|
|
67
|
+
return this
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
grow(increase: Vec3) {
|
|
71
|
+
const halfIncrease = increase.clone().half()
|
|
72
|
+
this.min.subtract(halfIncrease)
|
|
73
|
+
this.max.add(halfIncrease)
|
|
74
|
+
return this
|
|
32
75
|
}
|
|
33
76
|
|
|
34
|
-
|
|
35
|
-
|
|
77
|
+
growBy(increase: number) {
|
|
78
|
+
const halfIncrease = increase / 2
|
|
79
|
+
this.min.subtractBy(halfIncrease)
|
|
80
|
+
this.max.addBy(halfIncrease)
|
|
36
81
|
return this
|
|
37
82
|
}
|
|
38
83
|
}
|
package/s/shapes/3d/segment.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {Vec3} from "../../
|
|
2
|
+
import {Vec3} from "../../core/vec3.js"
|
|
3
3
|
|
|
4
4
|
export class Segment {
|
|
5
5
|
constructor(
|
|
@@ -7,18 +7,18 @@ export class Segment {
|
|
|
7
7
|
public end: Vec3,
|
|
8
8
|
) {}
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
vector() {
|
|
11
11
|
return this.end.clone().subtract(this.start)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
length() {
|
|
15
15
|
return this.start.distance(this.end)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
center() {
|
|
19
19
|
return this.start.clone()
|
|
20
20
|
.add(this.end)
|
|
21
|
-
.
|
|
21
|
+
.half()
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
clone() {
|
|
@@ -29,18 +29,20 @@ export class Segment {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
fromStart(length: number) {
|
|
32
|
-
const direction = this.vector.normalize()
|
|
32
|
+
const direction = this.vector().normalize()
|
|
33
33
|
return this.start.clone().add(direction.multiplyBy(length))
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
point(fraction: number) {
|
|
37
|
-
return this.start.clone().add(this.vector.multiplyBy(fraction))
|
|
37
|
+
return this.start.clone().add(this.vector().multiplyBy(fraction))
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
scale(fraction: number) {
|
|
41
|
-
const
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
41
|
+
const {center} = this
|
|
42
|
+
const newHalfVector = this.vector().multiplyBy(fraction / 2)
|
|
43
|
+
this.start.set(center().subtract(newHalfVector))
|
|
44
|
+
this.end.set(center().add(newHalfVector))
|
|
45
|
+
return this
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {Scalar} from "
|
|
2
|
+
import {Scalar} from "./scalar.js"
|
|
3
3
|
|
|
4
4
|
const pi = Math.PI
|
|
5
5
|
|
|
@@ -27,6 +27,9 @@ export const Turns = {
|
|
|
27
27
|
toRadians(t: number) {
|
|
28
28
|
return t * Radians.circle
|
|
29
29
|
},
|
|
30
|
+
toDegrees(t: number) {
|
|
31
|
+
return Radians.toDegrees(Turns.toRadians(t))
|
|
32
|
+
},
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export const Arcseconds = {
|
|
@@ -39,5 +42,8 @@ export const Degrees = {
|
|
|
39
42
|
toRadians(d: number) {
|
|
40
43
|
return d * (pi / 180)
|
|
41
44
|
},
|
|
45
|
+
toTurns(d: number) {
|
|
46
|
+
return Radians.toTurns(Degrees.toRadians(d))
|
|
47
|
+
},
|
|
42
48
|
}
|
|
43
49
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import {Scalar} from "./scalar.js"
|
|
3
3
|
|
|
4
|
+
const circle = 2 * Math.PI
|
|
5
|
+
|
|
4
6
|
export class Circular {
|
|
5
7
|
constructor(public x: number) {}
|
|
6
8
|
|
|
@@ -20,7 +22,7 @@ export class Circular {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
static normalize(x: number) {
|
|
23
|
-
return Scalar.wrap(x, 0,
|
|
25
|
+
return Scalar.wrap(x, 0, circle)
|
|
24
26
|
} normalize() {
|
|
25
27
|
this.x = Circular.normalize(this.x)
|
|
26
28
|
return this
|
|
@@ -30,8 +32,8 @@ export class Circular {
|
|
|
30
32
|
x = this.normalize(x)
|
|
31
33
|
y = this.normalize(y)
|
|
32
34
|
let delta = y - x
|
|
33
|
-
if (delta > Math.PI) delta -=
|
|
34
|
-
if (delta < -Math.PI) delta +=
|
|
35
|
+
if (delta > Math.PI) delta -= circle
|
|
36
|
+
if (delta < -Math.PI) delta += circle
|
|
35
37
|
return delta
|
|
36
38
|
} difference(y: number | Circular) {
|
|
37
39
|
return Circular.difference(this.x, Circular.value(y))
|
|
@@ -43,7 +43,7 @@ export class Scalar {
|
|
|
43
43
|
x += n
|
|
44
44
|
return x
|
|
45
45
|
} add(...nums: number[]) {
|
|
46
|
-
this.x = Scalar.add(...nums)
|
|
46
|
+
this.x = Scalar.add(this.x, ...nums)
|
|
47
47
|
return this
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -53,23 +53,23 @@ export class Scalar {
|
|
|
53
53
|
return this
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
static
|
|
57
|
-
return Math.max(x,
|
|
58
|
-
}
|
|
59
|
-
this.x = Scalar.
|
|
56
|
+
static atLeast(x: number, least: number = 0) {
|
|
57
|
+
return Math.max(x, least)
|
|
58
|
+
} atLeast(least: number = 0) {
|
|
59
|
+
this.x = Scalar.atLeast(this.x, least)
|
|
60
60
|
return this
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
static
|
|
64
|
-
return Math.min(x,
|
|
65
|
-
}
|
|
66
|
-
this.x = Scalar.
|
|
63
|
+
static atMost(x: number, most: number = 1) {
|
|
64
|
+
return Math.min(x, most)
|
|
65
|
+
} atMost(most: number = 1) {
|
|
66
|
+
this.x = Scalar.atMost(this.x, most)
|
|
67
67
|
return this
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
static clamp(x: number, a: number = 0, b: number = 1) {
|
|
71
|
-
x = Scalar.
|
|
72
|
-
x = Scalar.
|
|
71
|
+
x = Scalar.atLeast(x, Math.min(a, b))
|
|
72
|
+
x = Scalar.atMost(x, Math.max(a, b))
|
|
73
73
|
return x
|
|
74
74
|
} clamp(a: number = 0, b: number = 1) {
|
|
75
75
|
this.x = Scalar.clamp(this.x, a, b)
|