@benev/math 0.0.0-3 → 0.2.0-0

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 (118) hide show
  1. package/README.md +23 -0
  2. package/package.json +4 -3
  3. package/s/index.ts +26 -10
  4. package/s/optimizers/hash-map.ts +67 -0
  5. package/s/optimizers/hash-set.ts +46 -0
  6. package/s/optimizers/zen.ts +150 -0
  7. package/s/physics/2d/collide2d.ts +51 -0
  8. package/s/physics/2d/intersect2d.ts +77 -0
  9. package/s/shapes/2d/circle.ts +25 -0
  10. package/s/shapes/2d/edge.ts +3 -0
  11. package/s/shapes/2d/index.ts +6 -0
  12. package/s/shapes/2d/pill.ts +3 -0
  13. package/s/shapes/2d/rect.ts +45 -0
  14. package/s/shapes/3d/box.ts +39 -0
  15. package/s/shapes/3d/capsule.ts +3 -0
  16. package/s/shapes/3d/index.ts +6 -0
  17. package/s/shapes/3d/segment.ts +46 -0
  18. package/s/shapes/3d/sphere.ts +3 -0
  19. package/s/utils/angles.ts +43 -0
  20. package/s/{concepts → utils}/randy.ts +0 -14
  21. package/s/{concepts → utils}/spline.ts +2 -2
  22. package/x/index.d.ts +21 -10
  23. package/x/index.js +21 -10
  24. package/x/index.js.map +1 -1
  25. package/x/optimizers/hash-map.d.ts +16 -0
  26. package/x/optimizers/hash-map.js +52 -0
  27. package/x/optimizers/hash-map.js.map +1 -0
  28. package/x/optimizers/hash-set.d.ts +12 -0
  29. package/x/optimizers/hash-set.js +36 -0
  30. package/x/optimizers/hash-set.js.map +1 -0
  31. package/x/optimizers/zen.d.ts +32 -0
  32. package/x/optimizers/zen.js +120 -0
  33. package/x/optimizers/zen.js.map +1 -0
  34. package/x/physics/2d/collide2d.d.ts +8 -0
  35. package/x/physics/2d/collide2d.js +36 -0
  36. package/x/physics/2d/collide2d.js.map +1 -0
  37. package/x/physics/2d/intersect2d.d.ts +13 -0
  38. package/x/physics/2d/intersect2d.js +55 -0
  39. package/x/physics/2d/intersect2d.js.map +1 -0
  40. package/x/primitives/circular.js.map +1 -0
  41. package/x/primitives/quat.js.map +1 -0
  42. package/x/primitives/scalar.js.map +1 -0
  43. package/x/primitives/vec2.js.map +1 -0
  44. package/x/primitives/vec3.js.map +1 -0
  45. package/x/primitives/vec4.js.map +1 -0
  46. package/x/shapes/2d/circle.d.ts +10 -0
  47. package/x/shapes/2d/circle.js +22 -0
  48. package/x/shapes/2d/circle.js.map +1 -0
  49. package/x/shapes/2d/edge.d.ts +1 -0
  50. package/x/shapes/2d/edge.js +3 -0
  51. package/x/shapes/2d/edge.js.map +1 -0
  52. package/x/shapes/2d/index.d.ts +4 -0
  53. package/x/shapes/2d/index.js +5 -0
  54. package/x/shapes/2d/index.js.map +1 -0
  55. package/x/shapes/2d/pill.d.ts +1 -0
  56. package/x/shapes/2d/pill.js +3 -0
  57. package/x/shapes/2d/pill.js.map +1 -0
  58. package/x/shapes/2d/rect.d.ts +13 -0
  59. package/x/shapes/2d/rect.js +36 -0
  60. package/x/shapes/2d/rect.js.map +1 -0
  61. package/x/shapes/3d/box.d.ts +11 -0
  62. package/x/shapes/3d/box.js +29 -0
  63. package/x/shapes/3d/box.js.map +1 -0
  64. package/x/shapes/3d/capsule.d.ts +1 -0
  65. package/x/shapes/3d/capsule.js +3 -0
  66. package/x/shapes/3d/capsule.js.map +1 -0
  67. package/x/shapes/3d/index.d.ts +4 -0
  68. package/x/shapes/3d/index.js +5 -0
  69. package/x/shapes/3d/index.js.map +1 -0
  70. package/x/shapes/3d/segment.d.ts +13 -0
  71. package/x/shapes/3d/segment.js +35 -0
  72. package/x/shapes/3d/segment.js.map +1 -0
  73. package/x/shapes/3d/sphere.d.ts +1 -0
  74. package/x/shapes/3d/sphere.js +3 -0
  75. package/x/shapes/3d/sphere.js.map +1 -0
  76. package/x/{concepts → utils}/angles.d.ts +1 -13
  77. package/x/utils/angles.js +35 -0
  78. package/x/utils/angles.js.map +1 -0
  79. package/x/utils/noise.js.map +1 -0
  80. package/x/{concepts → utils}/randy.d.ts +0 -8
  81. package/x/{concepts → utils}/randy.js +0 -10
  82. package/x/utils/randy.js.map +1 -0
  83. package/x/{concepts → utils}/spline.d.ts +1 -1
  84. package/x/{concepts → utils}/spline.js +1 -1
  85. package/x/utils/spline.js.map +1 -0
  86. package/s/concepts/angles.ts +0 -74
  87. package/x/concepts/angles.js +0 -62
  88. package/x/concepts/angles.js.map +0 -1
  89. package/x/concepts/circular.js.map +0 -1
  90. package/x/concepts/noise.js.map +0 -1
  91. package/x/concepts/quat.js.map +0 -1
  92. package/x/concepts/randy.js.map +0 -1
  93. package/x/concepts/scalar.js.map +0 -1
  94. package/x/concepts/spline.js.map +0 -1
  95. package/x/concepts/vec2.js.map +0 -1
  96. package/x/concepts/vec3.js.map +0 -1
  97. package/x/concepts/vec4.js.map +0 -1
  98. /package/s/{concepts → primitives}/circular.ts +0 -0
  99. /package/s/{concepts → primitives}/quat.ts +0 -0
  100. /package/s/{concepts → primitives}/scalar.ts +0 -0
  101. /package/s/{concepts → primitives}/vec2.ts +0 -0
  102. /package/s/{concepts → primitives}/vec3.ts +0 -0
  103. /package/s/{concepts → primitives}/vec4.ts +0 -0
  104. /package/s/{concepts → utils}/noise.ts +0 -0
  105. /package/x/{concepts → primitives}/circular.d.ts +0 -0
  106. /package/x/{concepts → primitives}/circular.js +0 -0
  107. /package/x/{concepts → primitives}/quat.d.ts +0 -0
  108. /package/x/{concepts → primitives}/quat.js +0 -0
  109. /package/x/{concepts → primitives}/scalar.d.ts +0 -0
  110. /package/x/{concepts → primitives}/scalar.js +0 -0
  111. /package/x/{concepts → primitives}/vec2.d.ts +0 -0
  112. /package/x/{concepts → primitives}/vec2.js +0 -0
  113. /package/x/{concepts → primitives}/vec3.d.ts +0 -0
  114. /package/x/{concepts → primitives}/vec3.js +0 -0
  115. /package/x/{concepts → primitives}/vec4.d.ts +0 -0
  116. /package/x/{concepts → primitives}/vec4.js +0 -0
  117. /package/x/{concepts → utils}/noise.d.ts +0 -0
  118. /package/x/{concepts → utils}/noise.js +0 -0
