@gitborlando/geo 4.1.0 → 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.
@@ -1,61 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- abs,
4
- ceil,
5
- divide,
6
- floor,
7
- max,
8
- min,
9
- multiply,
10
- numberHalfFix,
11
- pow2,
12
- pow3,
13
- random,
14
- round,
15
- sqrt,
16
- } from '../math'
17
-
18
- describe('Math utilities', () => {
19
- it('should export Math functions correctly', () => {
20
- expect(sqrt(16)).toBe(4)
21
- expect(abs(-5)).toBe(5)
22
- expect(min(3, 1, 4)).toBe(1)
23
- expect(max(3, 1, 4)).toBe(4)
24
- expect(round(3.7)).toBe(4)
25
- expect(floor(3.7)).toBe(3)
26
- expect(ceil(3.2)).toBe(4)
27
- expect(typeof random()).toBe('number')
28
- })
29
-
30
- it('should calculate power of 2 correctly', () => {
31
- expect(pow2(3)).toBe(9)
32
- expect(pow2(4)).toBe(16)
33
- expect(pow2(0)).toBe(0)
34
- })
35
-
36
- it('should calculate power of 3 correctly', () => {
37
- expect(pow3(2)).toBe(8)
38
- expect(pow3(3)).toBe(27)
39
- expect(pow3(1)).toBe(1)
40
- })
41
-
42
- it('should multiply numbers correctly', () => {
43
- expect(multiply(2, 3, 4)).toBe(24)
44
- expect(multiply(1, 2, 3, 4, 5)).toBe(120)
45
- expect(multiply()).toBe(1)
46
- })
47
-
48
- it('should divide numbers correctly', () => {
49
- expect(divide(10, 2)).toBe(5)
50
- expect(divide(7, 3)).toBeCloseTo(2.333, 3)
51
- expect(divide(5, 0)).toBe(1) // 除零返回1
52
- })
53
-
54
- it('should fix number to half correctly', () => {
55
- expect(numberHalfFix(1.1)).toBe(1)
56
- expect(numberHalfFix(1.3)).toBe(1.5)
57
- expect(numberHalfFix(1.8)).toBe(2)
58
- expect(numberHalfFix(2.25)).toBe(2.5)
59
- expect(numberHalfFix(2.75)).toBe(3)
60
- })
61
- })
@@ -1,73 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { AABB } from '../aabb'
3
- import { IMatrix, Matrix } from '../matrix'
4
-
5
- describe('Matrix', () => {
6
- it('should create identity matrix correctly', () => {
7
- const matrix = Matrix.create()
8
- expect(matrix).toEqual([1, 0, 0, 1, 0, 0])
9
- })
10
-
11
- it('should invert matrix correctly', () => {
12
- const matrix: IMatrix = [2, 0, 0, 2, 10, 20]
13
- const inverted = Matrix.invert(matrix)
14
- expect(inverted[0]).toBeCloseTo(0.5)
15
- expect(inverted[1]).toBeCloseTo(0)
16
- expect(inverted[2]).toBeCloseTo(0)
17
- expect(inverted[3]).toBeCloseTo(0.5)
18
- expect(inverted[4]).toBeCloseTo(-5)
19
- expect(inverted[5]).toBeCloseTo(-10)
20
- })
21
-
22
- it('should apply matrix to point correctly', () => {
23
- const point = { x: 10, y: 20 }
24
- const matrix: IMatrix = [2, 0, 0, 2, 5, 10] // 缩放2倍,平移(5,10)
25
- const result = Matrix.applyPoint(point, matrix)
26
- expect(result.x).toBe(25) // 10*2 + 5 = 25
27
- expect(result.y).toBe(50) // 20*2 + 10 = 50
28
- })
29
-
30
- it('should apply matrix to AABB correctly', () => {
31
- const aabb = new AABB(0, 0, 10, 20)
32
- const matrix: IMatrix = [2, 0, 0, 2, 0, 0] // 缩放2倍
33
- const result = Matrix.applyAABB(aabb, matrix)
34
- expect(result.minX).toBe(0)
35
- expect(result.minY).toBe(0)
36
- expect(result.maxX).toBe(20)
37
- expect(result.maxY).toBe(40)
38
- })
39
-
40
- it('should invert point transformation correctly', () => {
41
- const point = { x: 25, y: 50 }
42
- const matrix: IMatrix = [2, 0, 0, 2, 5, 10]
43
- const result = Matrix.invertPoint(point, matrix)
44
- expect(result.x).toBe(10) // (25-5)/2 = 10
45
- expect(result.y).toBe(20) // (50-10)/2 = 20
46
- })
47
-
48
- it('should invert AABB transformation correctly', () => {
49
- const transformedAABB = { minX: 0, minY: 0, maxX: 20, maxY: 40 }
50
- const matrix: IMatrix = [2, 0, 0, 2, 0, 0]
51
- const result = Matrix.invertAABB(transformedAABB, matrix)
52
- expect(result.minX).toBe(0)
53
- expect(result.minY).toBe(0)
54
- expect(result.maxX).toBe(10)
55
- expect(result.maxY).toBe(20)
56
- })
57
-
58
- it('should handle translation matrix correctly', () => {
59
- const point = { x: 5, y: 10 }
60
- const translationMatrix: IMatrix = [1, 0, 0, 1, 15, 25]
61
- const result = Matrix.applyPoint(point, translationMatrix)
62
- expect(result.x).toBe(20) // 5 + 15
63
- expect(result.y).toBe(35) // 10 + 25
64
- })
65
-
66
- it('should handle rotation matrix correctly', () => {
67
- const point = { x: 1, y: 0 }
68
- const rotationMatrix: IMatrix = [0, 1, -1, 0, 0, 0] // 90度旋转
69
- const result = Matrix.applyPoint(point, rotationMatrix)
70
- expect(result.x).toBeCloseTo(0, 10)
71
- expect(result.y).toBeCloseTo(1, 10)
72
- })
73
- })
@@ -1,95 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { AABB } from '../aabb'
3
- import { OBB } from '../obb'
4
-
5
- describe('OBB', () => {
6
- it('should create OBB correctly', () => {
7
- const obb = new OBB(0, 0, 10, 20, 0)
8
- expect(obb.x).toBe(0)
9
- expect(obb.y).toBe(0)
10
- expect(obb.width).toBe(10)
11
- expect(obb.height).toBe(20)
12
- expect(obb.rotation).toBe(0)
13
- })
14
-
15
- it('should calculate center correctly', () => {
16
- const obb = new OBB(0, 0, 10, 20, 0)
17
- expect(obb.center.x).toBe(5)
18
- expect(obb.center.y).toBe(10)
19
- })
20
-
21
- it('should get xy property correctly', () => {
22
- const obb = new OBB(5, 10, 15, 20, 0)
23
- const xy = obb.xy
24
- expect(xy.x).toBe(5)
25
- expect(xy.y).toBe(10)
26
- })
27
-
28
- it('should calculate vertex positions correctly', () => {
29
- const obb = new OBB(0, 0, 10, 20, 0)
30
- const vertexes = obb.calcVertexXY()
31
- expect(vertexes).toHaveLength(4)
32
- expect(vertexes[0]).toEqual({ x: 0, y: 0 }) // TL
33
- expect(vertexes[1]).toEqual({ x: 10, y: 0 }) // TR
34
- expect(vertexes[2]).toEqual({ x: 10, y: 20 }) // BR
35
- expect(vertexes[3]).toEqual({ x: 0, y: 20 }) // BL
36
- })
37
-
38
- it('should clone OBB correctly', () => {
39
- const original = new OBB(5, 10, 15, 20, 45)
40
- const clone = original.clone()
41
- expect(clone.x).toBe(original.x)
42
- expect(clone.y).toBe(original.y)
43
- expect(clone.width).toBe(original.width)
44
- expect(clone.height).toBe(original.height)
45
- expect(clone.rotation).toBe(original.rotation)
46
- expect(clone).not.toBe(original) // 确保是不同的实例
47
- })
48
-
49
- it('should calculate projection length correctly', () => {
50
- const obb = new OBB(0, 0, 10, 20, 0)
51
- const xAxis = { x: 1, y: 0 }
52
- const yAxis = { x: 0, y: 1 }
53
-
54
- expect(obb.projectionLengthAt(xAxis)).toBe(10)
55
- expect(obb.projectionLengthAt(yAxis)).toBe(20)
56
- })
57
-
58
- it('should detect collision correctly', () => {
59
- const obb1 = new OBB(0, 0, 10, 10, 0)
60
- const obb2 = new OBB(5, 5, 10, 10, 0) // 重叠
61
- const obb3 = new OBB(20, 20, 10, 10, 0) // 不重叠
62
-
63
- expect(obb1.collide(obb2)).toBe(true)
64
- expect(obb1.collide(obb3)).toBe(false)
65
- })
66
-
67
- it('should create identity OBB correctly', () => {
68
- const identity = OBB.identityOBB()
69
- expect(identity.x).toBe(0)
70
- expect(identity.y).toBe(0)
71
- expect(identity.width).toBe(0)
72
- expect(identity.height).toBe(0)
73
- expect(identity.rotation).toBe(0)
74
- })
75
-
76
- it('should create from rect correctly', () => {
77
- const rect = { x: 10, y: 20, width: 30, height: 40 }
78
- const obb = OBB.fromRect(rect, 45)
79
- expect(obb.x).toBe(10)
80
- expect(obb.y).toBe(20)
81
- expect(obb.width).toBe(30)
82
- expect(obb.height).toBe(40)
83
- expect(obb.rotation).toBe(45)
84
- })
85
-
86
- it('should create from AABB correctly', () => {
87
- const aabb = new AABB(5, 10, 15, 25)
88
- const obb = OBB.fromAABB(aabb)
89
- expect(obb.x).toBe(5)
90
- expect(obb.y).toBe(10)
91
- expect(obb.width).toBe(10)
92
- expect(obb.height).toBe(15)
93
- expect(obb.rotation).toBe(0)
94
- })
95
- })
@@ -1,103 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- Point,
4
- pointsOnBezierCurves,
5
- simplify,
6
- simplifyPoints,
7
- } from '../points-of-bezier'
8
-
9
- describe('Points of Bezier', () => {
10
- const createBezierPoints = (): Point[] => [
11
- { x: 0, y: 0 }, // 起点
12
- { x: 10, y: 20 }, // 控制点1
13
- { x: 30, y: 20 }, // 控制点2
14
- { x: 40, y: 0 }, // 终点
15
- ]
16
-
17
- it('should generate points on bezier curve correctly', () => {
18
- const controlPoints = createBezierPoints()
19
- const points = pointsOnBezierCurves(controlPoints, 0.15)
20
-
21
- expect(points.length).toBeGreaterThan(2)
22
- expect(points[0]).toEqual({ x: 0, y: 0 }) // 起点
23
- expect(points[points.length - 1]).toEqual({ x: 40, y: 0 }) // 终点
24
- })
25
-
26
- it('should generate points with custom tolerance', () => {
27
- const controlPoints = createBezierPoints()
28
- const highTolerance = pointsOnBezierCurves(controlPoints, 1.0)
29
- const lowTolerance = pointsOnBezierCurves(controlPoints, 0.01)
30
-
31
- expect(lowTolerance.length).toBeGreaterThan(highTolerance.length)
32
- })
33
-
34
- it('should generate points with distance simplification', () => {
35
- const controlPoints = createBezierPoints()
36
- const points = pointsOnBezierCurves(controlPoints, 0.15, 5.0)
37
- const pointsWithoutSimplify = pointsOnBezierCurves(controlPoints, 0.15)
38
-
39
- expect(points.length).toBeLessThanOrEqual(pointsWithoutSimplify.length)
40
- })
41
-
42
- it('should simplify points correctly', () => {
43
- const points: Point[] = [
44
- { x: 0, y: 0 },
45
- { x: 1, y: 0.1 },
46
- { x: 2, y: 0.2 },
47
- { x: 3, y: 0.1 },
48
- { x: 4, y: 0 },
49
- { x: 10, y: 0 },
50
- ]
51
-
52
- const simplified = simplify(points, 0.5)
53
- expect(simplified.length).toBeLessThan(points.length)
54
- expect(simplified[0]).toEqual(points[0]) // 起点保持
55
- expect(simplified[simplified.length - 1]).toEqual(points[points.length - 1]) // 终点保持
56
- })
57
-
58
- it('should simplify points with Ramer-Douglas-Peucker algorithm', () => {
59
- const points: Point[] = [
60
- { x: 0, y: 0 },
61
- { x: 1, y: 1 },
62
- { x: 2, y: 0 },
63
- { x: 3, y: 1 },
64
- { x: 4, y: 0 },
65
- ]
66
-
67
- const simplified = simplifyPoints(points, 0, points.length, 0.5)
68
- expect(simplified.length).toBeGreaterThanOrEqual(2) // 至少保留起点和终点
69
- expect(simplified[0]).toEqual(points[0])
70
- })
71
-
72
- it('should handle empty bezier curves correctly', () => {
73
- const emptyPoints: Point[] = []
74
- const result = pointsOnBezierCurves(emptyPoints)
75
- expect(result).toEqual([])
76
- })
77
-
78
- it('should handle single segment bezier correctly', () => {
79
- const singleSegment = createBezierPoints()
80
- const points = pointsOnBezierCurves(singleSegment, 0.15)
81
-
82
- expect(points.length).toBeGreaterThanOrEqual(2)
83
- expect(points[0].x).toBe(0)
84
- expect(points[0].y).toBe(0)
85
- expect(points[points.length - 1].x).toBe(40)
86
- expect(points[points.length - 1].y).toBe(0)
87
- })
88
-
89
- it('should handle multiple bezier segments correctly', () => {
90
- const multipleSegments: Point[] = [
91
- { x: 0, y: 0 }, // 第一段:起点
92
- { x: 10, y: 20 }, // 控制点1
93
- { x: 30, y: 20 }, // 控制点2
94
- { x: 40, y: 0 }, // 终点/第二段起点
95
- { x: 50, y: -20 }, // 控制点1
96
- { x: 70, y: -20 }, // 控制点2
97
- { x: 80, y: 0 }, // 第二段:终点
98
- ]
99
-
100
- const points = pointsOnBezierCurves(multipleSegments, 0.15)
101
- expect(points.length).toBeGreaterThan(4) // 应该有更多点
102
- })
103
- })
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { IRect, IRectWithCenter, IXY } from '../types'
3
-
4
- describe('Types', () => {
5
- it('should define IXY interface correctly', () => {
6
- const point: IXY = { x: 10, y: 20 }
7
- expect(point.x).toBe(10)
8
- expect(point.y).toBe(20)
9
- })
10
-
11
- it('should define IRect interface correctly', () => {
12
- const rect: IRect = { x: 0, y: 0, width: 100, height: 50 }
13
- expect(rect.x).toBe(0)
14
- expect(rect.y).toBe(0)
15
- expect(rect.width).toBe(100)
16
- expect(rect.height).toBe(50)
17
- })
18
-
19
- it('should define IRectWithCenter interface correctly', () => {
20
- const rectWithCenter: IRectWithCenter = {
21
- x: 0,
22
- y: 0,
23
- width: 100,
24
- height: 50,
25
- centerX: 50,
26
- centerY: 25,
27
- }
28
- expect(rectWithCenter.centerX).toBe(50)
29
- expect(rectWithCenter.centerY).toBe(25)
30
- })
31
- })
@@ -1,143 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- XY,
4
- xy_,
5
- xy_center,
6
- xy_client,
7
- xy_distance,
8
- xy_divide,
9
- xy_dot,
10
- xy_from,
11
- xy_minus,
12
- xy_multiply,
13
- xy_mutate,
14
- xy_opposite,
15
- xy_plus,
16
- xy_toArray,
17
- } from '../xy'
18
-
19
- describe('XY utilities', () => {
20
- it('should create xy point correctly', () => {
21
- const point = xy_(10, 20)
22
- expect(point.x).toBe(10)
23
- expect(point.y).toBe(20)
24
- })
25
-
26
- it('should create xy from client event correctly', () => {
27
- const event = { clientX: 100, clientY: 200 }
28
- const point = xy_client(event)
29
- expect(point.x).toBe(100)
30
- expect(point.y).toBe(200)
31
- })
32
-
33
- it('should copy xy point correctly', () => {
34
- const original = { x: 5, y: 10 }
35
- const copy = xy_from(original)
36
- expect(copy.x).toBe(5)
37
- expect(copy.y).toBe(10)
38
- })
39
-
40
- it('should get center point correctly', () => {
41
- const rect = { centerX: 50, centerY: 75 }
42
- const center = xy_center(rect)
43
- expect(center.x).toBe(50)
44
- expect(center.y).toBe(75)
45
- })
46
-
47
- it('should mutate xy point correctly', () => {
48
- const point1 = { x: 1, y: 2 }
49
- const point2 = { x: 3, y: 4 }
50
- xy_mutate(point1, point2)
51
- expect(point1.x).toBe(3)
52
- expect(point1.y).toBe(4)
53
- })
54
-
55
- it('should add xy points correctly', () => {
56
- const point1 = { x: 1, y: 2 }
57
- const point2 = { x: 3, y: 4 }
58
- const result = xy_plus(point1, point2)
59
- expect(result.x).toBe(4)
60
- expect(result.y).toBe(6)
61
- })
62
-
63
- it('should subtract xy points correctly', () => {
64
- const point1 = { x: 5, y: 8 }
65
- const point2 = { x: 2, y: 3 }
66
- const result = xy_minus(point1, point2)
67
- expect(result.x).toBe(3)
68
- expect(result.y).toBe(5)
69
- })
70
-
71
- it('should multiply xy point correctly', () => {
72
- const point = { x: 2, y: 3 }
73
- const result = xy_multiply(point, 2, 3)
74
- expect(result.x).toBe(12)
75
- expect(result.y).toBe(18)
76
- })
77
-
78
- it('should divide xy point correctly', () => {
79
- const point = { x: 12, y: 18 }
80
- const result = xy_divide(point, 2, 3)
81
- expect(result.x).toBe(2)
82
- expect(result.y).toBe(3)
83
- })
84
-
85
- it('should calculate distance correctly', () => {
86
- const point1 = { x: 0, y: 0 }
87
- const point2 = { x: 3, y: 4 }
88
- const distance = xy_distance(point1, point2)
89
- expect(distance).toBe(5)
90
- })
91
-
92
- it('should calculate dot product correctly', () => {
93
- const point1 = { x: 2, y: 3 }
94
- const point2 = { x: 4, y: 5 }
95
- const dot = xy_dot(point1, point2)
96
- expect(dot).toBe(23) // 2*4 + 3*5 = 8 + 15 = 23
97
- })
98
-
99
- it('should get opposite point correctly', () => {
100
- const point = { x: 3, y: -4 }
101
- const opposite = xy_opposite(point)
102
- expect(opposite.x).toBe(-3)
103
- expect(opposite.y).toBe(4)
104
- })
105
-
106
- it('should convert to array correctly', () => {
107
- const point = { x: 7, y: 11 }
108
- const array = xy_toArray(point)
109
- expect(array).toEqual([7, 11])
110
- })
111
- })
112
-
113
- describe('XY class', () => {
114
- it('should create XY instance correctly', () => {
115
- const xy = new XY(10, 20)
116
- expect(xy.x).toBe(10)
117
- expect(xy.y).toBe(20)
118
- })
119
-
120
- it('should create from point correctly', () => {
121
- const xy = XY.from({ x: 5, y: 10 })
122
- expect(xy.x).toBe(5)
123
- expect(xy.y).toBe(10)
124
- })
125
-
126
- it('should create from array correctly', () => {
127
- const xy = XY.tuple([15, 25])
128
- expect(xy.x).toBe(15)
129
- expect(xy.y).toBe(25)
130
- })
131
-
132
- it('should perform chained operations correctly', () => {
133
- const xy = new XY(2, 3).plus({ x: 1, y: 2 }).multiply(2)
134
- expect(xy.x).toBe(6) // (2+1)*2 = 6
135
- expect(xy.y).toBe(10) // (3+2)*2 = 10
136
- })
137
-
138
- it('should calculate distance correctly', () => {
139
- const xy = new XY(0, 0)
140
- const distance = xy.getDistance({ x: 3, y: 4 })
141
- expect(distance).toBe(5)
142
- })
143
- })
package/src/math.ts DELETED
@@ -1,26 +0,0 @@
1
- export const { sqrt, abs, min, max, round, floor, ceil, random } = Math
2
-
3
- export function pow2(number: number) {
4
- return Math.pow(number, 2)
5
- }
6
- export function pow3(number: number) {
7
- return Math.pow(number, 3)
8
- }
9
-
10
- export function multiply(...numbers: number[]) {
11
- return numbers.reduce((i, all) => (all *= i), 1)
12
- }
13
- export function divide(a: number, b: number) {
14
- return b === 0 ? 1 : a / b
15
- }
16
-
17
- export function numberHalfFix(number: number) {
18
- const integerPart = ~~number
19
- const floatPart = number - integerPart
20
- const halfFixed = floatPart >= 0.75 ? 1 : floatPart >= 0.25 ? 0.5 : 0
21
- return integerPart + halfFixed
22
- }
23
-
24
- export function twoDecimal(number: number) {
25
- return Number(number.toFixed(Number.isInteger(number) ? 0 : 2))
26
- }
package/src/matrix.ts DELETED
@@ -1,48 +0,0 @@
1
- import { AABB } from './aabb'
2
- import { max, min } from './math'
3
- import { IXY } from './types'
4
- import { xy_ } from './xy'
5
-
6
- export type IMatrix = [number, number, number, number, number, number]
7
-
8
- export class Matrix {
9
- static create() {
10
- return [1, 0, 0, 1, 0, 0] as IMatrix
11
- }
12
-
13
- static invert(matrix: IMatrix) {
14
- const [a, b, c, d, e, f] = matrix
15
- const invDet = 1 / (a * d - b * c)
16
- return [d, -b, -c, a, c * f - d * e, b * e - a * f].map(
17
- (i) => i * invDet,
18
- ) as IMatrix
19
- }
20
-
21
- static applyPoint(xy: IXY, matrix: IMatrix) {
22
- const { x, y } = xy
23
- const [a, b, c, d, e, f] = matrix
24
- return xy_(a * x + c * y + e, b * x + d * y + f)
25
- }
26
-
27
- static applyAABB(aabb: AABB, matrix: IMatrix) {
28
- const { minX, minY, maxX, maxY } = aabb
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
- return {
34
- minX: min(xy1.x, xy2.x, xy3.x, xy4.x),
35
- minY: min(xy1.y, xy2.y, xy3.y, xy4.y),
36
- maxX: max(xy1.x, xy2.x, xy3.x, xy4.x),
37
- maxY: max(xy1.y, xy2.y, xy3.y, xy4.y),
38
- }
39
- }
40
-
41
- static invertPoint(xy: IXY, matrix: IMatrix) {
42
- return Matrix.applyPoint(xy, Matrix.invert(matrix))
43
- }
44
-
45
- static invertAABB(aabb: AABB, matrix: IMatrix) {
46
- return Matrix.applyAABB(aabb, Matrix.invert(matrix))
47
- }
48
- }