@gitborlando/geo 1.0.1 → 2.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/CHANGELOG.md +12 -0
- package/__test__/aabb.test.ts +10 -10
- package/__test__/angle.test.ts +24 -24
- package/__test__/index.test.ts +2 -2
- package/__test__/matrix.test.ts +8 -8
- package/__test__/obb.test.ts +3 -3
- package/__test__/xy.test.ts +2 -2
- package/dist/index.d.ts +33 -30
- package/dist/index.js +68 -55
- package/package.json +3 -3
- package/src/aabb.ts +6 -6
- package/src/angle.ts +21 -21
- package/src/math.ts +4 -0
- package/src/matrix.ts +12 -12
- package/src/obb.ts +16 -9
- package/src/xy.ts +12 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @gitborlando/geo
|
|
2
2
|
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7bd75bc: 新增一些方法
|
|
8
|
+
|
|
9
|
+
## 2.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- b2c20d9: 修正了多个类的方法名称,统一为小写格式,更新了相关测试用例以匹配新的方法名。同时,更新了 package.json 中的导出路径,从 src 目录改为 dist 目录。
|
|
14
|
+
|
|
3
15
|
## 1.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/__test__/aabb.test.ts
CHANGED
|
@@ -15,7 +15,7 @@ describe('AABB', () => {
|
|
|
15
15
|
|
|
16
16
|
it('should convert to rect correctly', () => {
|
|
17
17
|
const aabb = new AABB(5, 10, 15, 25)
|
|
18
|
-
const rect = AABB.
|
|
18
|
+
const rect = AABB.rect(aabb)
|
|
19
19
|
expect(rect.x).toBe(5)
|
|
20
20
|
expect(rect.y).toBe(10)
|
|
21
21
|
expect(rect.width).toBe(10)
|
|
@@ -29,8 +29,8 @@ describe('AABB', () => {
|
|
|
29
29
|
const aabb2 = new AABB(5, 5, 15, 15)
|
|
30
30
|
const aabb3 = new AABB(20, 20, 30, 30)
|
|
31
31
|
|
|
32
|
-
expect(AABB.
|
|
33
|
-
expect(AABB.
|
|
32
|
+
expect(AABB.collide(aabb1, aabb2)).toBe(true)
|
|
33
|
+
expect(AABB.collide(aabb1, aabb3)).toBe(false)
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
it('should detect inclusion correctly', () => {
|
|
@@ -38,14 +38,14 @@ describe('AABB', () => {
|
|
|
38
38
|
const small = new AABB(5, 5, 15, 15)
|
|
39
39
|
const outside = new AABB(25, 25, 35, 35)
|
|
40
40
|
|
|
41
|
-
expect(AABB.
|
|
42
|
-
expect(AABB.
|
|
43
|
-
expect(AABB.
|
|
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
44
|
})
|
|
45
45
|
|
|
46
46
|
it('should expand correctly with single value', () => {
|
|
47
47
|
const aabb = new AABB(5, 5, 15, 15)
|
|
48
|
-
const expanded = AABB.
|
|
48
|
+
const expanded = AABB.expand(aabb, 2)
|
|
49
49
|
expect(expanded.minX).toBe(3)
|
|
50
50
|
expect(expanded.minY).toBe(3)
|
|
51
51
|
expect(expanded.maxX).toBe(17)
|
|
@@ -54,7 +54,7 @@ describe('AABB', () => {
|
|
|
54
54
|
|
|
55
55
|
it('should expand correctly with four values', () => {
|
|
56
56
|
const aabb = new AABB(5, 5, 15, 15)
|
|
57
|
-
const expanded = AABB.
|
|
57
|
+
const expanded = AABB.expand(aabb, 1, 2, 3, 4)
|
|
58
58
|
expect(expanded.minX).toBe(4)
|
|
59
59
|
expect(expanded.minY).toBe(3)
|
|
60
60
|
expect(expanded.maxX).toBe(18)
|
|
@@ -66,7 +66,7 @@ describe('AABB', () => {
|
|
|
66
66
|
const aabb2 = new AABB(10, 10, 15, 15)
|
|
67
67
|
const aabb3 = new AABB(-5, -5, 0, 0)
|
|
68
68
|
|
|
69
|
-
const merged = AABB.
|
|
69
|
+
const merged = AABB.merge(aabb1, aabb2, aabb3)
|
|
70
70
|
expect(merged.minX).toBe(-5)
|
|
71
71
|
expect(merged.minY).toBe(-5)
|
|
72
72
|
expect(merged.maxX).toBe(15)
|
|
@@ -75,7 +75,7 @@ describe('AABB', () => {
|
|
|
75
75
|
|
|
76
76
|
it('should create from OBB correctly', () => {
|
|
77
77
|
const obb = new OBB(0, 0, 10, 20, 0)
|
|
78
|
-
const aabb = AABB.
|
|
78
|
+
const aabb = AABB.fromOBB(obb)
|
|
79
79
|
expect(aabb.minX).toBe(0)
|
|
80
80
|
expect(aabb.minY).toBe(0)
|
|
81
81
|
expect(aabb.maxX).toBe(10)
|
package/__test__/angle.test.ts
CHANGED
|
@@ -7,51 +7,51 @@ describe('Angle', () => {
|
|
|
7
7
|
})
|
|
8
8
|
|
|
9
9
|
it('should calculate cosine correctly', () => {
|
|
10
|
-
expect(Angle.
|
|
11
|
-
expect(Angle.
|
|
12
|
-
expect(Angle.
|
|
10
|
+
expect(Angle.cos(0)).toBe(1)
|
|
11
|
+
expect(Angle.cos(90)).toBeCloseTo(0, 10)
|
|
12
|
+
expect(Angle.cos(180)).toBeCloseTo(-1, 10)
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
it('should calculate sine correctly', () => {
|
|
16
|
-
expect(Angle.
|
|
17
|
-
expect(Angle.
|
|
18
|
-
expect(Angle.
|
|
16
|
+
expect(Angle.sin(0)).toBe(0)
|
|
17
|
+
expect(Angle.sin(90)).toBeCloseTo(1, 10)
|
|
18
|
+
expect(Angle.sin(180)).toBeCloseTo(0, 10)
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
it('should calculate tangent correctly', () => {
|
|
22
|
-
expect(Angle.
|
|
23
|
-
expect(Angle.
|
|
22
|
+
expect(Angle.tan(0)).toBe(0)
|
|
23
|
+
expect(Angle.tan(45)).toBeCloseTo(1, 10)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
it('should convert radians to degrees correctly', () => {
|
|
27
|
-
expect(Angle.
|
|
28
|
-
expect(Angle.
|
|
29
|
-
expect(Angle.
|
|
27
|
+
expect(Angle.angleFy(Math.PI)).toBe(180)
|
|
28
|
+
expect(Angle.angleFy(Math.PI / 2)).toBe(90)
|
|
29
|
+
expect(Angle.angleFy(0)).toBe(0)
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
it('should convert degrees to radians correctly', () => {
|
|
33
|
-
expect(Angle.
|
|
34
|
-
expect(Angle.
|
|
35
|
-
expect(Angle.
|
|
33
|
+
expect(Angle.radianFy(180)).toBe(Math.PI)
|
|
34
|
+
expect(Angle.radianFy(90)).toBe(Math.PI / 2)
|
|
35
|
+
expect(Angle.radianFy(0)).toBe(0)
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
it('should normalize angles correctly', () => {
|
|
39
|
-
expect(Angle.
|
|
40
|
-
expect(Angle.
|
|
41
|
-
expect(Angle.
|
|
39
|
+
expect(Angle.normal(370)).toBe(10)
|
|
40
|
+
expect(Angle.normal(-10)).toBe(350)
|
|
41
|
+
expect(Angle.normal(0)).toBe(0)
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
it('should snap angles to steps correctly', () => {
|
|
45
|
-
expect(Angle.
|
|
46
|
-
expect(Angle.
|
|
47
|
-
expect(Angle.
|
|
48
|
-
expect(Angle.
|
|
49
|
-
expect(Angle.
|
|
50
|
-
expect(Angle.
|
|
45
|
+
expect(Angle.snap(45)).toBe(90) // 45度四舍五入到90度
|
|
46
|
+
expect(Angle.snap(80)).toBe(90)
|
|
47
|
+
expect(Angle.snap(120)).toBe(90)
|
|
48
|
+
expect(Angle.snap(135)).toBe(180)
|
|
49
|
+
expect(Angle.snap(0)).toBe(0)
|
|
50
|
+
expect(Angle.snap(30)).toBe(0) // 30度四舍五入到0度
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
it('should rotate point correctly', () => {
|
|
54
|
-
const result = Angle.
|
|
54
|
+
const result = Angle.rotatePoint(1, 0, 0, 0, 90)
|
|
55
55
|
expect(result.x).toBeCloseTo(0, 10)
|
|
56
56
|
expect(result.y).toBeCloseTo(1, 10)
|
|
57
57
|
})
|
package/__test__/index.test.ts
CHANGED
|
@@ -74,8 +74,8 @@ describe('Index exports', () => {
|
|
|
74
74
|
|
|
75
75
|
it('should allow using static methods from exported classes', () => {
|
|
76
76
|
// 测试静态方法
|
|
77
|
-
const matrix = Geo.Matrix.
|
|
78
|
-
const normalizedAngle = Geo.Angle.
|
|
77
|
+
const matrix = Geo.Matrix.create()
|
|
78
|
+
const normalizedAngle = Geo.Angle.normal(370)
|
|
79
79
|
const distance = Geo.xy_distance({ x: 0, y: 0 }, { x: 3, y: 4 })
|
|
80
80
|
|
|
81
81
|
expect(matrix).toEqual([1, 0, 0, 1, 0, 0])
|
package/__test__/matrix.test.ts
CHANGED
|
@@ -4,13 +4,13 @@ import { IMatrix, Matrix } from '../src/matrix'
|
|
|
4
4
|
|
|
5
5
|
describe('Matrix', () => {
|
|
6
6
|
it('should create identity matrix correctly', () => {
|
|
7
|
-
const matrix = Matrix.
|
|
7
|
+
const matrix = Matrix.create()
|
|
8
8
|
expect(matrix).toEqual([1, 0, 0, 1, 0, 0])
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
it('should invert matrix correctly', () => {
|
|
12
12
|
const matrix: IMatrix = [2, 0, 0, 2, 10, 20]
|
|
13
|
-
const inverted = Matrix.
|
|
13
|
+
const inverted = Matrix.invert(matrix)
|
|
14
14
|
expect(inverted[0]).toBeCloseTo(0.5)
|
|
15
15
|
expect(inverted[1]).toBeCloseTo(0)
|
|
16
16
|
expect(inverted[2]).toBeCloseTo(0)
|
|
@@ -22,7 +22,7 @@ describe('Matrix', () => {
|
|
|
22
22
|
it('should apply matrix to point correctly', () => {
|
|
23
23
|
const point = { x: 10, y: 20 }
|
|
24
24
|
const matrix: IMatrix = [2, 0, 0, 2, 5, 10] // 缩放2倍,平移(5,10)
|
|
25
|
-
const result = Matrix.
|
|
25
|
+
const result = Matrix.applyPoint(point, matrix)
|
|
26
26
|
expect(result.x).toBe(25) // 10*2 + 5 = 25
|
|
27
27
|
expect(result.y).toBe(50) // 20*2 + 10 = 50
|
|
28
28
|
})
|
|
@@ -30,7 +30,7 @@ describe('Matrix', () => {
|
|
|
30
30
|
it('should apply matrix to AABB correctly', () => {
|
|
31
31
|
const aabb = new AABB(0, 0, 10, 20)
|
|
32
32
|
const matrix: IMatrix = [2, 0, 0, 2, 0, 0] // 缩放2倍
|
|
33
|
-
const result = Matrix.
|
|
33
|
+
const result = Matrix.applyAABB(aabb, matrix)
|
|
34
34
|
expect(result.minX).toBe(0)
|
|
35
35
|
expect(result.minY).toBe(0)
|
|
36
36
|
expect(result.maxX).toBe(20)
|
|
@@ -40,7 +40,7 @@ describe('Matrix', () => {
|
|
|
40
40
|
it('should invert point transformation correctly', () => {
|
|
41
41
|
const point = { x: 25, y: 50 }
|
|
42
42
|
const matrix: IMatrix = [2, 0, 0, 2, 5, 10]
|
|
43
|
-
const result = Matrix.
|
|
43
|
+
const result = Matrix.invertPoint(point, matrix)
|
|
44
44
|
expect(result.x).toBe(10) // (25-5)/2 = 10
|
|
45
45
|
expect(result.y).toBe(20) // (50-10)/2 = 20
|
|
46
46
|
})
|
|
@@ -48,7 +48,7 @@ describe('Matrix', () => {
|
|
|
48
48
|
it('should invert AABB transformation correctly', () => {
|
|
49
49
|
const transformedAABB = { minX: 0, minY: 0, maxX: 20, maxY: 40 }
|
|
50
50
|
const matrix: IMatrix = [2, 0, 0, 2, 0, 0]
|
|
51
|
-
const result = Matrix.
|
|
51
|
+
const result = Matrix.invertAABB(transformedAABB, matrix)
|
|
52
52
|
expect(result.minX).toBe(0)
|
|
53
53
|
expect(result.minY).toBe(0)
|
|
54
54
|
expect(result.maxX).toBe(10)
|
|
@@ -58,7 +58,7 @@ describe('Matrix', () => {
|
|
|
58
58
|
it('should handle translation matrix correctly', () => {
|
|
59
59
|
const point = { x: 5, y: 10 }
|
|
60
60
|
const translationMatrix: IMatrix = [1, 0, 0, 1, 15, 25]
|
|
61
|
-
const result = Matrix.
|
|
61
|
+
const result = Matrix.applyPoint(point, translationMatrix)
|
|
62
62
|
expect(result.x).toBe(20) // 5 + 15
|
|
63
63
|
expect(result.y).toBe(35) // 10 + 25
|
|
64
64
|
})
|
|
@@ -66,7 +66,7 @@ describe('Matrix', () => {
|
|
|
66
66
|
it('should handle rotation matrix correctly', () => {
|
|
67
67
|
const point = { x: 1, y: 0 }
|
|
68
68
|
const rotationMatrix: IMatrix = [0, 1, -1, 0, 0, 0] // 90度旋转
|
|
69
|
-
const result = Matrix.
|
|
69
|
+
const result = Matrix.applyPoint(point, rotationMatrix)
|
|
70
70
|
expect(result.x).toBeCloseTo(0, 10)
|
|
71
71
|
expect(result.y).toBeCloseTo(1, 10)
|
|
72
72
|
})
|
package/__test__/obb.test.ts
CHANGED
|
@@ -65,7 +65,7 @@ describe('OBB', () => {
|
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
it('should create identity OBB correctly', () => {
|
|
68
|
-
const identity = OBB.
|
|
68
|
+
const identity = OBB.identityOBB()
|
|
69
69
|
expect(identity.x).toBe(0)
|
|
70
70
|
expect(identity.y).toBe(0)
|
|
71
71
|
expect(identity.width).toBe(0)
|
|
@@ -75,7 +75,7 @@ describe('OBB', () => {
|
|
|
75
75
|
|
|
76
76
|
it('should create from rect correctly', () => {
|
|
77
77
|
const rect = { x: 10, y: 20, width: 30, height: 40 }
|
|
78
|
-
const obb = OBB.
|
|
78
|
+
const obb = OBB.fromRect(rect, 45)
|
|
79
79
|
expect(obb.x).toBe(10)
|
|
80
80
|
expect(obb.y).toBe(20)
|
|
81
81
|
expect(obb.width).toBe(30)
|
|
@@ -85,7 +85,7 @@ describe('OBB', () => {
|
|
|
85
85
|
|
|
86
86
|
it('should create from AABB correctly', () => {
|
|
87
87
|
const aabb = new AABB(5, 10, 15, 25)
|
|
88
|
-
const obb = OBB.
|
|
88
|
+
const obb = OBB.fromAABB(aabb)
|
|
89
89
|
expect(obb.x).toBe(5)
|
|
90
90
|
expect(obb.y).toBe(10)
|
|
91
91
|
expect(obb.width).toBe(10)
|
package/__test__/xy.test.ts
CHANGED
|
@@ -118,13 +118,13 @@ describe('XY class', () => {
|
|
|
118
118
|
})
|
|
119
119
|
|
|
120
120
|
it('should create from point correctly', () => {
|
|
121
|
-
const xy = XY.
|
|
121
|
+
const xy = XY.from({ x: 5, y: 10 })
|
|
122
122
|
expect(xy.x).toBe(5)
|
|
123
123
|
expect(xy.y).toBe(10)
|
|
124
124
|
})
|
|
125
125
|
|
|
126
126
|
it('should create from array correctly', () => {
|
|
127
|
-
const xy = XY.
|
|
127
|
+
const xy = XY.fromArray([15, 25])
|
|
128
128
|
expect(xy.x).toBe(15)
|
|
129
129
|
expect(xy.y).toBe(25)
|
|
130
130
|
})
|
package/dist/index.d.ts
CHANGED
|
@@ -49,9 +49,10 @@ declare class OBB {
|
|
|
49
49
|
clone: () => OBB;
|
|
50
50
|
projectionLengthAt: (anotherAxis: IXY) => number;
|
|
51
51
|
collide: (another: OBB) => boolean;
|
|
52
|
-
static
|
|
53
|
-
static
|
|
54
|
-
static
|
|
52
|
+
static identityOBB(): OBB;
|
|
53
|
+
static fromRect(rect: IRect, rotation?: number): OBB;
|
|
54
|
+
static fromCenter(center: IXY, width: number, height: number, rotation?: number): OBB;
|
|
55
|
+
static fromAABB(aabb: AABB): OBB;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
declare class AABB {
|
|
@@ -60,12 +61,12 @@ declare class AABB {
|
|
|
60
61
|
maxX: number;
|
|
61
62
|
maxY: number;
|
|
62
63
|
constructor(minX: number, minY: number, maxX: number, maxY: number);
|
|
63
|
-
static
|
|
64
|
-
static
|
|
65
|
-
static
|
|
66
|
-
static
|
|
67
|
-
static
|
|
68
|
-
static
|
|
64
|
+
static rect(aabb: AABB): IRectWithCenter;
|
|
65
|
+
static collide(one: AABB, another: AABB): boolean;
|
|
66
|
+
static include(one: AABB, another: AABB): number;
|
|
67
|
+
static expand(aabb: AABB, ...expands: [number] | [number, number, number, number]): AABB;
|
|
68
|
+
static merge(...aabbList: AABB[]): AABB;
|
|
69
|
+
static fromOBB(obb: OBB): AABB;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
declare const PI: number;
|
|
@@ -77,18 +78,18 @@ declare const asin: (x: number) => number;
|
|
|
77
78
|
declare const atan: (x: number) => number;
|
|
78
79
|
declare const atan2: (y: number, x: number) => number;
|
|
79
80
|
declare class Angle {
|
|
80
|
-
static
|
|
81
|
-
static
|
|
82
|
-
static
|
|
83
|
-
static
|
|
84
|
-
static
|
|
85
|
-
static
|
|
86
|
-
static
|
|
87
|
-
static
|
|
88
|
-
static
|
|
89
|
-
static
|
|
90
|
-
static
|
|
91
|
-
static
|
|
81
|
+
static cos(angle: number): number;
|
|
82
|
+
static sin(angle: number): number;
|
|
83
|
+
static tan(angle: number): number;
|
|
84
|
+
static acos(angle: number): number;
|
|
85
|
+
static asin(angle: number): number;
|
|
86
|
+
static atan(angle: number): number;
|
|
87
|
+
static atan2(y: number, x: number): number;
|
|
88
|
+
static angleFy(radians: number): number;
|
|
89
|
+
static radianFy(angle: number): number;
|
|
90
|
+
static normal(angle: number): number;
|
|
91
|
+
static snap(angle: number, step?: number): number;
|
|
92
|
+
static rotatePoint(ax: number, ay: number, ox: number, oy: number, angle: number): {
|
|
92
93
|
x: number;
|
|
93
94
|
y: number;
|
|
94
95
|
};
|
|
@@ -107,26 +108,27 @@ declare function pow3(number: number): number;
|
|
|
107
108
|
declare function multiply(...numbers: number[]): number;
|
|
108
109
|
declare function divide(a: number, b: number): number;
|
|
109
110
|
declare function numberHalfFix(number: number): number;
|
|
111
|
+
declare function twoDecimal(number: number): number;
|
|
110
112
|
|
|
111
113
|
type IMatrix = [number, number, number, number, number, number];
|
|
112
114
|
declare class Matrix {
|
|
113
|
-
static
|
|
114
|
-
static
|
|
115
|
-
static
|
|
115
|
+
static create(): IMatrix;
|
|
116
|
+
static invert(matrix: IMatrix): IMatrix;
|
|
117
|
+
static applyPoint(xy: IXY, matrix: IMatrix): {
|
|
116
118
|
x: number;
|
|
117
119
|
y: number;
|
|
118
120
|
};
|
|
119
|
-
static
|
|
121
|
+
static applyAABB(aabb: AABB, matrix: IMatrix): {
|
|
120
122
|
minX: number;
|
|
121
123
|
minY: number;
|
|
122
124
|
maxX: number;
|
|
123
125
|
maxY: number;
|
|
124
126
|
};
|
|
125
|
-
static
|
|
127
|
+
static invertPoint(xy: IXY, matrix: IMatrix): {
|
|
126
128
|
x: number;
|
|
127
129
|
y: number;
|
|
128
130
|
};
|
|
129
|
-
static
|
|
131
|
+
static invertAABB(aabb: AABB, matrix: IMatrix): {
|
|
130
132
|
minX: number;
|
|
131
133
|
minY: number;
|
|
132
134
|
maxX: number;
|
|
@@ -238,8 +240,9 @@ declare class XY {
|
|
|
238
240
|
y: number;
|
|
239
241
|
};
|
|
240
242
|
angle(another: IXY, origin: IXY): number;
|
|
241
|
-
static
|
|
242
|
-
static
|
|
243
|
+
static of(x: number, y: number): XY;
|
|
244
|
+
static from(xy: IXY): XY;
|
|
245
|
+
static fromArray(arr: [number, number]): XY;
|
|
243
246
|
}
|
|
244
247
|
|
|
245
|
-
export { AABB, Angle, type IMatrix, type IRect, type IRectWithCenter, type IXY, Matrix, OBB, PI, type Point, XY, abs, acos, asin, atan, atan2, ceil, cos, divide, floor, max, min, multiply, numberHalfFix, pointsOnBezierCurves, pow2, pow3, random, round, simplify, simplifyPoints, sin, sqrt, tan, xy_, xy_center, xy_client, xy_distance, xy_divide, xy_dot, xy_from, xy_getRotation, xy_minus, xy_minus_mutate, xy_multiply, xy_multiply_mutate, xy_mutate, xy_opposite, xy_plus, xy_plus_all, xy_plus_mutate, xy_rotate, xy_symmetric, xy_toArray, xy_xAxis, xy_yAxis };
|
|
248
|
+
export { AABB, Angle, type IMatrix, type IRect, type IRectWithCenter, type IXY, Matrix, OBB, PI, type Point, XY, abs, acos, asin, atan, atan2, ceil, cos, divide, floor, max, min, multiply, numberHalfFix, pointsOnBezierCurves, pow2, pow3, random, round, simplify, simplifyPoints, sin, sqrt, tan, twoDecimal, xy_, xy_center, xy_client, xy_distance, xy_divide, xy_dot, xy_from, xy_getRotation, xy_minus, xy_minus_mutate, xy_multiply, xy_multiply_mutate, xy_mutate, xy_opposite, xy_plus, xy_plus_all, xy_plus_mutate, xy_rotate, xy_symmetric, xy_toArray, xy_xAxis, xy_yAxis };
|
package/dist/index.js
CHANGED
|
@@ -18,45 +18,48 @@ function numberHalfFix(number) {
|
|
|
18
18
|
const halfFixed = floatPart >= 0.75 ? 1 : floatPart >= 0.25 ? 0.5 : 0;
|
|
19
19
|
return integerPart + halfFixed;
|
|
20
20
|
}
|
|
21
|
+
function twoDecimal(number) {
|
|
22
|
+
return Number(number.toFixed(Number.isInteger(number) ? 0 : 2));
|
|
23
|
+
}
|
|
21
24
|
|
|
22
25
|
// src/angle.ts
|
|
23
26
|
var { PI, cos, sin, tan, acos, asin, atan, atan2 } = Math;
|
|
24
27
|
var Angle = class _Angle {
|
|
25
|
-
static
|
|
26
|
-
return cos(_Angle.
|
|
28
|
+
static cos(angle) {
|
|
29
|
+
return cos(_Angle.radianFy(angle));
|
|
27
30
|
}
|
|
28
|
-
static
|
|
29
|
-
return sin(_Angle.
|
|
31
|
+
static sin(angle) {
|
|
32
|
+
return sin(_Angle.radianFy(angle));
|
|
30
33
|
}
|
|
31
|
-
static
|
|
32
|
-
return tan(_Angle.
|
|
34
|
+
static tan(angle) {
|
|
35
|
+
return tan(_Angle.radianFy(angle));
|
|
33
36
|
}
|
|
34
|
-
static
|
|
35
|
-
return _Angle.
|
|
37
|
+
static acos(angle) {
|
|
38
|
+
return _Angle.angleFy(acos(_Angle.radianFy(angle)));
|
|
36
39
|
}
|
|
37
|
-
static
|
|
38
|
-
return _Angle.
|
|
40
|
+
static asin(angle) {
|
|
41
|
+
return _Angle.angleFy(asin(_Angle.radianFy(angle)));
|
|
39
42
|
}
|
|
40
|
-
static
|
|
41
|
-
return _Angle.
|
|
43
|
+
static atan(angle) {
|
|
44
|
+
return _Angle.angleFy(atan(_Angle.radianFy(angle)));
|
|
42
45
|
}
|
|
43
|
-
static
|
|
44
|
-
return _Angle.
|
|
46
|
+
static atan2(y, x) {
|
|
47
|
+
return _Angle.angleFy(atan2(y, x));
|
|
45
48
|
}
|
|
46
|
-
static
|
|
49
|
+
static angleFy(radians) {
|
|
47
50
|
return radians * (180 / Math.PI);
|
|
48
51
|
}
|
|
49
|
-
static
|
|
52
|
+
static radianFy(angle) {
|
|
50
53
|
return angle * (Math.PI / 180);
|
|
51
54
|
}
|
|
52
|
-
static
|
|
55
|
+
static normal(angle) {
|
|
53
56
|
return (angle + 360) % 360;
|
|
54
57
|
}
|
|
55
|
-
static
|
|
56
|
-
return _Angle.
|
|
58
|
+
static snap(angle, step = 90) {
|
|
59
|
+
return _Angle.normal(Math.round(angle / step) * step);
|
|
57
60
|
}
|
|
58
|
-
static
|
|
59
|
-
const radian = _Angle.
|
|
61
|
+
static rotatePoint(ax, ay, ox, oy, angle) {
|
|
62
|
+
const radian = _Angle.radianFy(angle);
|
|
60
63
|
return {
|
|
61
64
|
x: (ax - ox) * cos(radian) - (ay - oy) * sin(radian) + ox,
|
|
62
65
|
y: (ax - ox) * sin(radian) + (ay - oy) * cos(radian) + oy
|
|
@@ -116,7 +119,7 @@ function xy_distance(self, another = xy_(0, 0)) {
|
|
|
116
119
|
}
|
|
117
120
|
function xy_rotate(self, origin, rotation) {
|
|
118
121
|
if (rotation === 0) return self;
|
|
119
|
-
return Angle.
|
|
122
|
+
return Angle.rotatePoint(self.x, self.y, origin.x, origin.y, rotation);
|
|
120
123
|
}
|
|
121
124
|
function xy_dot(self, another) {
|
|
122
125
|
return self.x * another.x + self.y * another.y;
|
|
@@ -128,7 +131,7 @@ function xy_opposite(self) {
|
|
|
128
131
|
return { x: -self.x, y: -self.y };
|
|
129
132
|
}
|
|
130
133
|
function xy_getRotation(self, another, origin) {
|
|
131
|
-
return Angle.
|
|
134
|
+
return Angle.angleFy(
|
|
132
135
|
Math.atan2(self.y - origin.y, self.x - origin.x) - Math.atan2(another.y - origin.y, another.x - origin.x)
|
|
133
136
|
);
|
|
134
137
|
}
|
|
@@ -136,10 +139,10 @@ function xy_toArray(self) {
|
|
|
136
139
|
return [self.x, self.y];
|
|
137
140
|
}
|
|
138
141
|
function xy_xAxis(rotation) {
|
|
139
|
-
return { x: Angle.
|
|
142
|
+
return { x: Angle.cos(rotation), y: Angle.sin(rotation) };
|
|
140
143
|
}
|
|
141
144
|
function xy_yAxis(rotation) {
|
|
142
|
-
return { x: -Angle.
|
|
145
|
+
return { x: -Angle.sin(rotation), y: Angle.cos(rotation) };
|
|
143
146
|
}
|
|
144
147
|
var XY = class _XY {
|
|
145
148
|
constructor(x, y) {
|
|
@@ -188,7 +191,7 @@ var XY = class _XY {
|
|
|
188
191
|
}
|
|
189
192
|
rotate(origin, rotation) {
|
|
190
193
|
if (rotation === 0) return this;
|
|
191
|
-
return Angle.
|
|
194
|
+
return Angle.rotatePoint(this.x, this.y, origin.x, origin.y, rotation);
|
|
192
195
|
}
|
|
193
196
|
dot(another) {
|
|
194
197
|
return this.x * another.x + this.y * another.y;
|
|
@@ -200,14 +203,17 @@ var XY = class _XY {
|
|
|
200
203
|
return { x: 2 * origin.x - another.x, y: 2 * origin.y - another.y };
|
|
201
204
|
}
|
|
202
205
|
angle(another, origin) {
|
|
203
|
-
return Angle.
|
|
206
|
+
return Angle.angleFy(
|
|
204
207
|
Math.atan2(this.y - origin.y, this.x - origin.x) - Math.atan2(another.y - origin.y, another.x - origin.x)
|
|
205
208
|
);
|
|
206
209
|
}
|
|
207
|
-
static
|
|
210
|
+
static of(x, y) {
|
|
211
|
+
return new _XY(x, y);
|
|
212
|
+
}
|
|
213
|
+
static from(xy) {
|
|
208
214
|
return new _XY(xy.x, xy.y);
|
|
209
215
|
}
|
|
210
|
-
static
|
|
216
|
+
static fromArray(arr) {
|
|
211
217
|
return new _XY(arr[0], arr[1]);
|
|
212
218
|
}
|
|
213
219
|
};
|
|
@@ -220,7 +226,7 @@ var AABB = class _AABB {
|
|
|
220
226
|
this.maxX = maxX;
|
|
221
227
|
this.maxY = maxY;
|
|
222
228
|
}
|
|
223
|
-
static
|
|
229
|
+
static rect(aabb) {
|
|
224
230
|
return {
|
|
225
231
|
x: aabb.minX,
|
|
226
232
|
y: aabb.minY,
|
|
@@ -230,10 +236,10 @@ var AABB = class _AABB {
|
|
|
230
236
|
centerY: aabb.minY + (aabb.maxY - aabb.minY) / 2
|
|
231
237
|
};
|
|
232
238
|
}
|
|
233
|
-
static
|
|
239
|
+
static collide(one, another) {
|
|
234
240
|
return one.minX <= another.maxX && one.maxX >= another.minX && one.minY <= another.maxY && one.maxY >= another.minY;
|
|
235
241
|
}
|
|
236
|
-
static
|
|
242
|
+
static include(one, another) {
|
|
237
243
|
let result = 1;
|
|
238
244
|
let [large, small] = [one, another];
|
|
239
245
|
if (one.maxX - one.minX < another.maxX - another.minX) {
|
|
@@ -244,7 +250,7 @@ var AABB = class _AABB {
|
|
|
244
250
|
const included = large.minX <= small.minX && large.maxX >= small.maxX && large.minY <= small.minY && large.maxY >= small.maxY;
|
|
245
251
|
return included ? result : -1;
|
|
246
252
|
}
|
|
247
|
-
static
|
|
253
|
+
static expand(aabb, ...expands) {
|
|
248
254
|
const { minX, minY, maxX, maxY } = aabb;
|
|
249
255
|
if (expands.length === 1) {
|
|
250
256
|
const expand = expands[0];
|
|
@@ -258,7 +264,7 @@ var AABB = class _AABB {
|
|
|
258
264
|
);
|
|
259
265
|
}
|
|
260
266
|
}
|
|
261
|
-
static
|
|
267
|
+
static merge(...aabbList) {
|
|
262
268
|
let [xMin, yMin, xMax, yMax] = [Infinity, Infinity, -Infinity, -Infinity];
|
|
263
269
|
aabbList.forEach((aabb) => {
|
|
264
270
|
xMin = min(xMin, aabb.minX);
|
|
@@ -268,7 +274,7 @@ var AABB = class _AABB {
|
|
|
268
274
|
});
|
|
269
275
|
return new _AABB(xMin, yMin, xMax, yMax);
|
|
270
276
|
}
|
|
271
|
-
static
|
|
277
|
+
static fromOBB(obb) {
|
|
272
278
|
const width = obb.projectionLengthAt(xy_(1, 0));
|
|
273
279
|
const height = obb.projectionLengthAt(xy_(0, 1));
|
|
274
280
|
return new _AABB(
|
|
@@ -282,27 +288,27 @@ var AABB = class _AABB {
|
|
|
282
288
|
|
|
283
289
|
// src/matrix.ts
|
|
284
290
|
var Matrix = class _Matrix {
|
|
285
|
-
static
|
|
291
|
+
static create() {
|
|
286
292
|
return [1, 0, 0, 1, 0, 0];
|
|
287
293
|
}
|
|
288
|
-
static
|
|
294
|
+
static invert(matrix) {
|
|
289
295
|
const [a, b, c, d, e, f] = matrix;
|
|
290
296
|
const invDet = 1 / (a * d - b * c);
|
|
291
297
|
return [d, -b, -c, a, c * f - d * e, b * e - a * f].map(
|
|
292
298
|
(i) => i * invDet
|
|
293
299
|
);
|
|
294
300
|
}
|
|
295
|
-
static
|
|
301
|
+
static applyPoint(xy, matrix) {
|
|
296
302
|
const { x, y } = xy;
|
|
297
303
|
const [a, b, c, d, e, f] = matrix;
|
|
298
304
|
return xy_(a * x + c * y + e, b * x + d * y + f);
|
|
299
305
|
}
|
|
300
|
-
static
|
|
306
|
+
static applyAABB(aabb, matrix) {
|
|
301
307
|
const { minX, minY, maxX, maxY } = aabb;
|
|
302
|
-
const xy1 = _Matrix.
|
|
303
|
-
const xy2 = _Matrix.
|
|
304
|
-
const xy3 = _Matrix.
|
|
305
|
-
const xy4 = _Matrix.
|
|
308
|
+
const xy1 = _Matrix.applyPoint(xy_(minX, minY), matrix);
|
|
309
|
+
const xy2 = _Matrix.applyPoint(xy_(maxX, minY), matrix);
|
|
310
|
+
const xy3 = _Matrix.applyPoint(xy_(maxX, maxY), matrix);
|
|
311
|
+
const xy4 = _Matrix.applyPoint(xy_(minX, maxY), matrix);
|
|
306
312
|
return {
|
|
307
313
|
minX: min(xy1.x, xy2.x, xy3.x, xy4.x),
|
|
308
314
|
minY: min(xy1.y, xy2.y, xy3.y, xy4.y),
|
|
@@ -310,11 +316,11 @@ var Matrix = class _Matrix {
|
|
|
310
316
|
maxY: max(xy1.y, xy2.y, xy3.y, xy4.y)
|
|
311
317
|
};
|
|
312
318
|
}
|
|
313
|
-
static
|
|
314
|
-
return _Matrix.
|
|
319
|
+
static invertPoint(xy, matrix) {
|
|
320
|
+
return _Matrix.applyPoint(xy, _Matrix.invert(matrix));
|
|
315
321
|
}
|
|
316
|
-
static
|
|
317
|
-
return _Matrix.
|
|
322
|
+
static invertAABB(aabb, matrix) {
|
|
323
|
+
return _Matrix.applyAABB(aabb, _Matrix.invert(matrix));
|
|
318
324
|
}
|
|
319
325
|
};
|
|
320
326
|
|
|
@@ -329,7 +335,7 @@ var OBB = class _OBB {
|
|
|
329
335
|
this.center = this.#calcCenter();
|
|
330
336
|
this.axis = this.#calcAxis();
|
|
331
337
|
this.vertexes = this.calcVertexXY();
|
|
332
|
-
this.aabb = AABB.
|
|
338
|
+
this.aabb = AABB.fromOBB(this);
|
|
333
339
|
}
|
|
334
340
|
center;
|
|
335
341
|
axis;
|
|
@@ -343,15 +349,15 @@ var OBB = class _OBB {
|
|
|
343
349
|
return xy_rotate(center, xy_(this.x, this.y), this.rotation);
|
|
344
350
|
};
|
|
345
351
|
#calcAxis = () => {
|
|
346
|
-
const cos2 = Angle.
|
|
347
|
-
const sin2 = Angle.
|
|
352
|
+
const cos2 = Angle.cos(this.rotation);
|
|
353
|
+
const sin2 = Angle.sin(this.rotation);
|
|
348
354
|
const widthAxis = xy_(cos2, -sin2);
|
|
349
355
|
const heightAxis = xy_(sin2, cos2);
|
|
350
356
|
return this.axis = { widthAxis, heightAxis };
|
|
351
357
|
};
|
|
352
358
|
calcVertexXY = () => {
|
|
353
|
-
const cos2 = Angle.
|
|
354
|
-
const sin2 = Angle.
|
|
359
|
+
const cos2 = Angle.cos(this.rotation);
|
|
360
|
+
const sin2 = Angle.sin(this.rotation);
|
|
355
361
|
const cosWidth = cos2 * this.width;
|
|
356
362
|
const sinWidth = sin2 * this.width;
|
|
357
363
|
const cosHeight = cos2 * this.height;
|
|
@@ -381,14 +387,20 @@ var OBB = class _OBB {
|
|
|
381
387
|
return false;
|
|
382
388
|
return true;
|
|
383
389
|
};
|
|
384
|
-
static
|
|
390
|
+
static identityOBB() {
|
|
385
391
|
return new _OBB(0, 0, 0, 0, 0);
|
|
386
392
|
}
|
|
387
|
-
static
|
|
393
|
+
static fromRect(rect, rotation = 0) {
|
|
388
394
|
const { x, y, width, height } = rect;
|
|
389
395
|
return new _OBB(x, y, width, height, rotation);
|
|
390
396
|
}
|
|
391
|
-
static
|
|
397
|
+
static fromCenter(center, width, height, rotation = 0) {
|
|
398
|
+
const dx = center.x - width / 2;
|
|
399
|
+
const dy = center.y - height / 2;
|
|
400
|
+
const xy = XY.of(dx, dy).rotate(center, rotation);
|
|
401
|
+
return new _OBB(xy.x, xy.y, width, height, rotation);
|
|
402
|
+
}
|
|
403
|
+
static fromAABB(aabb) {
|
|
392
404
|
const { minX, minY, maxX, maxY } = aabb;
|
|
393
405
|
return new _OBB(minX, minY, maxX - minX, maxY - minY, 0);
|
|
394
406
|
}
|
|
@@ -533,6 +545,7 @@ export {
|
|
|
533
545
|
sin,
|
|
534
546
|
sqrt,
|
|
535
547
|
tan,
|
|
548
|
+
twoDecimal,
|
|
536
549
|
xy_,
|
|
537
550
|
xy_center,
|
|
538
551
|
xy_client,
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitborlando/geo",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"import": "./
|
|
9
|
-
"types": "./
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"publishConfig": {
|
package/src/aabb.ts
CHANGED
|
@@ -11,7 +11,7 @@ export class AABB {
|
|
|
11
11
|
public maxY: number,
|
|
12
12
|
) {}
|
|
13
13
|
|
|
14
|
-
static
|
|
14
|
+
static rect(aabb: AABB): IRectWithCenter {
|
|
15
15
|
return {
|
|
16
16
|
x: aabb.minX,
|
|
17
17
|
y: aabb.minY,
|
|
@@ -22,7 +22,7 @@ export class AABB {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
static
|
|
25
|
+
static collide(one: AABB, another: AABB): boolean {
|
|
26
26
|
return (
|
|
27
27
|
one.minX <= another.maxX &&
|
|
28
28
|
one.maxX >= another.minX &&
|
|
@@ -31,7 +31,7 @@ export class AABB {
|
|
|
31
31
|
)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
static
|
|
34
|
+
static include(one: AABB, another: AABB) {
|
|
35
35
|
let result = 1
|
|
36
36
|
let [large, small] = [one, another]
|
|
37
37
|
if (one.maxX - one.minX < another.maxX - another.minX) {
|
|
@@ -47,7 +47,7 @@ export class AABB {
|
|
|
47
47
|
return included ? result : -1
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
static
|
|
50
|
+
static expand(
|
|
51
51
|
aabb: AABB,
|
|
52
52
|
...expands: [number] | [number, number, number, number]
|
|
53
53
|
): AABB {
|
|
@@ -65,7 +65,7 @@ export class AABB {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
static
|
|
68
|
+
static merge(...aabbList: AABB[]) {
|
|
69
69
|
let [xMin, yMin, xMax, yMax] = [Infinity, Infinity, -Infinity, -Infinity]
|
|
70
70
|
aabbList.forEach((aabb) => {
|
|
71
71
|
xMin = min(xMin, aabb.minX)
|
|
@@ -76,7 +76,7 @@ export class AABB {
|
|
|
76
76
|
return new AABB(xMin, yMin, xMax, yMax)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
static
|
|
79
|
+
static fromOBB(obb: OBB) {
|
|
80
80
|
const width = obb.projectionLengthAt(xy_(1, 0))
|
|
81
81
|
const height = obb.projectionLengthAt(xy_(0, 1))
|
|
82
82
|
return new AABB(
|
package/src/angle.ts
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
export const { PI, cos, sin, tan, acos, asin, atan, atan2 } = Math
|
|
2
2
|
|
|
3
3
|
export class Angle {
|
|
4
|
-
static
|
|
5
|
-
return cos(Angle.
|
|
4
|
+
static cos(angle: number) {
|
|
5
|
+
return cos(Angle.radianFy(angle))
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
static
|
|
9
|
-
return sin(Angle.
|
|
8
|
+
static sin(angle: number) {
|
|
9
|
+
return sin(Angle.radianFy(angle))
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
static
|
|
13
|
-
return tan(Angle.
|
|
12
|
+
static tan(angle: number) {
|
|
13
|
+
return tan(Angle.radianFy(angle))
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
static
|
|
17
|
-
return Angle.
|
|
16
|
+
static acos(angle: number) {
|
|
17
|
+
return Angle.angleFy(acos(Angle.radianFy(angle)))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
static
|
|
21
|
-
return Angle.
|
|
20
|
+
static asin(angle: number) {
|
|
21
|
+
return Angle.angleFy(asin(Angle.radianFy(angle)))
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
static
|
|
25
|
-
return Angle.
|
|
24
|
+
static atan(angle: number) {
|
|
25
|
+
return Angle.angleFy(atan(Angle.radianFy(angle)))
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
static
|
|
29
|
-
return Angle.
|
|
28
|
+
static atan2(y: number, x: number) {
|
|
29
|
+
return Angle.angleFy(atan2(y, x))
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
static
|
|
32
|
+
static angleFy(radians: number) {
|
|
33
33
|
return radians * (180 / Math.PI)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
static
|
|
36
|
+
static radianFy(angle: number) {
|
|
37
37
|
return angle * (Math.PI / 180)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
static
|
|
40
|
+
static normal(angle: number) {
|
|
41
41
|
return (angle + 360) % 360
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
static
|
|
45
|
-
return Angle.
|
|
44
|
+
static snap(angle: number, step = 90) {
|
|
45
|
+
return Angle.normal(Math.round(angle / step) * step)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
static
|
|
49
|
-
const radian = Angle.
|
|
48
|
+
static rotatePoint(ax: number, ay: number, ox: number, oy: number, angle: number) {
|
|
49
|
+
const radian = Angle.radianFy(angle)
|
|
50
50
|
return {
|
|
51
51
|
x: (ax - ox) * cos(radian) - (ay - oy) * sin(radian) + ox,
|
|
52
52
|
y: (ax - ox) * sin(radian) + (ay - oy) * cos(radian) + oy,
|
package/src/math.ts
CHANGED
|
@@ -20,3 +20,7 @@ export function numberHalfFix(number: number) {
|
|
|
20
20
|
const halfFixed = floatPart >= 0.75 ? 1 : floatPart >= 0.25 ? 0.5 : 0
|
|
21
21
|
return integerPart + halfFixed
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
export function twoDecimal(number: number) {
|
|
25
|
+
return Number(number.toFixed(Number.isInteger(number) ? 0 : 2))
|
|
26
|
+
}
|
package/src/matrix.ts
CHANGED
|
@@ -6,11 +6,11 @@ import { xy_ } from './xy'
|
|
|
6
6
|
export type IMatrix = [number, number, number, number, number, number]
|
|
7
7
|
|
|
8
8
|
export class Matrix {
|
|
9
|
-
static
|
|
9
|
+
static create() {
|
|
10
10
|
return [1, 0, 0, 1, 0, 0] as IMatrix
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
static
|
|
13
|
+
static invert(matrix: IMatrix) {
|
|
14
14
|
const [a, b, c, d, e, f] = matrix
|
|
15
15
|
const invDet = 1 / (a * d - b * c)
|
|
16
16
|
return [d, -b, -c, a, c * f - d * e, b * e - a * f].map(
|
|
@@ -18,18 +18,18 @@ export class Matrix {
|
|
|
18
18
|
) as IMatrix
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
static
|
|
21
|
+
static applyPoint(xy: IXY, matrix: IMatrix) {
|
|
22
22
|
const { x, y } = xy
|
|
23
23
|
const [a, b, c, d, e, f] = matrix
|
|
24
24
|
return xy_(a * x + c * y + e, b * x + d * y + f)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
static
|
|
27
|
+
static applyAABB(aabb: AABB, matrix: IMatrix) {
|
|
28
28
|
const { minX, minY, maxX, maxY } = aabb
|
|
29
|
-
const xy1 = Matrix.
|
|
30
|
-
const xy2 = Matrix.
|
|
31
|
-
const xy3 = Matrix.
|
|
32
|
-
const xy4 = Matrix.
|
|
29
|
+
const xy1 = Matrix.applyPoint(xy_(minX, minY), matrix)
|
|
30
|
+
const xy2 = Matrix.applyPoint(xy_(maxX, minY), matrix)
|
|
31
|
+
const xy3 = Matrix.applyPoint(xy_(maxX, maxY), matrix)
|
|
32
|
+
const xy4 = Matrix.applyPoint(xy_(minX, maxY), matrix)
|
|
33
33
|
return {
|
|
34
34
|
minX: min(xy1.x, xy2.x, xy3.x, xy4.x),
|
|
35
35
|
minY: min(xy1.y, xy2.y, xy3.y, xy4.y),
|
|
@@ -38,11 +38,11 @@ export class Matrix {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
static
|
|
42
|
-
return Matrix.
|
|
41
|
+
static invertPoint(xy: IXY, matrix: IMatrix) {
|
|
42
|
+
return Matrix.applyPoint(xy, Matrix.invert(matrix))
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
static
|
|
46
|
-
return Matrix.
|
|
45
|
+
static invertAABB(aabb: AABB, matrix: IMatrix) {
|
|
46
|
+
return Matrix.applyAABB(aabb, Matrix.invert(matrix))
|
|
47
47
|
}
|
|
48
48
|
}
|
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_dot, xy_minus, xy_rotate } from './xy'
|
|
4
|
+
import { XY, xy_, xy_dot, xy_minus, xy_rotate } from './xy'
|
|
5
5
|
|
|
6
6
|
type IAxis = { widthAxis: IXY; heightAxis: IXY }
|
|
7
7
|
|
|
@@ -21,7 +21,7 @@ export class OBB {
|
|
|
21
21
|
this.center = this.#calcCenter()
|
|
22
22
|
this.axis = this.#calcAxis()
|
|
23
23
|
this.vertexes = this.calcVertexXY()
|
|
24
|
-
this.aabb = AABB.
|
|
24
|
+
this.aabb = AABB.fromOBB(this)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
get xy() {
|
|
@@ -34,16 +34,16 @@ export class OBB {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
#calcAxis = () => {
|
|
37
|
-
const cos = Angle.
|
|
38
|
-
const sin = Angle.
|
|
37
|
+
const cos = Angle.cos(this.rotation)
|
|
38
|
+
const sin = Angle.sin(this.rotation)
|
|
39
39
|
const widthAxis = xy_(cos, -sin)
|
|
40
40
|
const heightAxis = xy_(sin, cos)
|
|
41
41
|
return (this.axis = { widthAxis, heightAxis })
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
calcVertexXY = () => {
|
|
45
|
-
const cos = Angle.
|
|
46
|
-
const sin = Angle.
|
|
45
|
+
const cos = Angle.cos(this.rotation)
|
|
46
|
+
const sin = Angle.sin(this.rotation)
|
|
47
47
|
const cosWidth = cos * this.width
|
|
48
48
|
const sinWidth = sin * this.width
|
|
49
49
|
const cosHeight = cos * this.height
|
|
@@ -92,16 +92,23 @@ export class OBB {
|
|
|
92
92
|
return true
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
static
|
|
95
|
+
static identityOBB() {
|
|
96
96
|
return new OBB(0, 0, 0, 0, 0)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
static
|
|
99
|
+
static fromRect(rect: IRect, rotation = 0): OBB {
|
|
100
100
|
const { x, y, width, height } = rect
|
|
101
101
|
return new OBB(x, y, width, height, rotation)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
static
|
|
104
|
+
static fromCenter(center: IXY, width: number, height: number, rotation = 0) {
|
|
105
|
+
const dx = center.x - width / 2
|
|
106
|
+
const dy = center.y - height / 2
|
|
107
|
+
const xy = XY.of(dx, dy).rotate(center, rotation)
|
|
108
|
+
return new OBB(xy.x, xy.y, width, height, rotation)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static fromAABB(aabb: AABB): OBB {
|
|
105
112
|
const { minX, minY, maxX, maxY } = aabb
|
|
106
113
|
return new OBB(minX, minY, maxX - minX, maxY - minY, 0)
|
|
107
114
|
}
|
package/src/xy.ts
CHANGED
|
@@ -63,7 +63,7 @@ export function xy_distance(self: IXY, another: IXY = xy_(0, 0)) {
|
|
|
63
63
|
|
|
64
64
|
export function xy_rotate(self: IXY, origin: IXY, rotation: number) {
|
|
65
65
|
if (rotation === 0) return self
|
|
66
|
-
return Angle.
|
|
66
|
+
return Angle.rotatePoint(self.x, self.y, origin.x, origin.y, rotation)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export function xy_dot(self: IXY, another: IXY) {
|
|
@@ -79,7 +79,7 @@ export function xy_opposite(self: IXY) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function xy_getRotation(self: IXY, another: IXY, origin: IXY) {
|
|
82
|
-
return Angle.
|
|
82
|
+
return Angle.angleFy(
|
|
83
83
|
Math.atan2(self.y - origin.y, self.x - origin.x) -
|
|
84
84
|
Math.atan2(another.y - origin.y, another.x - origin.x),
|
|
85
85
|
)
|
|
@@ -90,11 +90,11 @@ export function xy_toArray(self: IXY) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
export function xy_xAxis(rotation: number) {
|
|
93
|
-
return { x: Angle.
|
|
93
|
+
return { x: Angle.cos(rotation), y: Angle.sin(rotation) }
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export function xy_yAxis(rotation: number) {
|
|
97
|
-
return { x: -Angle.
|
|
97
|
+
return { x: -Angle.sin(rotation), y: Angle.cos(rotation) }
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export class XY {
|
|
@@ -153,7 +153,7 @@ export class XY {
|
|
|
153
153
|
|
|
154
154
|
rotate(origin: IXY, rotation: number) {
|
|
155
155
|
if (rotation === 0) return this
|
|
156
|
-
return Angle.
|
|
156
|
+
return Angle.rotatePoint(this.x, this.y, origin.x, origin.y, rotation)
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
dot(another: IXY) {
|
|
@@ -169,17 +169,21 @@ export class XY {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
angle(another: IXY, origin: IXY) {
|
|
172
|
-
return Angle.
|
|
172
|
+
return Angle.angleFy(
|
|
173
173
|
Math.atan2(this.y - origin.y, this.x - origin.x) -
|
|
174
174
|
Math.atan2(another.y - origin.y, another.x - origin.x),
|
|
175
175
|
)
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
static
|
|
178
|
+
static of(x: number, y: number) {
|
|
179
|
+
return new XY(x, y)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static from(xy: IXY) {
|
|
179
183
|
return new XY(xy.x, xy.y)
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
static
|
|
186
|
+
static fromArray(arr: [number, number]) {
|
|
183
187
|
return new XY(arr[0], arr[1])
|
|
184
188
|
}
|
|
185
189
|
}
|