package/README.md CHANGED
@@ -1,3 +1,26 @@
1
1
 
2
2
  # @benev/math
3
+ > benevolent's game math library.
4
+
5
+ ***TODO*** actual documentation coming soon.
6
+
7
+ ### numeric primitives
8
+ - [Scalar](./s/concepts/scalar.ts)
9
+ - [Vec2](./s/concepts/vec2.ts)
10
+ - [Vec3](./s/concepts/vec3.ts)
11
+ - [Vec4](./s/concepts/vec4.ts)
12
+ - [Quat](./s/concepts/quat.ts)
13
+
14
+ ### cool utilities
15
+ - [Randy](./s/concepts/randy.ts)
16
+ - [Circular](./s/concepts/circular.ts)
17
+ - [Noise](./s/concepts/noise.ts)
18
+ - [spline](./s/concepts/spline.ts)
19
+
20
+ ### angular stuff
21
+ - [angles.ts](./s/concepts/angles.ts)
22
+ - Radians
23
+ - Arcseconds
24
+ - Turns
25
+ - Degrees
3
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benev/math",
3
- "version": "0.0.0-3",
3
+ "version": "0.2.0-0",
4
4
  "description": "game math toolkit",
5
5
  "license": "MIT",
6
6
  "author": "Chase Moskal <chasemoskal@gmail.com>",
