@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.
Files changed (90) hide show
  1. package/README.md +110 -23
  2. package/package.json +2 -1
  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 +57 -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 +37 -21
  26. package/x/core/vec2.js.map +1 -0
  27. package/x/{primitives → core}/vec3.d.ts +19 -20
  28. package/x/{primitives → core}/vec3.js +46 -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,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
 
@@ -1,38 +1,83 @@
1
1
 
2
- import {Vec3} from "../../primitives/vec3.js"
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
- public center: Vec3,
7
- public extent: Vec3,
8
- ) {
9
- if (extent.x < 0 || extent.y < 0 || extent.z < 0)
10
- throw new Error(`invalid negative extent, ${extent.toString()}`)
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, extent: 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
- get min() {
21
- return this.center.clone()
22
- .subtract(this.extent.clone().half())
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
- get max() {
26
- return this.center.clone()
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.center.clone(), this.extent.clone())
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
- grow(increase: number) {
35
- this.extent.addBy(increase)
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
  }
@@ -1,5 +1,5 @@
1
1
 
2
- import {Vec3} from "../../primitives/vec3.js"
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
- get vector() {
10
+ vector() {
11
11
  return this.end.clone().subtract(this.start)
12
12
  }
13
13
 
14
- get length() {
14
+ length() {
15
15
  return this.start.distance(this.end)
16
16
  }
17
17
 
18
- get center() {
18
+ center() {
19
19
  return this.start.clone()
20
20
  .add(this.end)
21
- .divideBy(2)
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 newHalfVector = this.vector.multiplyBy(fraction / 2)
42
- this.start.set(this.center.subtract(newHalfVector))
43
- this.end.set(this.center.add(newHalfVector))
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 "../primitives/scalar.js"
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, 2 * Math.PI)
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 -= 2 * Math.PI
34
- if (delta < -Math.PI) delta += 2 * Math.PI
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 min(x: number, minimum: number = 0) {
57
- return Math.max(x, minimum)
58
- } min(minimum: number = 0) {
59
- this.x = Scalar.min(this.x, minimum)
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 max(x: number, maximum: number = 1) {
64
- return Math.min(x, maximum)
65
- } max(maximum: number = 1) {
66
- this.x = Scalar.max(this.x, maximum)
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.min(x, Math.min(a, b))
72
- x = Scalar.max(x, Math.max(a, b))
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)