@gitborlando/geo 4.1.1 → 5.1.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.
package/src/aabb.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { max, min } from './math'
2
1
  import { OBB } from './obb'
3
- import { IRectWithCenter } from './types'
2
+ import { IRect, IRectWithCenter, IXY } from './types'
4
3
  import { XY } from './xy'
5
4
 
6
5
  export class AABB {
@@ -31,6 +30,32 @@ export class AABB {
31
30
  ] as const
32
31
  }
33
32
 
33
+ static update(aabb: AABB, minX: number, minY: number, maxX: number, maxY: number) {
34
+ aabb.minX = minX
35
+ aabb.minY = minY
36
+ aabb.maxX = maxX
37
+ aabb.maxY = maxY
38
+ return aabb
39
+ }
40
+
41
+ static updateFromRect(aabb: AABB, rect: IRect) {
42
+ return AABB.update(
43
+ aabb,
44
+ rect.x,
45
+ rect.y,
46
+ rect.x + rect.width,
47
+ rect.y + rect.height,
48
+ )
49
+ }
50
+
51
+ static shift(aabb: AABB, delta: IXY) {
52
+ aabb.minX += delta.x
53
+ aabb.minY += delta.y
54
+ aabb.maxX += delta.x
55
+ aabb.maxY += delta.y
56
+ return aabb
57
+ }
58
+
34
59
  static collide(one: AABB, another: AABB): boolean {
35
60
  return (
36
61
  one.minX <= another.maxX &&
@@ -74,20 +99,29 @@ export class AABB {
74
99
  }
75
100
  }
76
101
 
77
- static merge(...aabbList: AABB[]) {
78
- let [xMin, yMin, xMax, yMax] = [Infinity, Infinity, -Infinity, -Infinity]
79
- aabbList.forEach((aabb) => {
80
- xMin = min(xMin, aabb.minX)
81
- yMin = min(yMin, aabb.minY)
82
- xMax = max(xMax, aabb.maxX)
83
- yMax = max(yMax, aabb.maxY)
84
- })
102
+ static merge(aabbList: AABB[] | Set<AABB>) {
103
+ if (Array.isArray(aabbList)) {
104
+ if (aabbList.length === 0) return new AABB(0, 0, 0, 0)
105
+ } else {
106
+ if (aabbList.size === 0) return new AABB(0, 0, 0, 0)
107
+ }
108
+
109
+ let xMin = Infinity,
110
+ yMin = Infinity,
111
+ xMax = -Infinity,
112
+ yMax = -Infinity
113
+ for (const aabb of aabbList) {
114
+ xMin = Math.min(xMin, aabb.minX)
115
+ yMin = Math.min(yMin, aabb.minY)
116
+ xMax = Math.max(xMax, aabb.maxX)
117
+ yMax = Math.max(yMax, aabb.maxY)
118
+ }
85
119
  return new AABB(xMin, yMin, xMax, yMax)
86
120
  }
87
121
 
88
122
  static fromOBB(obb: OBB) {
89
- const width = obb.projectionLengthAt(XY._(1, 0))
90
- const height = obb.projectionLengthAt(XY._(0, 1))
123
+ const width = obb.projectAt(XY.$(1, 0))
124
+ const height = obb.projectAt(XY.$(0, 1))
91
125
  return new AABB(
92
126
  obb.center.x - width / 2,
93
127
  obb.center.y - height / 2,
@@ -95,4 +129,14 @@ export class AABB {
95
129
  obb.center.y + height / 2,
96
130
  )
97
131
  }
132
+
133
+ static updateFromOBB(aabb: AABB, obb: OBB) {
134
+ const width = obb.projectAt(XY.$(1, 0))
135
+ const height = obb.projectAt(XY.$(0, 1))
136
+ aabb.minX = obb.center.x - width / 2
137
+ aabb.minY = obb.center.y - height / 2
138
+ aabb.maxX = obb.center.x + width / 2
139
+ aabb.maxY = obb.center.y + height / 2
140
+ return aabb
141
+ }
98
142
  }
package/src/angle.ts CHANGED
@@ -1,32 +1,26 @@
1
- export const { PI, cos, sin, tan, acos, asin, atan, atan2 } = Math
1
+ import { IXY } from './types'
2
+ import { XY } from './xy'
2
3
 
3
4
  export class Angle {
4
5
  static cos(angle: number) {
5
- return cos(Angle.radianFy(angle))
6
+ return Math.cos(Angle.radianFy(angle))
6
7
  }
7
8
 
8
9
  static sin(angle: number) {
9
- return sin(Angle.radianFy(angle))
10
+ return Math.sin(Angle.radianFy(angle))
10
11
  }
11
12
 
12
- static tan(angle: number) {
13
- return tan(Angle.radianFy(angle))
14
- }
15
-
16
- static acos(angle: number) {
17
- return Angle.angleFy(acos(Angle.radianFy(angle)))
18
- }
19
-
20
- static asin(angle: number) {
21
- return Angle.angleFy(asin(Angle.radianFy(angle)))
13
+ static cosSin(angle: number) {
14
+ const radians = Angle.radianFy(angle)
15
+ return { cos: Math.cos(radians), sin: Math.sin(radians) }
22
16
  }
23
17
 
24
- static atan(angle: number) {
25
- return Angle.angleFy(atan(Angle.radianFy(angle)))
18
+ static tan(angle: number) {
19
+ return Math.tan(Angle.radianFy(angle))
26
20
  }
27
21
 
28
22
  static atan2(y: number, x: number) {
29
- return Angle.angleFy(atan2(y, x))
23
+ return Angle.angleFy(Math.atan2(y, x))
30
24
  }
31
25
 
32
26
  static angleFy(radians: number) {
@@ -38,18 +32,20 @@ export class Angle {
38
32
  }
39
33
 
40
34
  static normal(angle: number) {
41
- return (angle + 360) % 360
35
+ return ((angle % 360) + 360) % 360
36
+ }
37
+
38
+ static minor(angle: number) {
39
+ return Math.min(angle, 360 - angle)
42
40
  }
43
41
 
44
42
  static snap(angle: number, step = 90) {
45
43
  return Angle.normal(Math.round(angle / step) * step)
46
44
  }
47
45
 
48
- static rotatePoint(ax: number, ay: number, ox: number, oy: number, angle: number) {
49
- const radian = Angle.radianFy(angle)
50
- return {
51
- x: (ax - ox) * cos(radian) - (ay - oy) * sin(radian) + ox,
52
- y: (ax - ox) * sin(radian) + (ay - oy) * cos(radian) + oy,
53
- }
46
+ static sweep(v1: IXY, v2: IXY = XY.xAxis(), clockwise = false) {
47
+ const dot = v1.x * v2.x + v1.y * v2.y
48
+ const det = v1.x * v2.y - v1.y * v2.x
49
+ return Angle.normal(Angle.atan2(det, dot) * (clockwise ? 1 : -1))
54
50
  }
55
51
  }
package/src/index.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  export * from './aabb'
2
2
  export * from './angle'
3
- export * from './math'
4
- export * from './matrix'
3
+ export * from './misc'
5
4
  export * from './obb'
6
- export * from './points-of-bezier'
7
5
  export * from './types'
8
6
  export * from './xy'
package/src/misc.ts ADDED
@@ -0,0 +1,7 @@
1
+ export function twoDecimal(number: number) {
2
+ return Number(number.toFixed(Number.isInteger(number) ? 0 : 2))
3
+ }
4
+
5
+ export function minMax(val: number, min: number, max: number) {
6
+ return Math.min(Math.max(val, min), max)
7
+ }
package/src/obb.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AABB } from './aabb'
2
2
  import { Angle } from './angle'
3
3
  import { IRect, IXY } from './types'
4
- import { XY, xy_, xy_dot, xy_minus, xy_rotate } from './xy'
4
+ import { XY } from './xy'
5
5
 
6
6
  type IAxis = { widthAxis: IXY; heightAxis: IXY }
7
7
 
@@ -25,19 +25,18 @@ export class OBB {
25
25
  }
26
26
 
27
27
  get xy() {
28
- return xy_(this.x, this.y)
28
+ return XY.$(this.x, this.y)
29
29
  }
30
30
 
31
31
  #calcCenter = () => {
32
- const center = xy_(this.x + this.width / 2, this.y + this.height / 2)
33
- return xy_rotate(center, xy_(this.x, this.y), this.rotation)
32
+ const center = XY.center(this)
33
+ return center.rotate(this.xy, this.rotation)
34
34
  }
35
35
 
36
36
  #calcAxis = () => {
37
- const cos = Angle.cos(this.rotation)
38
- const sin = Angle.sin(this.rotation)
39
- const widthAxis = xy_(cos, -sin)
40
- const heightAxis = xy_(sin, cos)
37
+ const { cos, sin } = Angle.cosSin(this.rotation)
38
+ const widthAxis = XY.$(cos, -sin)
39
+ const heightAxis = XY.$(sin, cos)
41
40
  return (this.axis = { widthAxis, heightAxis })
42
41
  }
43
42
 
@@ -48,10 +47,10 @@ export class OBB {
48
47
  const sinWidth = sin * this.width
49
48
  const cosHeight = cos * this.height
50
49
  const sinHeight = sin * this.height
51
- const TL = xy_(this.x, this.y)
52
- const TR = xy_(this.x + cosWidth, this.y + sinWidth)
53
- const BR = xy_(this.x + cosWidth - sinHeight, this.y + sinWidth + cosHeight)
54
- const BL = xy_(this.x - sinHeight, this.y + cosHeight)
50
+ const TL = XY.$(this.x, this.y)
51
+ const TR = XY.$(this.x + cosWidth, this.y + sinWidth)
52
+ const BR = XY.$(this.x + cosWidth - sinHeight, this.y + sinWidth + cosHeight)
53
+ const BL = XY.$(this.x - sinHeight, this.y + cosHeight)
55
54
  return (this.vertexes = [TL, TR, BR, BL])
56
55
  }
57
56
 
@@ -59,34 +58,34 @@ export class OBB {
59
58
  return new OBB(this.x, this.y, this.width, this.height, this.rotation)
60
59
  }
61
60
 
62
- projectionLengthAt = (anotherAxis: IXY) => {
61
+ projectAt = (anotherAxis: IXY) => {
63
62
  const { widthAxis, heightAxis } = this.axis
64
63
  return (
65
- Math.abs(xy_dot(widthAxis, anotherAxis)) * this.width +
66
- Math.abs(xy_dot(heightAxis, anotherAxis)) * this.height
64
+ Math.abs(XY.dot(widthAxis, anotherAxis)) * this.width +
65
+ Math.abs(XY.dot(heightAxis, anotherAxis)) * this.height
67
66
  )
68
67
  }
69
68
 
70
69
  collide = (another: OBB) => {
71
- const centerVector = xy_minus(this.center, another.center)
70
+ const centerVector = XY.vector(this.center, another.center)
72
71
  if (
73
- this.projectionLengthAt(another.axis.widthAxis) + another.width <=
74
- 2 * Math.abs(xy_dot(centerVector, another.axis.widthAxis))
72
+ this.projectAt(another.axis.widthAxis) + another.width <=
73
+ 2 * Math.abs(XY.dot(centerVector, another.axis.widthAxis))
75
74
  )
76
75
  return false
77
76
  if (
78
- this.projectionLengthAt(another.axis.heightAxis) + another.height <=
79
- 2 * Math.abs(xy_dot(centerVector, another.axis.heightAxis))
77
+ this.projectAt(another.axis.heightAxis) + another.height <=
78
+ 2 * Math.abs(XY.dot(centerVector, another.axis.heightAxis))
80
79
  )
81
80
  return false
82
81
  if (
83
- another.projectionLengthAt(this.axis.widthAxis) + this.width <=
84
- 2 * Math.abs(xy_dot(centerVector, this.axis.widthAxis))
82
+ another.projectAt(this.axis.widthAxis) + this.width <=
83
+ 2 * Math.abs(XY.dot(centerVector, this.axis.widthAxis))
85
84
  )
86
85
  return false
87
86
  if (
88
- another.projectionLengthAt(this.axis.heightAxis) + this.height <=
89
- 2 * Math.abs(xy_dot(centerVector, this.axis.heightAxis))
87
+ another.projectAt(this.axis.heightAxis) + this.height <=
88
+ 2 * Math.abs(XY.dot(centerVector, this.axis.heightAxis))
90
89
  )
91
90
  return false
92
91
  return true
@@ -104,7 +103,7 @@ export class OBB {
104
103
  static fromCenter(center: IXY, width: number, height: number, rotation = 0) {
105
104
  const dx = center.x - width / 2
106
105
  const dy = center.y - height / 2
107
- const xy = XY.of(dx, dy).rotate(center, rotation)
106
+ const xy = XY.from(dx, dy).rotate(center, rotation)
108
107
  return new OBB(xy.x, xy.y, width, height, rotation)
109
108
  }
110
109
 
package/src/xy.ts CHANGED
@@ -1,108 +1,13 @@
1
1
  import { Angle } from './angle'
2
- import { sqrt } from './math'
3
2
  import { IXY } from './types'
4
3
 
5
- export function xy_(x: number = 0, y: number = 0) {
6
- return { x, y }
7
- }
8
-
9
- export function xy_client(e: any) {
10
- return { x: e.clientX, y: e.clientY }
11
- }
12
-
13
- export function xy_from(xy: IXY) {
14
- return { x: xy.x, y: xy.y }
15
- }
16
-
17
- export function xy_center(xy: { centerX: number; centerY: number }) {
18
- return { x: xy.centerX, y: xy.centerY }
19
- }
20
-
21
- export function xy_mutate(self: IXY, another: IXY) {
22
- self.x = another.x
23
- self.y = another.y
24
- }
25
-
26
- export function xy_plus(self: IXY, another: IXY) {
27
- return { x: self.x + another.x, y: self.y + another.y }
28
- }
29
- export function xy_plus_mutate(self: IXY, another: IXY) {
30
- self.x = self.x + another.x
31
- self.y = self.y + another.y
32
- }
33
- export function xy_plus_all(...xys: IXY[]) {
34
- return xys.reduce((a, b) => xy_plus(a, b))
35
- }
36
-
37
- export function xy_minus(self: IXY, another: IXY) {
38
- return { x: self.x - another.x, y: self.y - another.y }
39
- }
40
- export function xy_minus_mutate(self: IXY, another: IXY) {
41
- self.x = self.x - another.x
42
- self.y = self.y - another.y
43
- }
44
-
45
- export function xy_multiply(self: IXY, ...numbers: number[]) {
46
- const n = numbers.reduce((a, b) => a * b, 1)
47
- return { x: self.x * n, y: self.y * n }
48
- }
49
- export function xy_multiply_mutate(self: IXY, ...numbers: number[]) {
50
- const n = numbers.reduce((a, b) => a * b, 1)
51
- self.x = self.x * n
52
- self.y = self.y * n
53
- }
54
-
55
- export function xy_divide(self: IXY, ...numbers: number[]) {
56
- const n = numbers.reduce((a, b) => a * b, 1)
57
- return { x: self.x / n, y: self.y / n }
58
- }
59
-
60
- export function xy_distance(self: IXY, another: IXY = xy_(0, 0)) {
61
- return Math.sqrt((self.x - another.x) ** 2 + (self.y - another.y) ** 2)
62
- }
63
-
64
- export function xy_rotate(self: IXY, origin: IXY, rotation: number) {
65
- if (rotation === 0) return self
66
- return Angle.rotatePoint(self.x, self.y, origin.x, origin.y, rotation)
67
- }
68
-
69
- export function xy_dot(self: IXY, another: IXY) {
70
- return self.x * another.x + self.y * another.y
71
- }
72
-
73
- export function xy_symmetric(self: IXY, origin: IXY) {
74
- return { x: 2 * origin.x - self.x, y: 2 * origin.y - self.y }
75
- }
76
-
77
- export function xy_opposite(self: IXY) {
78
- return { x: -self.x, y: -self.y }
79
- }
80
-
81
- export function xy_getRotation(self: IXY, another: IXY, origin: IXY) {
82
- return Angle.angleFy(
83
- Math.atan2(self.y - origin.y, self.x - origin.x) -
84
- Math.atan2(another.y - origin.y, another.x - origin.x),
85
- )
86
- }
87
-
88
- export function xy_toArray(self: IXY) {
89
- return [self.x, self.y] as [number, number]
90
- }
91
-
92
- export function xy_xAxis(rotation: number) {
93
- return { x: Angle.cos(rotation), y: Angle.sin(rotation) }
94
- }
95
-
96
- export function xy_yAxis(rotation: number) {
97
- return { x: -Angle.sin(rotation), y: Angle.cos(rotation) }
98
- }
99
-
100
4
  export class XY {
101
5
  constructor(
102
6
  public x: number,
103
7
  public y: number,
104
8
  ) {}
105
- plain() {
9
+
10
+ $() {
106
11
  return { x: this.x, y: this.y }
107
12
  }
108
13
 
@@ -111,91 +16,107 @@ export class XY {
111
16
  }
112
17
 
113
18
  plus(...others: IXY[]) {
114
- const x = others.reduce((sum, cur) => sum + cur.x, this.x)
115
- const y = others.reduce((sum, cur) => sum + cur.y, this.y)
116
- return XY.of(x, y)
19
+ this.x = others.reduce((sum, cur) => sum + cur.x, this.x)
20
+ this.y = others.reduce((sum, cur) => sum + cur.y, this.y)
21
+ return this
22
+ }
23
+
24
+ plusNum(num: number) {
25
+ this.x += num
26
+ this.y += num
27
+ return this
117
28
  }
118
29
 
119
30
  minus(...others: IXY[]) {
120
- const x = others.reduce((sum, cur) => sum - cur.x, this.x)
121
- const y = others.reduce((sum, cur) => sum - cur.y, this.y)
122
- return XY.of(x, y)
31
+ this.x = others.reduce((sum, cur) => sum - cur.x, this.x)
32
+ this.y = others.reduce((sum, cur) => sum - cur.y, this.y)
33
+ return this
123
34
  }
124
35
 
125
36
  multiply(...numbers: number[]) {
126
37
  const n = numbers.reduce((a, b) => a * b, 1)
127
- return XY.of(this.x * n, this.y * n)
38
+ this.x *= n
39
+ this.y *= n
40
+ return this
41
+ }
42
+
43
+ multiplyNum(num: number) {
44
+ this.x *= num
45
+ this.y *= num
46
+ return this
128
47
  }
129
48
 
130
49
  divide(...numbers: number[]) {
131
50
  const n = numbers.reduce((a, b) => a * b, 1)
132
- return XY.of(this.x / n, this.y / n)
51
+ this.x /= n
52
+ this.y /= n
53
+ return this
133
54
  }
134
55
 
135
56
  rotate(origin: IXY, rotation: number) {
136
- if (rotation === 0) return XY.from(this)
137
- return XY.from(Angle.rotatePoint(this.x, this.y, origin.x, origin.y, rotation))
138
- }
139
-
140
- symmetric(origin: IXY) {
141
- return XY.of(2 * origin.x - this.x, 2 * origin.y - this.y)
57
+ const { cos, sin } = Angle.cosSin(rotation)
58
+ const dx = this.x - origin.x
59
+ const dy = this.y - origin.y
60
+ this.x = dx * cos - dy * sin + origin.x
61
+ this.y = dx * sin + dy * cos + origin.y
62
+ return this
142
63
  }
143
64
 
144
- ratio(another: IXY, t: number) {
145
- const x = this.x + (another.x - this.x) * t
146
- const y = this.y + (another.y - this.y) * t
147
- return XY.of(x, y)
65
+ static $(x = 0, y = 0) {
66
+ return { x, y }
148
67
  }
149
68
 
150
- getDot(another: IXY) {
151
- return this.x * another.x + this.y * another.y
69
+ static of(xy: IXY) {
70
+ return new XY(xy.x, xy.y)
152
71
  }
153
72
 
154
- getDistance(another: IXY) {
155
- return sqrt((this.x - another.x) ** 2 + (this.y - another.y) ** 2)
73
+ static from(x: number, y: number) {
74
+ return new XY(x, y)
156
75
  }
157
76
 
158
- getAngle(another: IXY, origin: IXY) {
159
- return Angle.angleFy(
160
- Math.atan2(this.y - origin.y, this.x - origin.x) -
161
- Math.atan2(another.y - origin.y, another.x - origin.x),
162
- )
77
+ static center(wh: { width: number; height: number }) {
78
+ return new XY(wh.width / 2, wh.height / 2)
163
79
  }
164
80
 
165
- static _(x: number = 0, y: number = 0) {
166
- return { x, y }
81
+ static leftTop(e: { left: number; top: number }) {
82
+ return new XY(e.left, e.top)
167
83
  }
168
84
 
169
- static of(x: number, y: number) {
170
- return new XY(x, y)
85
+ static client(e: { clientX: number; clientY: number }) {
86
+ return new XY(e.clientX, e.clientY)
171
87
  }
172
88
 
173
- static from(xy: IXY) {
174
- if (xy instanceof XY) return xy
175
- return XY.of(xy.x, xy.y)
89
+ static xAxis(rotation: number = 0) {
90
+ const { cos, sin } = Angle.cosSin(rotation)
91
+ return new XY(cos, sin)
176
92
  }
177
93
 
178
- static center(xy: { centerX: number; centerY: number }) {
179
- return XY.of(xy.centerX, xy.centerY)
94
+ static yAxis(rotation: number = 0) {
95
+ const { cos, sin } = Angle.cosSin(rotation)
96
+ return new XY(-sin, cos)
180
97
  }
181
98
 
182
- static leftTop(e: { left: number; top: number }) {
183
- return XY.of(e.left, e.top)
99
+ static dot(self: IXY, another: IXY) {
100
+ return self.x * another.x + self.y * another.y
184
101
  }
185
102
 
186
- static client(e: { clientX: number; clientY: number }) {
187
- return XY.of(e.clientX, e.clientY)
103
+ static distance(self: IXY, another: IXY) {
104
+ return Math.hypot(self.x - another.x, self.y - another.y)
188
105
  }
189
106
 
190
- static tuple(arr: [number, number]) {
191
- return XY.of(arr[0], arr[1])
107
+ static vector(self: IXY, another: IXY) {
108
+ return new XY(self.x - another.x, self.y - another.y)
192
109
  }
193
110
 
194
- static xAxis(rotation: number) {
195
- return XY.of(Angle.cos(rotation), Angle.sin(rotation))
111
+ static symmetric(self: IXY, origin = XY.$()) {
112
+ return new XY(2 * origin.x - self.x, 2 * origin.y - self.y)
196
113
  }
197
114
 
198
- static yAxis(rotation: number) {
199
- return XY.of(-Angle.sin(rotation), Angle.cos(rotation))
115
+ static lerp(self: IXY, origin: IXY, t: number) {
116
+ const distance = XY.distance(self, origin)
117
+ return new XY(
118
+ self.x + (self.x - origin.x) * (t / distance),
119
+ self.y + (self.y - origin.y) * (t / distance),
120
+ )
200
121
  }
201
122
  }
@@ -1,84 +0,0 @@
1
- // 测试轴对齐包围盒功能
2
-
3
- import { describe, expect, it } from 'vitest'
4
- import { AABB } from '../aabb'
5
- import { OBB } from '../obb'
6
-
7
- describe('AABB', () => {
8
- it('should create AABB correctly', () => {
9
- const aabb = new AABB(0, 0, 10, 10)
10
- expect(aabb.minX).toBe(0)
11
- expect(aabb.minY).toBe(0)
12
- expect(aabb.maxX).toBe(10)
13
- expect(aabb.maxY).toBe(10)
14
- })
15
-
16
- it('should convert to rect correctly', () => {
17
- const aabb = new AABB(5, 10, 15, 25)
18
- const rect = AABB.rect(aabb)
19
- expect(rect.x).toBe(5)
20
- expect(rect.y).toBe(10)
21
- expect(rect.width).toBe(10)
22
- expect(rect.height).toBe(15)
23
- expect(rect.centerX).toBe(10)
24
- expect(rect.centerY).toBe(17.5)
25
- })
26
-
27
- it('should detect collision correctly', () => {
28
- const aabb1 = new AABB(0, 0, 10, 10)
29
- const aabb2 = new AABB(5, 5, 15, 15)
30
- const aabb3 = new AABB(20, 20, 30, 30)
31
-
32
- expect(AABB.collide(aabb1, aabb2)).toBe(true)
33
- expect(AABB.collide(aabb1, aabb3)).toBe(false)
34
- })
35
-
36
- it('should detect inclusion correctly', () => {
37
- const large = new AABB(0, 0, 20, 20)
38
- const small = new AABB(5, 5, 15, 15)
39
- const outside = new AABB(25, 25, 35, 35)
40
-
41
- expect(AABB.include(large, small)).toBe(1) // large包含small
42
- expect(AABB.include(small, large)).toBe(0) // small被large包含
43
- expect(AABB.include(large, outside)).toBe(-1) // 不包含
44
- })
45
-
46
- it('should expand correctly with single value', () => {
47
- const aabb = new AABB(5, 5, 15, 15)
48
- const expanded = AABB.extend(aabb, 2)
49
- expect(expanded.minX).toBe(3)
50
- expect(expanded.minY).toBe(3)
51
- expect(expanded.maxX).toBe(17)
52
- expect(expanded.maxY).toBe(17)
53
- })
54
-
55
- it('should expand correctly with four values', () => {
56
- const aabb = new AABB(5, 5, 15, 15)
57
- const expanded = AABB.extend(aabb, 1, 2, 3, 4)
58
- expect(expanded.minX).toBe(4)
59
- expect(expanded.minY).toBe(3)
60
- expect(expanded.maxX).toBe(18)
61
- expect(expanded.maxY).toBe(19)
62
- })
63
-
64
- it('should merge multiple AABBs correctly', () => {
65
- const aabb1 = new AABB(0, 0, 5, 5)
66
- const aabb2 = new AABB(10, 10, 15, 15)
67
- const aabb3 = new AABB(-5, -5, 0, 0)
68
-
69
- const merged = AABB.merge(aabb1, aabb2, aabb3)
70
- expect(merged.minX).toBe(-5)
71
- expect(merged.minY).toBe(-5)
72
- expect(merged.maxX).toBe(15)
73
- expect(merged.maxY).toBe(15)
74
- })
75
-
76
- it('should create from OBB correctly', () => {
77
- const obb = new OBB(0, 0, 10, 20, 0)
78
- const aabb = AABB.fromOBB(obb)
79
- expect(aabb.minX).toBe(0)
80
- expect(aabb.minY).toBe(0)
81
- expect(aabb.maxX).toBe(10)
82
- expect(aabb.maxY).toBe(20)
83
- })
84
- })