@@ -21,11 +21,12 @@
21
21
  "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +"
22
22
  },
23
23
  "dependencies": {
24
+ "@e280/stz": "^0.1.0",
24
25
  "simplex-noise": "^4.0.3"
25
26
  },
26
27
  "devDependencies": {
27
- "@e280/science": "^0.0.6",
28
- "@e280/scute": "^0.0.0-7",
28
+ "@e280/science": "^0.1.0",
29
+ "@e280/scute": "^0.0.0",
29
30
  "npm-run-all": "^4.1.5",
30
31
  "typescript": "^5.9.2"
31
32
  },
package/s/index.ts CHANGED
@@ -1,12 +1,28 @@
1
1
 
2
- export * from "./concepts/angles.js"
3
- export * from "./concepts/circular.js"
4
- export * from "./concepts/noise.js"
5
- export * from "./concepts/quat.js"
6
- export * from "./concepts/randy.js"
7
- export * from "./concepts/scalar.js"
8
- export * from "./concepts/spline.js"
9
- export * from "./concepts/vec2.js"
10
- export * from "./concepts/vec3.js"
11
- export * from "./concepts/vec4.js"
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"
8
+
9
+ export * from "./optimizers/hash-map.js"
10
+ export * from "./optimizers/hash-set.js"
11
+ export * from "./optimizers/zen.js"
12
+
13
+ export * from "./physics/2d/collide2d.js"
14
+ export * as collide2d from "./physics/2d/collide2d.js"
15
+ export * from "./physics/2d/intersect2d.js"
16
+ export * as intersect2d from "./physics/2d/intersect2d.js"
17
+
18
+ export * from "./shapes/2d/index.js"
19
+ export * as shapes2d from "./shapes/2d/index.js"
20
+
21
+ export * from "./shapes/3d/index.js"
22
+ export * as shapes3d from "./shapes/3d/index.js"
23
+
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"
12
28
 
@@ -0,0 +1,67 @@
1
+
2
+ import {MapG} from "@e280/stz"
3
+
4
+ export class HashMap<Key, Value> {
5
+ #map = new MapG<string, [Key, Value]>
6
+
7
+ constructor(
8
+ private hash: (x: Key) => string,
9
+ entries: [Key, Value][] = [],
10
+ ) {
11
+ for (const [key, value] of entries)
12
+ this.set(key, value)
13
+ }
14
+
15
+ get size() {
16
+ return this.#map.size
17
+ }
18
+
19
+ get(key: Key) {
20
+ const result = this.#map.get(this.hash(key))
21
+ if (result)
22
+ return result[1]
23
+ }
24
+
25
+ require(key: Key) {
26
+ return this.#map.require(this.hash(key))[1]
27
+ }
28
+
29
+ has(key: Key) {
30
+ return this.#map.has(this.hash(key))
31
+ }
32
+
33
+ set(key: Key, value: Value) {
34
+ this.#map.set(this.hash(key), [key, value])
35
+ return this
36
+ }
37
+
38
+ delete(...keys: Key[]) {
39
+ for (const key of keys)
40
+ this.#map.delete(this.hash(key))
41
+ return this
42
+ }
43
+
44
+ entries() {
45
+ return this.#map.values()
46
+ }
47
+
48
+ *keys() {
49
+ for (const [key] of this.#map.values())
50
+ yield key
51
+ }
52
+
53
+ *values() {
54
+ for (const [,value] of this.#map.values())
55
+ yield value
56
+ }
57
+
58
+ array() {
59
+ return [...this.entries()]
60
+ }
61
+
62
+ guarantee(key: Key, fn: () => Value) {
63
+ const [,value] = this.#map.guarantee(this.hash(key), () => [key, fn()])
64
+ return value
65
+ }
66
+ }
67
+
@@ -0,0 +1,46 @@
1
+
2
+ export class HashSet<Value> {
3
+ #map = new Map<string, Value>
4
+
5
+ constructor(
6
+ private hash: (value: Value) => string,
7
+ values: Value[] = [],
8
+ ) {
9
+ this.add(...values)
10
+ }
11
+
12
+ get size() {
13
+ return this.#map.size
14
+ }
15
+
16
+ get(value: Value) {
17
+ return this.#map.get(this.hash(value))
18
+ }
19
+
20
+ has(value: Value) {
21
+ return this.#map.has(this.hash(value))
22
+ }
23
+
24
+ add(...values: Value[]) {
25
+ for (const value of values) {
26
+ const key = this.hash(value)
27
+ this.#map.set(key, value)
28
+ }
29
+ return this
30
+ }
31
+
32
+ delete(...values: Value[]) {
33
+ for (const value of values)
34
+ this.#map.delete(this.hash(value))
35
+ return this
36
+ }
37
+
38
+ array() {
39
+ return [...this.#map.values()]
40
+ }
41
+
42
+ values() {
43
+ return this.#map.values()
44
+ }
45
+ }
46
+
@@ -0,0 +1,150 @@
1
+
2
+ import {MapG} from "@e280/stz"
3
+ import {Rect} from "../shapes/2d/rect.js"
4
+ import {Vec2} from "../primitives/vec2.js"
5
+ import {rectVsRect} from "../physics/2d/collide2d.js"
6
+
7
+ export class Zen<X> {
8
+ zones = new Set<ZenZone<X>>()
9
+
10
+ constructor(
11
+ public grid: ZenGrid<X>,
12
+ public box: Rect,
13
+ public item: X,
14
+ ) {}
15
+
16
+ update() {
17
+ this.grid.update(this)
18
+ }
19
+
20
+ delete() {
21
+ this.grid.delete(this)
22
+ }
23
+ }
24
+
25
+ export class ZenZone<X> extends Rect {
26
+ zens = new Set<Zen<X>>()
27
+
28
+ constructor(public hash: string, center: Vec2, extent: Vec2) {
29
+ super(center, extent)
30
+ }
31
+ }
32
+
33
+ export class ZenGrid<X> {
34
+ #zones = new MapG<string, ZenZone<X>>()
35
+
36
+ constructor(private zoneExtent: Vec2) {}
37
+
38
+ count() {
39
+ let n = 0
40
+ for (const zone of this.#zones.values())
41
+ n += zone.zens.size
42
+ return n
43
+ }
44
+
45
+ create(box: Rect, item: X) {
46
+ const zen = new Zen<X>(this, box, item)
47
+ this.update(zen)
48
+ return zen
49
+ }
50
+
51
+ update(zen: Zen<X>) {
52
+ const wantedZones = this.#selectZones(zen.box)
53
+
54
+ // delete stale zones
55
+ for (const zone of zen.zones) {
56
+ if (!wantedZones.has(zone)) {
57
+ zen.zones.delete(zone)
58
+ zone.zens.delete(zen)
59
+ }
60
+ }
61
+
62
+ // add fresh zones
63
+ for (const zone of wantedZones) {
64
+ if (!zen.zones.has(zone)) {
65
+ zone.zens.add(zen)
66
+ zen.zones.add(zone)
67
+ }
68
+ }
69
+ }
70
+
71
+ delete(zen: Zen<X>) {
72
+ const emptyZones: ZenZone<X>[] = []
73
+
74
+ for (const zone of zen.zones) {
75
+ zone.zens.delete(zen)
76
+ if (zone.zens.size === 0)
77
+ emptyZones.push(zone)
78
+ }
79
+
80
+ for (const emptyZone of emptyZones)
81
+ this.#zones.delete(emptyZone.hash)
82
+ }
83
+
84
+ check(box: Rect) {
85
+ const zones = this.#selectZones(box)
86
+
87
+ for (const zone of zones)
88
+ for (const zen of zone.zens)
89
+ if (rectVsRect(box, zen.box))
90
+ return true
91
+
92
+ return false
93
+ }
94
+
95
+ /** return all zens that touch the given box */
96
+ query(box: Rect) {
97
+ const zones = this.#selectZones(box)
98
+ const selected: Zen<X>[] = []
99
+
100
+ for (const zone of zones)
101
+ for (const zen of zone.zens)
102
+ if (rectVsRect(box, zen.box) && !selected.includes(zen))
103
+ selected.push(zen)
104
+
105
+ return selected
106
+ }
107
+
108
+ /** return all zen items that touch the given box */
109
+ queryItems(box: Rect) {
110
+ return this.query(box).map(zen => zen.item)
111
+ }
112
+
113
+ /** return all zen boxes that touch the given box */
114
+ queryBoxes(box: Rect) {
115
+ return this.query(box).map(zen => zen.box)
116
+ }
117
+
118
+ #hash(v: Vec2) {
119
+ return `${v.x},${v.y}`
120
+ }
121
+
122
+ #calculateZoneCorner(point: Vec2) {
123
+ return new Vec2(
124
+ Math.floor(point.x / this.zoneExtent.x),
125
+ Math.floor(point.y / this.zoneExtent.y),
126
+ ).multiply(this.zoneExtent)
127
+ }
128
+
129
+ #obtainZone(zoneCorner: Vec2) {
130
+ const hash = this.#hash(zoneCorner)
131
+ return this.#zones.guarantee(hash, () => new ZenZone(
132
+ hash,
133
+ zoneCorner.clone().add(this.zoneExtent.clone().half()),
134
+ this.zoneExtent,
135
+ ))
136
+ }
137
+
138
+ #selectZones(box: Rect) {
139
+ const zones = new Set<ZenZone<X>>()
140
+ const minZoneCorner = this.#calculateZoneCorner(box.min)
141
+ const maxZoneCorner = this.#calculateZoneCorner(box.max)
142
+
143
+ for (let x = minZoneCorner.x; x <= maxZoneCorner.x; x += this.zoneExtent.x)
144
+ for (let y = minZoneCorner.y; y <= maxZoneCorner.y; y += this.zoneExtent.y)
145
+ zones.add(this.#obtainZone(new Vec2(x, y)))
146
+
147
+ return zones
148
+ }
149
+ }
150
+
@@ -0,0 +1,51 @@
1
+
2
+ import {Vec2} from "../../primitives/vec2.js"
3
+ import {Rect} from "../../shapes/2d/rect.js"
4
+ import {Scalar} from "../../primitives/scalar.js"
5
+ import {Circle} from "../../shapes/2d/circle.js"
6
+
7
+ export function pointVsRect(point: Vec2, box: Rect) {
8
+ const {min, max} = box
9
+ return (
10
+ point.x >= min.x &&
11
+ point.x <= max.x &&
12
+ point.y >= min.y &&
13
+ point.y <= max.y
14
+ )
15
+ }
16
+
17
+ export function pointVsCircle(point: Vec2, circle: Circle) {
18
+ const dx = point.x - circle.center.x
19
+ const dy = point.y - circle.center.y
20
+ const distanceSquared = (dx ** 2) + (dy ** 2)
21
+ return distanceSquared <= (circle.radius ** 2)
22
+ }
23
+
24
+ export function rectVsRect(a: Rect, b: Rect) {
25
+ return !(
26
+ a.max.x <= b.min.x ||
27
+ a.min.x >= b.max.x ||
28
+ a.max.y <= b.min.y ||
29
+ a.min.y >= b.max.y
30
+ )
31
+ }
32
+
33
+ export function rectVsCircle(rect: Rect, circle: Circle) {
34
+ const clamped = new Vec2(
35
+ Scalar.clamp(circle.center.x, rect.min.x, rect.max.x),
36
+ Scalar.clamp(circle.center.y, rect.min.y, rect.max.y),
37
+ )
38
+ const difference = circle.center.clone().subtract(clamped)
39
+ const distanceSquared = (difference.x ** 2) + (difference.y ** 2)
40
+ const radiusSquared = circle.radius ** 2
41
+ return distanceSquared <= radiusSquared
42
+ }
43
+
44
+ export function circleVsCircle(circleA: Circle, circleB: Circle) {
45
+ const dx = circleB.center.x - circleA.center.x
46
+ const dy = circleB.center.y - circleA.center.y
47
+ const distanceSquared = (dx ** 2) + (dy ** 2)
48
+ const radiusSum = circleA.radius + circleB.radius
49
+ return distanceSquared <= (radiusSum ** 2)
50
+ }
51
+
@@ -0,0 +1,77 @@
1
+
2
+ import {Vec2} from "../../primitives/vec2.js"
3
+ import {Rect} from "../../shapes/2d/rect.js"
4
+ import {Scalar} from "../../primitives/scalar.js"
5
+ import {Circle} from "../../shapes/2d/circle.js"
6
+ import {rectVsCircle, rectVsRect} from "./collide2d.js"
7
+
8
+ export class Intersection {
9
+ constructor(
10
+ public contactPoint: Vec2,
11
+ public depth: number,
12
+ public normalA: Vec2,
13
+ public normalB: Vec2,
14
+ ) {}
15
+ }
16
+
17
+ export function intersectRectVsRect(a: Rect, b: Rect) {
18
+ if (!rectVsRect(a, b)) return null
19
+
20
+ const overlapX = Math.min(a.max.x - b.min.x, b.max.x - a.min.x)
21
+ const overlapY = Math.min(a.max.y - b.min.y, b.max.y - a.min.y)
22
+ const depth = Math.min(overlapX, overlapY)
23
+
24
+ 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)
27
+ )
28
+
29
+ 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)
32
+
33
+ const normalB = normalA.clone().multiplyBy(-1)
34
+
35
+ return new Intersection(contactPoint, depth, normalA, normalB)
36
+ }
37
+
38
+ export function intersectRectVsCircle(rect: Rect, circle: Circle) {
39
+ if (!rectVsCircle(rect, circle)) return null
40
+
41
+ const clamped = new Vec2(
42
+ Scalar.clamp(circle.center.x, rect.min.x, rect.max.x),
43
+ Scalar.clamp(circle.center.y, rect.min.y, rect.max.y),
44
+ )
45
+ const difference = circle.center.clone().subtract(clamped)
46
+ const distance = difference.magnitude()
47
+ const depth = circle.radius - distance
48
+
49
+ const contactPoint = clamped
50
+ const normalA = difference.normalize()
51
+ const normalB = normalA.clone().multiplyBy(-1)
52
+
53
+ return new Intersection(contactPoint, depth, normalA, normalB)
54
+ }
55
+
56
+ export function intersectCircleVsCircle(a: Circle, b: Circle) {
57
+ const dx = b.center.x - a.center.x
58
+ const dy = b.center.y - a.center.y
59
+ const distance = Math.sqrt(dx ** 2 + dy ** 2)
60
+ if (distance >= a.radius + b.radius) return null
61
+
62
+ const depth = Math.max(0, a.radius + b.radius - distance)
63
+
64
+ const normalA = distance === 0
65
+ ? new Vec2(1, 0) // fallback for perfectly overlapping circles
66
+ : new Vec2(dx / distance, dy / distance)
67
+
68
+ const normalB = normalA.clone().multiplyBy(-1)
69
+
70
+ const contactPoint = new Vec2(
71
+ (a.center.x + b.center.x) / 2,
72
+ (a.center.y + b.center.y) / 2
73
+ )
74
+
75
+ return new Intersection(contactPoint, depth, normalA, normalB)
76
+ }
77
+
@@ -0,0 +1,25 @@
1
+
2
+ import {Rect} from "./rect.js"
3
+ import {Vec2} from "../../primitives/vec2.js"
4
+
5
+ export class Circle {
6
+ constructor(
7
+ public center: Vec2,
8
+ public radius: number,
9
+ ) {}
10
+
11
+ offset(delta: Vec2) {
12
+ this.center.add(delta)
13
+ return this
14
+ }
15
+
16
+ boundingBox() {
17
+ const extent = Vec2.all(this.radius * 2)
18
+ return new Rect(this.center, extent)
19
+ }
20
+
21
+ clone() {
22
+ return new Circle(this.center.clone(), this.radius)
23
+ }
24
+ }
25
+
@@ -0,0 +1,3 @@
1
+
2
+ // TODO
3
+
@@ -0,0 +1,6 @@
1
+
2
+ export * from "./circle.js"
3
+ export * from "./edge.js"
4
+ export * from "./pill.js"
5
+ export * from "./rect.js"
6
+
@@ -0,0 +1,3 @@
1
+
2
+ // TODO
3
+
@@ -0,0 +1,45 @@
1
+
2
+ import {Vec2} from "../../primitives/vec2.js"
3
+ import {pointVsRect} from "../../physics/2d/collide2d.js"
4
+
5
+ export class Rect {
6
+ 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()}`)
12
+ }
13
+
14
+ static fromCorner(min: Vec2, extent: Vec2) {
15
+ return new this(min.add(extent.clone().half()), extent)
16
+ }
17
+
18
+ get min() {
19
+ return this.center.clone()
20
+ .subtract(this.extent.clone().half())
21
+ }
22
+
23
+ get max() {
24
+ return this.center.clone()
25
+ .add(this.extent.clone().half())
26
+ }
27
+
28
+ offset(delta: Vec2) {
29
+ this.center.add(delta)
30
+ return this
31
+ }
32
+
33
+ boundingBox() {
34
+ return this
35
+ }
36
+
37
+ contains(point: Vec2) {
38
+ return pointVsRect(point, this)
39
+ }
40
+
41
+ clone() {
42
+ return new Rect(this.center.clone(), this.extent.clone())
43
+ }
44
+ }
45
+
@@ -0,0 +1,39 @@
1
+
2
+ import {Vec3} from "../../primitives/vec3.js"
3
+
4
+ export class Box {
5
+ 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()}`)
11
+ }
12
+
13
+ static fromCorner(min: Vec3, extent: Vec3) {
14
+ return new this(
15
+ min.clone().add(extent.clone().half()),
16
+ extent,
17
+ )
18
+ }
19
+
20
+ get min() {
21
+ return this.center.clone()
22
+ .subtract(this.extent.clone().half())
23
+ }
24
+
25
+ get max() {
26
+ return this.center.clone()
27
+ .add(this.extent.clone().half())
28
+ }
29
+
30
+ clone() {
31
+ return new Box(this.center.clone(), this.extent.clone())
32
+ }
33
+
34
+ grow(increase: number) {
35
+ this.extent.addBy(increase)
36
+ return this
37
+ }
38
+ }
39
+
@@ -0,0 +1,3 @@
1
+
2
+ // TODO
3
+
@@ -0,0 +1,6 @@
1
+
2
+ export * from "./box.js"
3
+ export * from "./capsule.js"
4
+ export * from "./segment.js"
5
+ export * from "./sphere.js"
6
+
@@ -0,0 +1,46 @@
1
+
2
+ import {Vec3} from "../../primitives/vec3.js"
3
+
4
+ export class Segment {
5
+ constructor(
6
+ public start: Vec3,
7
+ public end: Vec3,
8
+ ) {}
9
+
10
+ get vector() {
11
+ return this.end.clone().subtract(this.start)
12
+ }
13
+
14
+ get length() {
15
+ return this.start.distance(this.end)
16
+ }
17
+
18
+ get center() {
19
+ return this.start.clone()
20
+ .add(this.end)
21
+ .divideBy(2)
22
+ }
23
+
24
+ clone() {
25
+ return new Segment(
26
+ this.start.clone(),
27
+ this.end.clone(),
28
+ )
29
+ }
30
+
31
+ fromStart(length: number) {
32
+ const direction = this.vector.normalize()
33
+ return this.start.clone().add(direction.multiplyBy(length))
34
+ }
35
+
36
+ point(fraction: number) {
37
+ return this.start.clone().add(this.vector.multiplyBy(fraction))
38
+ }
39
+
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))
44
+ }
45
+ }
46
+
@@ -0,0 +1,3 @@
1
+
2
+ // TODO
3
+