@flighthq/geometry 0.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/dist/aabb.d.ts +88 -0
- package/dist/aabb.d.ts.map +1 -0
- package/dist/aabb.js +230 -0
- package/dist/aabb.js.map +1 -0
- package/dist/boundingSphere.d.ts +62 -0
- package/dist/boundingSphere.d.ts.map +1 -0
- package/dist/boundingSphere.js +188 -0
- package/dist/boundingSphere.js.map +1 -0
- package/dist/capsule.d.ts +38 -0
- package/dist/capsule.d.ts.map +1 -0
- package/dist/capsule.js +215 -0
- package/dist/capsule.js.map +1 -0
- package/dist/frustum.d.ts +49 -0
- package/dist/frustum.d.ts.map +1 -0
- package/dist/frustum.js +149 -0
- package/dist/frustum.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/matrix.d.ts +152 -0
- package/dist/matrix.d.ts.map +1 -0
- package/dist/matrix.js +488 -0
- package/dist/matrix.js.map +1 -0
- package/dist/matrix3.d.ts +63 -0
- package/dist/matrix3.d.ts.map +1 -0
- package/dist/matrix3.js +408 -0
- package/dist/matrix3.js.map +1 -0
- package/dist/matrix3Pool.d.ts +6 -0
- package/dist/matrix3Pool.d.ts.map +1 -0
- package/dist/matrix3Pool.js +26 -0
- package/dist/matrix3Pool.js.map +1 -0
- package/dist/matrix4.d.ts +238 -0
- package/dist/matrix4.d.ts.map +1 -0
- package/dist/matrix4.js +931 -0
- package/dist/matrix4.js.map +1 -0
- package/dist/matrix4Pool.d.ts +6 -0
- package/dist/matrix4Pool.d.ts.map +1 -0
- package/dist/matrix4Pool.js +26 -0
- package/dist/matrix4Pool.js.map +1 -0
- package/dist/matrixPool.d.ts +6 -0
- package/dist/matrixPool.d.ts.map +1 -0
- package/dist/matrixPool.js +26 -0
- package/dist/matrixPool.js.map +1 -0
- package/dist/obb.d.ts +44 -0
- package/dist/obb.d.ts.map +1 -0
- package/dist/obb.js +248 -0
- package/dist/obb.js.map +1 -0
- package/dist/plane.d.ts +66 -0
- package/dist/plane.d.ts.map +1 -0
- package/dist/plane.js +140 -0
- package/dist/plane.js.map +1 -0
- package/dist/quaternion.d.ts +128 -0
- package/dist/quaternion.d.ts.map +1 -0
- package/dist/quaternion.js +508 -0
- package/dist/quaternion.js.map +1 -0
- package/dist/quaternionPool.d.ts +6 -0
- package/dist/quaternionPool.d.ts.map +1 -0
- package/dist/quaternionPool.js +29 -0
- package/dist/quaternionPool.js.map +1 -0
- package/dist/ray3d.d.ts +69 -0
- package/dist/ray3d.d.ts.map +1 -0
- package/dist/ray3d.js +264 -0
- package/dist/ray3d.js.map +1 -0
- package/dist/rectangle.d.ts +56 -0
- package/dist/rectangle.d.ts.map +1 -0
- package/dist/rectangle.js +235 -0
- package/dist/rectangle.js.map +1 -0
- package/dist/rectanglePool.d.ts +6 -0
- package/dist/rectanglePool.d.ts.map +1 -0
- package/dist/rectanglePool.js +29 -0
- package/dist/rectanglePool.js.map +1 -0
- package/dist/typedarray.d.ts +4 -0
- package/dist/typedarray.d.ts.map +1 -0
- package/dist/typedarray.js +25 -0
- package/dist/typedarray.js.map +1 -0
- package/dist/vector2.d.ts +130 -0
- package/dist/vector2.d.ts.map +1 -0
- package/dist/vector2.js +250 -0
- package/dist/vector2.js.map +1 -0
- package/dist/vector2Pool.d.ts +6 -0
- package/dist/vector2Pool.d.ts.map +1 -0
- package/dist/vector2Pool.js +20 -0
- package/dist/vector2Pool.js.map +1 -0
- package/dist/vector3.d.ts +220 -0
- package/dist/vector3.d.ts.map +1 -0
- package/dist/vector3.js +380 -0
- package/dist/vector3.js.map +1 -0
- package/dist/vector3Pool.d.ts +6 -0
- package/dist/vector3Pool.d.ts.map +1 -0
- package/dist/vector3Pool.js +28 -0
- package/dist/vector3Pool.js.map +1 -0
- package/dist/vector4.d.ts +180 -0
- package/dist/vector4.d.ts.map +1 -0
- package/dist/vector4.js +333 -0
- package/dist/vector4.js.map +1 -0
- package/dist/vector4Pool.d.ts +6 -0
- package/dist/vector4Pool.d.ts.map +1 -0
- package/dist/vector4Pool.js +29 -0
- package/dist/vector4Pool.js.map +1 -0
- package/package.json +38 -0
- package/src/aabb.test.ts +341 -0
- package/src/boundingSphere.test.ts +247 -0
- package/src/capsule.test.ts +157 -0
- package/src/frustum.test.ts +160 -0
- package/src/matrix.test.ts +1111 -0
- package/src/matrix3.test.ts +752 -0
- package/src/matrix3Pool.test.ts +73 -0
- package/src/matrix4.test.ts +1627 -0
- package/src/matrix4Pool.test.ts +71 -0
- package/src/matrixPool.test.ts +69 -0
- package/src/obb.test.ts +183 -0
- package/src/plane.test.ts +225 -0
- package/src/quaternion.test.ts +531 -0
- package/src/quaternionPool.test.ts +64 -0
- package/src/ray3d.test.ts +297 -0
- package/src/rectangle.test.ts +982 -0
- package/src/rectanglePool.test.ts +71 -0
- package/src/typedarray.test.ts +118 -0
- package/src/vector2.test.ts +958 -0
- package/src/vector2Pool.test.ts +65 -0
- package/src/vector3.test.ts +749 -0
- package/src/vector3Pool.test.ts +68 -0
- package/src/vector4.test.ts +660 -0
- package/src/vector4Pool.test.ts +71 -0
|
@@ -0,0 +1,982 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cloneRectangle,
|
|
3
|
+
computeRectangleIntersection,
|
|
4
|
+
containsRectanglePoint,
|
|
5
|
+
containsRectanglePointXY,
|
|
6
|
+
copyRectangle,
|
|
7
|
+
createRectangle,
|
|
8
|
+
createVector2,
|
|
9
|
+
enclosesRectangle,
|
|
10
|
+
equalsRectangle,
|
|
11
|
+
expandRectangleToPoint,
|
|
12
|
+
getRectangleBottom,
|
|
13
|
+
getRectangleBottomRight,
|
|
14
|
+
getRectangleLeft,
|
|
15
|
+
getRectangleMaxX,
|
|
16
|
+
getRectangleMaxY,
|
|
17
|
+
getRectangleMinX,
|
|
18
|
+
getRectangleMinY,
|
|
19
|
+
getRectangleNormalizedBottomRight,
|
|
20
|
+
getRectangleNormalizedTopLeft,
|
|
21
|
+
getRectangleRight,
|
|
22
|
+
getRectangleSize,
|
|
23
|
+
getRectangleTop,
|
|
24
|
+
getRectangleTopLeft,
|
|
25
|
+
inflateRectangle,
|
|
26
|
+
intersectsRectangle,
|
|
27
|
+
isEmptyRectangle,
|
|
28
|
+
isFlippedXRectangle,
|
|
29
|
+
isFlippedYRectangle,
|
|
30
|
+
mergeRectangle,
|
|
31
|
+
normalizeRectangle,
|
|
32
|
+
offsetRectangle,
|
|
33
|
+
offsetRectangleByPoint,
|
|
34
|
+
setEmptyRectangle,
|
|
35
|
+
setRectangle,
|
|
36
|
+
setRectangleBottom,
|
|
37
|
+
setRectangleBottomRight,
|
|
38
|
+
setRectangleLeft,
|
|
39
|
+
setRectangleRight,
|
|
40
|
+
setRectangleSize,
|
|
41
|
+
setRectangleTop,
|
|
42
|
+
setRectangleTopLeft,
|
|
43
|
+
} from '@flighthq/geometry';
|
|
44
|
+
import type { Rectangle } from '@flighthq/types';
|
|
45
|
+
|
|
46
|
+
let r: Rectangle;
|
|
47
|
+
let r2: Rectangle;
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
r = createRectangle(0, 0, 10, 20);
|
|
51
|
+
r2 = createRectangle(2, 5, 3, 4);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('cloneRectangle', () => {
|
|
55
|
+
it('clone creates a copy', () => {
|
|
56
|
+
const c = cloneRectangle(r);
|
|
57
|
+
expect(equalsRectangle(r, c)).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('clone does not affect original rectangle', () => {
|
|
61
|
+
const c = cloneRectangle(r);
|
|
62
|
+
c.x = 100;
|
|
63
|
+
expect(r.x).not.toBe(c.x); // Original should remain unchanged
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('allows a rectangle-like object', () => {
|
|
67
|
+
const r = { x: 1, y: 1, width: 100, height: 100 };
|
|
68
|
+
const c = cloneRectangle(r);
|
|
69
|
+
c.x = 100;
|
|
70
|
+
expect(r.x).not.toBe(c.x);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('returns a Rectangle instance', () => {
|
|
74
|
+
const r = { x: 1, y: 1, width: 100, height: 100 };
|
|
75
|
+
const c: Rectangle = cloneRectangle(r);
|
|
76
|
+
expect(c).not.toBeNull();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('computeRectangleIntersection', () => {
|
|
81
|
+
it('returns intersection rectangle', () => {
|
|
82
|
+
const r3 = createRectangle(5, 10, 10, 10);
|
|
83
|
+
const result = createRectangle();
|
|
84
|
+
computeRectangleIntersection(result, r, r3);
|
|
85
|
+
expect(result.x).toBe(5);
|
|
86
|
+
expect(result.y).toBe(10);
|
|
87
|
+
expect(result.width).toBe(5);
|
|
88
|
+
expect(result.height).toBe(10);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('returns empty rectangle if no intersection', () => {
|
|
92
|
+
const r3 = createRectangle(20, 20, 5, 5);
|
|
93
|
+
const result = createRectangle();
|
|
94
|
+
computeRectangleIntersection(result, r, r3);
|
|
95
|
+
expect(isEmptyRectangle(result)).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('correctly modifies the original rectangle when intersection is empty', () => {
|
|
99
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
100
|
+
const r2 = createRectangle(20, 20, 5, 5);
|
|
101
|
+
const result = r1;
|
|
102
|
+
computeRectangleIntersection(r1, r1, r2); // r1 is both source and target
|
|
103
|
+
|
|
104
|
+
// Ensure the result is empty (since no intersection)
|
|
105
|
+
expect(result.width).toBe(0);
|
|
106
|
+
expect(result.height).toBe(0);
|
|
107
|
+
|
|
108
|
+
// Ensure r1 is also modified correctly (should be set to empty)
|
|
109
|
+
expect(r1.width).toBe(0); // r1's width should be 0
|
|
110
|
+
expect(r1.height).toBe(0); // r1's height should be 0
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('correctly modifies the target when intersection occurs', () => {
|
|
114
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
115
|
+
const r2 = createRectangle(5, 5, 10, 10);
|
|
116
|
+
const result = r1;
|
|
117
|
+
computeRectangleIntersection(r1, r1, r2); // r1 is both source and target
|
|
118
|
+
|
|
119
|
+
// Ensure r1 is correctly modified
|
|
120
|
+
expect(result.width).toBe(5); // Correct intersection width
|
|
121
|
+
expect(result.height).toBe(5); // Correct intersection height
|
|
122
|
+
expect(r1.width).toBe(5); // Ensure r1 got updated
|
|
123
|
+
expect(r1.height).toBe(5); // Ensure r1 got updated
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('supports out === b', () => {
|
|
127
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
128
|
+
const r2 = createRectangle(5, 5, 10, 10);
|
|
129
|
+
computeRectangleIntersection(r2, r1, r2);
|
|
130
|
+
expect(r2.x).toBe(5);
|
|
131
|
+
expect(r2.y).toBe(5);
|
|
132
|
+
expect(r2.width).toBe(5);
|
|
133
|
+
expect(r2.height).toBe(5);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('allows rectangle-like objects', () => {
|
|
137
|
+
const r3 = { x: 5, y: 10, width: 10, height: 10 };
|
|
138
|
+
const result = { x: 0, y: 0, width: 0, height: 0 };
|
|
139
|
+
computeRectangleIntersection(result, r, r3);
|
|
140
|
+
expect(result.x).toBe(5);
|
|
141
|
+
expect(result.y).toBe(10);
|
|
142
|
+
expect(result.width).toBe(5);
|
|
143
|
+
expect(result.height).toBe(10);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('containsRectanglePoint', () => {
|
|
148
|
+
it('delegates to contains', () => {
|
|
149
|
+
expect(containsRectanglePoint(r, createVector2(5, 10))).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('allows point-like and rectangle-like objects', () => {
|
|
153
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
154
|
+
const p = { x: 5, y: 10 };
|
|
155
|
+
expect(containsRectanglePoint(r, p)).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('containsRectanglePointXY', () => {
|
|
160
|
+
it('returns true for a point inside', () => {
|
|
161
|
+
expect(containsRectanglePointXY(r, 5, 10)).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('returns false for a point outside', () => {
|
|
165
|
+
expect(containsRectanglePointXY(r, -1, 0)).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('works with flipped rectangle', () => {
|
|
169
|
+
r.width = -10;
|
|
170
|
+
r.height = -20;
|
|
171
|
+
expect(containsRectanglePointXY(r, -5, -10)).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('allows a rectangle-like object', () => {
|
|
175
|
+
const r = { x: 0, y: 0, width: -10, height: -20 };
|
|
176
|
+
expect(containsRectanglePointXY(r, -5, -10)).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('copyRectangle', () => {
|
|
181
|
+
it('copies values', () => {
|
|
182
|
+
copyRectangle(r, r2);
|
|
183
|
+
expect(equalsRectangle(r, r2)).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('does not change the original values if source and target are the same', () => {
|
|
187
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
188
|
+
copyRectangle(r1, r1); // r1 is both source and target
|
|
189
|
+
|
|
190
|
+
// Ensure no changes occur
|
|
191
|
+
expect(r1.x).toBe(0);
|
|
192
|
+
expect(r1.y).toBe(0);
|
|
193
|
+
expect(r1.width).toBe(10);
|
|
194
|
+
expect(r1.height).toBe(10);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('allows rectangle-like objects', () => {
|
|
198
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
199
|
+
const r2 = { x: 2, y: 2, width: 2, height: 2 };
|
|
200
|
+
copyRectangle(r2, r);
|
|
201
|
+
expect(equalsRectangle(r, r2)).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('createRectangle', () => {
|
|
206
|
+
it('initializes with default values', () => {
|
|
207
|
+
const rect = createRectangle();
|
|
208
|
+
expect(rect.x).toBe(0);
|
|
209
|
+
expect(rect.y).toBe(0);
|
|
210
|
+
expect(rect.width).toBe(0);
|
|
211
|
+
expect(rect.height).toBe(0);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('initializes with specified values', () => {
|
|
215
|
+
const rect = createRectangle(1, 2, 3, 4);
|
|
216
|
+
expect(rect.x).toBe(1);
|
|
217
|
+
expect(rect.y).toBe(2);
|
|
218
|
+
expect(rect.width).toBe(3);
|
|
219
|
+
expect(rect.height).toBe(4);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('enclosesRectangle', () => {
|
|
224
|
+
it('returns true if rectangle is fully inside', () => {
|
|
225
|
+
// r: 0,0,10,10
|
|
226
|
+
// r2: 2,2,5,5 fully inside r
|
|
227
|
+
r2.x = 2;
|
|
228
|
+
r2.y = 2;
|
|
229
|
+
r2.width = 5;
|
|
230
|
+
r2.height = 5;
|
|
231
|
+
expect(enclosesRectangle(r, r2)).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('returns false if rectangle partially outside', () => {
|
|
235
|
+
r2.x = -1; // partially outside on the left
|
|
236
|
+
r2.y = 2;
|
|
237
|
+
r2.width = 5;
|
|
238
|
+
r2.height = 5;
|
|
239
|
+
expect(enclosesRectangle(r, r2)).toBe(false);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('works with flipped rectangle fully inside', () => {
|
|
243
|
+
// Flipped rectangle: width and height negative
|
|
244
|
+
r2.x = 5;
|
|
245
|
+
r2.y = 6;
|
|
246
|
+
r2.width = -3; // left edge at 2
|
|
247
|
+
r2.height = -4; // top edge at 2
|
|
248
|
+
expect(enclosesRectangle(r, r2)).toBe(true);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('returns false if flipped rectangle exceeds bounds', () => {
|
|
252
|
+
// Flipped rectangle exceeding bounds on left/top
|
|
253
|
+
r2.x = 15;
|
|
254
|
+
r2.y = 15;
|
|
255
|
+
r2.width = -20; // left edge at -5
|
|
256
|
+
r2.height = -20; // top edge at -5
|
|
257
|
+
expect(enclosesRectangle(r, r2)).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('works if flipped rectangle exactly fits inside', () => {
|
|
261
|
+
// Flipped rectangle with exact bounds
|
|
262
|
+
r2.x = 10;
|
|
263
|
+
r2.y = 10;
|
|
264
|
+
r2.width = -10; // left edge 0
|
|
265
|
+
r2.height = -10; // top edge 0
|
|
266
|
+
expect(enclosesRectangle(r, r2)).toBe(true);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('returns false if zero-size rectangle outside', () => {
|
|
270
|
+
r2.x = 20;
|
|
271
|
+
r2.y = 20;
|
|
272
|
+
r2.width = 0;
|
|
273
|
+
r2.height = 0;
|
|
274
|
+
expect(enclosesRectangle(r, r2)).toBe(false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('returns true if zero-size rectangle exactly on a corner', () => {
|
|
278
|
+
r2.x = 0;
|
|
279
|
+
r2.y = 0;
|
|
280
|
+
r2.width = 0;
|
|
281
|
+
r2.height = 0;
|
|
282
|
+
expect(enclosesRectangle(r, r2)).toBe(true);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('allows a rectangle-like object', () => {
|
|
286
|
+
// r: 0,0,10,10
|
|
287
|
+
// r2: 2,2,5,5 fully inside r
|
|
288
|
+
const r2 = { x: 2, y: 2, width: 5, height: 5 };
|
|
289
|
+
expect(enclosesRectangle(r, r2)).toBe(true);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('equalsRectangle', () => {
|
|
294
|
+
it('returns true for identical rectangles', () => {
|
|
295
|
+
expect(equalsRectangle(r, r)).toBe(true);
|
|
296
|
+
expect(equalsRectangle(r, cloneRectangle(r))).toBe(true);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('returns false for different rectangles', () => {
|
|
300
|
+
r2.x = 1;
|
|
301
|
+
expect(equalsRectangle(r, r2)).toBe(false);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('allows rectangle like objects', () => {
|
|
305
|
+
const r = { x: 1, y: 1, width: 1, height: 1 };
|
|
306
|
+
const r2 = { x: 1, y: 1, width: 1, height: 1 };
|
|
307
|
+
expect(equalsRectangle(r, r)).toBe(true);
|
|
308
|
+
expect(equalsRectangle(r, r2)).toBe(true);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe('expandRectangleToPoint', () => {
|
|
313
|
+
it('inflates rectangle by Vector2', () => {
|
|
314
|
+
const result = createRectangle();
|
|
315
|
+
expandRectangleToPoint(result, r, createVector2(1, 2));
|
|
316
|
+
expect(result).not.toBe(r);
|
|
317
|
+
expect(result.x).toBe(-1);
|
|
318
|
+
expect(result.y).toBe(-2);
|
|
319
|
+
expect(result.width).toBe(12);
|
|
320
|
+
expect(result.height).toBe(24);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('allows rectangle- and point-like objects', () => {
|
|
324
|
+
const r = { x: 0, y: 0, width: 10, height: 20 };
|
|
325
|
+
const p = { x: 1, y: 2 };
|
|
326
|
+
const result = { x: 0, y: 0, width: 0, height: 0 };
|
|
327
|
+
expandRectangleToPoint(result, r, p);
|
|
328
|
+
expect(result.x).toBe(-1);
|
|
329
|
+
expect(result.y).toBe(-2);
|
|
330
|
+
expect(result.width).toBe(12);
|
|
331
|
+
expect(result.height).toBe(24);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
describe('getRectangleBottom', () => {
|
|
336
|
+
it('returns y + height', () => {
|
|
337
|
+
expect(getRectangleBottom(r)).toBe(20);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('allows a rectangle-like object', () => {
|
|
341
|
+
const r = { x: 0, y: 0, width: 10, height: 20 };
|
|
342
|
+
expect(getRectangleBottom(r)).toBe(20);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('getRectangleBottomRight', () => {
|
|
347
|
+
it('returns correct Vector2', () => {
|
|
348
|
+
const br = createVector2();
|
|
349
|
+
getRectangleBottomRight(br, r);
|
|
350
|
+
expect(br.x).toBe(10);
|
|
351
|
+
expect(br.y).toBe(20);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
describe('getRectangleLeft', () => {
|
|
356
|
+
it('returns x', () => {
|
|
357
|
+
expect(getRectangleLeft(r)).toBe(0);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
describe('getRectangleMaxX', () => {
|
|
362
|
+
it('returns correct maximum X for positive rectangle', () => {
|
|
363
|
+
expect(getRectangleMaxX(r)).toBe(10);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('returns correct maximum X for flipped rectangle', () => {
|
|
367
|
+
r.width = -5;
|
|
368
|
+
expect(getRectangleMaxX(r)).toBe(0);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('allows a rectangle-like object', () => {
|
|
372
|
+
const r = { x: 0, y: 0, width: 10, height: 10 };
|
|
373
|
+
expect(getRectangleMaxX(r)).toBe(10);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('getRectangleMaxY', () => {
|
|
378
|
+
it('returns correct maximum Y for positive rectangle', () => {
|
|
379
|
+
expect(getRectangleMaxY(r)).toBe(20);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('returns correct maximum Y for flipped rectangle', () => {
|
|
383
|
+
r.height = -10;
|
|
384
|
+
expect(getRectangleMaxY(r)).toBe(0);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it('allows a rectangle-like object', () => {
|
|
388
|
+
const r = { x: 0, y: 0, width: 10, height: 10 };
|
|
389
|
+
expect(getRectangleMaxY(r)).toBe(10);
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
describe('getRectangleMinX', () => {
|
|
394
|
+
it('returns correct minimum X for positive rectangle', () => {
|
|
395
|
+
expect(getRectangleMinX(r)).toBe(0);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('returns correct minimum X for flipped rectangle', () => {
|
|
399
|
+
r.width = -5;
|
|
400
|
+
expect(getRectangleMinX(r)).toBe(-5);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('allows a rectangle-like object', () => {
|
|
404
|
+
const r = { x: 0, y: 0, width: 10, height: 10 };
|
|
405
|
+
expect(getRectangleMinX(r)).toBe(0);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
describe('getRectangleMinY', () => {
|
|
410
|
+
it('returns correct minimum Y for positive rectangle', () => {
|
|
411
|
+
expect(getRectangleMinY(r)).toBe(0);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('returns correct minimum Y for flipped rectangle', () => {
|
|
415
|
+
r.height = -10;
|
|
416
|
+
expect(getRectangleMinY(r)).toBe(-10);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('allows a rectangle-like object', () => {
|
|
420
|
+
const r = { x: 0, y: 0, width: 10, height: 10 };
|
|
421
|
+
expect(getRectangleMinY(r)).toBe(0);
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
describe('getRectangleNormalizedBottomRight', () => {
|
|
426
|
+
it('return proper Vector2s', () => {
|
|
427
|
+
r.x = 10;
|
|
428
|
+
r.y = 20;
|
|
429
|
+
r.width = -5;
|
|
430
|
+
r.height = -15;
|
|
431
|
+
const nbr = createVector2();
|
|
432
|
+
getRectangleNormalizedBottomRight(nbr, r);
|
|
433
|
+
expect(nbr.x).toBe(10);
|
|
434
|
+
expect(nbr.y).toBe(20);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('match min/max for positive rectangles', () => {
|
|
438
|
+
r.x = 2;
|
|
439
|
+
r.y = 3;
|
|
440
|
+
r.width = 10;
|
|
441
|
+
r.height = 15;
|
|
442
|
+
const nbr = createVector2();
|
|
443
|
+
getRectangleNormalizedBottomRight(nbr, r);
|
|
444
|
+
expect(nbr.x).toBe(getRectangleMaxX(r));
|
|
445
|
+
expect(nbr.y).toBe(getRectangleMaxY(r));
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('allows Rectangle-like objects', () => {
|
|
449
|
+
const r = { x: 10, y: 20, width: -5, height: -15 };
|
|
450
|
+
const nbr = { x: 0, y: 0 };
|
|
451
|
+
getRectangleNormalizedBottomRight(nbr, r);
|
|
452
|
+
expect(nbr.x).toBe(10);
|
|
453
|
+
expect(nbr.y).toBe(20);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
describe('getRectangleNormalizedTopLeft', () => {
|
|
458
|
+
it('return proper Vector2s', () => {
|
|
459
|
+
r.x = 10;
|
|
460
|
+
r.y = 20;
|
|
461
|
+
r.width = -5;
|
|
462
|
+
r.height = -15;
|
|
463
|
+
const ntl = createVector2();
|
|
464
|
+
getRectangleNormalizedTopLeft(ntl, r);
|
|
465
|
+
expect(ntl.x).toBe(5);
|
|
466
|
+
expect(ntl.y).toBe(5);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('match min/max for positive rectangles', () => {
|
|
470
|
+
r.x = 2;
|
|
471
|
+
r.y = 3;
|
|
472
|
+
r.width = 10;
|
|
473
|
+
r.height = 15;
|
|
474
|
+
const ntl = createVector2();
|
|
475
|
+
getRectangleNormalizedTopLeft(ntl, r);
|
|
476
|
+
expect(ntl.x).toBe(getRectangleMinX(r));
|
|
477
|
+
expect(ntl.y).toBe(getRectangleMinY(r));
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it('allows rectangle-like objects', () => {
|
|
481
|
+
const r = { x: 10, y: 20, width: -5, height: -15 };
|
|
482
|
+
let ntl = { x: 0, y: 0 };
|
|
483
|
+
getRectangleNormalizedTopLeft(ntl, r);
|
|
484
|
+
expect(ntl.x).toBe(5);
|
|
485
|
+
expect(ntl.y).toBe(5);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
describe('getRectangleRight', () => {
|
|
490
|
+
it('getter returns x + width', () => {
|
|
491
|
+
expect(getRectangleRight(r)).toBe(10);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('allows a rectangle-like object', () => {
|
|
495
|
+
const r = { x: 5, y: 0, width: 5, height: 0 };
|
|
496
|
+
expect(getRectangleRight(r)).toBe(10);
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
describe('getRectangleSize', () => {
|
|
501
|
+
it('returns width and height as Vector2', () => {
|
|
502
|
+
const s = createVector2();
|
|
503
|
+
getRectangleSize(s, r);
|
|
504
|
+
expect(s.x).toBe(10);
|
|
505
|
+
expect(s.y).toBe(20);
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
describe('getRectangleTop', () => {
|
|
510
|
+
it('returns y', () => {
|
|
511
|
+
expect(getRectangleTop(r)).toBe(0);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
describe('getRectangleTopLeft', () => {
|
|
516
|
+
it('getter returns top-left Vector2', () => {
|
|
517
|
+
const tl = createVector2();
|
|
518
|
+
getRectangleTopLeft(tl, r);
|
|
519
|
+
expect(tl.x).toBe(0);
|
|
520
|
+
expect(tl.y).toBe(0);
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it('allows point-like objects', () => {
|
|
524
|
+
const r = { x: 0, y: 0, height: 0, width: 0 };
|
|
525
|
+
let tl = { x: 0, y: 0 };
|
|
526
|
+
getRectangleTopLeft(tl, r);
|
|
527
|
+
expect(tl.x).toBe(0);
|
|
528
|
+
expect(tl.y).toBe(0);
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
describe('inflateRectangle', () => {
|
|
533
|
+
it('inflates rectangle by dx/dy', () => {
|
|
534
|
+
const result = createRectangle();
|
|
535
|
+
inflateRectangle(result, r, 2, 3);
|
|
536
|
+
expect(result).not.toBe(r);
|
|
537
|
+
expect(result.x).toBe(-2);
|
|
538
|
+
expect(result.y).toBe(-3);
|
|
539
|
+
expect(result.width).toBe(14);
|
|
540
|
+
expect(result.height).toBe(26);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it('correctly inflates the rectangle when it is both source and target', () => {
|
|
544
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
545
|
+
inflateRectangle(r1, r1, 2, 3); // r1 is both source and target
|
|
546
|
+
|
|
547
|
+
// Ensure r1 is correctly inflated
|
|
548
|
+
expect(r1.x).toBe(-2);
|
|
549
|
+
expect(r1.y).toBe(-3);
|
|
550
|
+
expect(r1.width).toBe(14);
|
|
551
|
+
expect(r1.height).toBe(16);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
it('allows rectangle-like objects', () => {
|
|
555
|
+
const r = { x: 0, y: 0, width: 10, height: 20 };
|
|
556
|
+
const result = { x: 0, y: 0, width: 0, height: 0 };
|
|
557
|
+
inflateRectangle(result, r, 2, 3);
|
|
558
|
+
expect(result).not.toBe(r);
|
|
559
|
+
expect(result.x).toBe(-2);
|
|
560
|
+
expect(result.y).toBe(-3);
|
|
561
|
+
expect(result.width).toBe(14);
|
|
562
|
+
expect(result.height).toBe(26);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
describe('intersectsRectangle', () => {
|
|
567
|
+
it('returns true if rectangles overlap', () => {
|
|
568
|
+
const r3 = createRectangle(5, 10, 10, 10);
|
|
569
|
+
expect(intersectsRectangle(r, r3)).toBe(true);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('returns false if rectangles do not overlap', () => {
|
|
573
|
+
const r3 = createRectangle(20, 20, 5, 5);
|
|
574
|
+
expect(intersectsRectangle(r, r3)).toBe(false);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
it('allows rectangle-like objects', () => {
|
|
578
|
+
const r3 = { x: 5, y: 10, width: 10, height: 10 };
|
|
579
|
+
expect(intersectsRectangle(r, r3)).toBe(true);
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
describe('isEmptyRectangle', () => {
|
|
584
|
+
it('returns true only for zero width or height', () => {
|
|
585
|
+
expect(isEmptyRectangle(r)).toBe(false);
|
|
586
|
+
r.width = 0;
|
|
587
|
+
expect(isEmptyRectangle(r)).toBe(true);
|
|
588
|
+
r.width = 10;
|
|
589
|
+
r.height = 0;
|
|
590
|
+
expect(isEmptyRectangle(r)).toBe(true);
|
|
591
|
+
r.width = -5;
|
|
592
|
+
r.height = -5;
|
|
593
|
+
expect(isEmptyRectangle(r)).toBe(false); // flipped rectangles are valid
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('allows rectangle-like objects', () => {
|
|
597
|
+
const r = { x: 0, y: 0, width: 10, height: 10 };
|
|
598
|
+
expect(isEmptyRectangle(r)).toBe(false);
|
|
599
|
+
r.width = 0;
|
|
600
|
+
expect(isEmptyRectangle(r)).toBe(true);
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
describe('isFlippedXRectangle', () => {
|
|
605
|
+
it('returns false if width is positive', () => {
|
|
606
|
+
expect(isFlippedXRectangle(r)).toBe(false);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
it('returns false if width is negative', () => {
|
|
610
|
+
r.width = -10;
|
|
611
|
+
expect(isFlippedXRectangle(r)).toBe(true);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it('allows a rectangle-like object', () => {
|
|
615
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
616
|
+
expect(isFlippedXRectangle(r)).toBe(false);
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
describe('isFlippedYRectangle', () => {
|
|
621
|
+
it('returns false if height is positive', () => {
|
|
622
|
+
expect(isFlippedYRectangle(r)).toBe(false);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('returns false if height is negative', () => {
|
|
626
|
+
r.height = -20;
|
|
627
|
+
expect(isFlippedYRectangle(r)).toBe(true);
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
it('allows a rectangle-like object', () => {
|
|
631
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
632
|
+
expect(isFlippedYRectangle(r)).toBe(false);
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
describe('mergeRectangle', () => {
|
|
637
|
+
it('returns union of two rectangles', () => {
|
|
638
|
+
const r3 = createRectangle(5, 15, 10, 10);
|
|
639
|
+
const u = createRectangle();
|
|
640
|
+
mergeRectangle(u, r, r3);
|
|
641
|
+
expect(u.x).toBe(0);
|
|
642
|
+
expect(u.y).toBe(0);
|
|
643
|
+
expect(u.width).toBe(15);
|
|
644
|
+
expect(u.height).toBe(25);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('union works with zero-width rectangle', () => {
|
|
648
|
+
const r3 = createRectangle(5, 15, 0, 0);
|
|
649
|
+
const u = createRectangle();
|
|
650
|
+
mergeRectangle(u, r, r3);
|
|
651
|
+
expect(equalsRectangle(u, r)).toBe(true);
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it('has the values of the right-hand rectangle if the left-hand is degenerate', () => {
|
|
655
|
+
const lh = createRectangle();
|
|
656
|
+
const rh = createRectangle(5, 15, 100, 100);
|
|
657
|
+
const out = createRectangle();
|
|
658
|
+
mergeRectangle(out, lh, rh);
|
|
659
|
+
expect(equalsRectangle(out, rh)).toBe(true);
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it('has the values of the left-hand rectangle if the right-hand is degenerate', () => {
|
|
663
|
+
const lh = createRectangle(5, 15, 100, 100);
|
|
664
|
+
const rh = createRectangle();
|
|
665
|
+
const out = createRectangle();
|
|
666
|
+
mergeRectangle(out, lh, rh);
|
|
667
|
+
expect(equalsRectangle(out, lh)).toBe(true);
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it('returns an empty rectangle if both are degenerate', () => {
|
|
671
|
+
const lh = createRectangle(-50, -150, 0, 0);
|
|
672
|
+
const rh = createRectangle(-5, -15, 0, 0);
|
|
673
|
+
const out = createRectangle();
|
|
674
|
+
mergeRectangle(out, lh, rh);
|
|
675
|
+
expect(isEmptyRectangle(out)).toBe(true);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
it('returns the x/y of the left-hand rectangle if both are degenerate', () => {
|
|
679
|
+
const lh = createRectangle(-50, -150, 0, 0);
|
|
680
|
+
const rh = createRectangle(-5, -15, 0, 0);
|
|
681
|
+
const out = createRectangle();
|
|
682
|
+
mergeRectangle(out, lh, rh);
|
|
683
|
+
expect(equalsRectangle(out, lh)).toBe(true);
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
it('does nothing if right-hand is empty and source===out', () => {
|
|
687
|
+
const lh = createRectangle(-50, -150, 0, 0);
|
|
688
|
+
const rh = createRectangle(-5, -15, 0, 0);
|
|
689
|
+
const cache = createRectangle();
|
|
690
|
+
copyRectangle(cache, lh);
|
|
691
|
+
mergeRectangle(lh, lh, rh);
|
|
692
|
+
expect(equalsRectangle(cache, lh)).toBe(true);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('union works with flipped rectangles', () => {
|
|
696
|
+
const r3 = createRectangle(15, 20, -10, -10);
|
|
697
|
+
const u = createRectangle();
|
|
698
|
+
mergeRectangle(u, r, r3);
|
|
699
|
+
expect(u.x).toBe(0);
|
|
700
|
+
expect(u.y).toBe(0);
|
|
701
|
+
expect(u.width).toBe(15);
|
|
702
|
+
expect(u.height).toBe(20);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('correctly modifies the target when union occurs', () => {
|
|
706
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
707
|
+
const r2 = createRectangle(5, 5, 10, 10);
|
|
708
|
+
const result = r1;
|
|
709
|
+
mergeRectangle(r1, r1, r2); // r1 is both source and target
|
|
710
|
+
|
|
711
|
+
// Ensure r1 is correctly updated
|
|
712
|
+
expect(result.width).toBe(15); // Correct union width
|
|
713
|
+
expect(result.height).toBe(15); // Correct union height
|
|
714
|
+
expect(r1.width).toBe(15); // r1 should be updated
|
|
715
|
+
expect(r1.height).toBe(15); // r1 should be updated
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
it('correctly handles union of non-overlapping rectangles', () => {
|
|
719
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
720
|
+
const r2 = createRectangle(20, 20, 5, 5);
|
|
721
|
+
const result = r1;
|
|
722
|
+
mergeRectangle(r1, r1, r2); // r1 is both source and target
|
|
723
|
+
|
|
724
|
+
// Ensure r1 is correctly updated
|
|
725
|
+
expect(result.width).toBe(25); // Correct union width
|
|
726
|
+
expect(result.height).toBe(25); // Correct union height
|
|
727
|
+
expect(r1.width).toBe(25); // r1 should be updated
|
|
728
|
+
expect(r1.height).toBe(25); // r1 should be updated
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('supports out === other', () => {
|
|
732
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
733
|
+
const r2 = createRectangle(5, 5, 10, 10);
|
|
734
|
+
mergeRectangle(r2, r1, r2);
|
|
735
|
+
expect(r2.x).toBe(0);
|
|
736
|
+
expect(r2.y).toBe(0);
|
|
737
|
+
expect(r2.width).toBe(15);
|
|
738
|
+
expect(r2.height).toBe(15);
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it('allows rectangle-like objects', () => {
|
|
742
|
+
const r = { x: 0, y: 0, width: 10, height: 20 };
|
|
743
|
+
const r3 = { x: 5, y: 15, width: 10, height: 10 };
|
|
744
|
+
const u = { x: 0, y: 0, width: 0, height: 0 };
|
|
745
|
+
mergeRectangle(u, r, r3);
|
|
746
|
+
expect(u.x).toBe(0);
|
|
747
|
+
expect(u.y).toBe(0);
|
|
748
|
+
expect(u.width).toBe(15);
|
|
749
|
+
expect(u.height).toBe(25);
|
|
750
|
+
});
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
describe('normalizeRectangle', () => {
|
|
754
|
+
it('returns rectangle with positive width and height', () => {
|
|
755
|
+
r.x = 10;
|
|
756
|
+
r.y = 20;
|
|
757
|
+
r.width = -5;
|
|
758
|
+
r.height = -15;
|
|
759
|
+
const n = createRectangle();
|
|
760
|
+
normalizeRectangle(n, r);
|
|
761
|
+
expect(n.x).toBe(5);
|
|
762
|
+
expect(n.y).toBe(5);
|
|
763
|
+
expect(n.width).toBe(5);
|
|
764
|
+
expect(n.height).toBe(15);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it('supports out === source', () => {
|
|
768
|
+
const rect = createRectangle(10, 20, -5, -15);
|
|
769
|
+
normalizeRectangle(rect, rect);
|
|
770
|
+
expect(rect.x).toBe(5);
|
|
771
|
+
expect(rect.y).toBe(5);
|
|
772
|
+
expect(rect.width).toBe(5);
|
|
773
|
+
expect(rect.height).toBe(15);
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
it('normalized of positive rectangle equals original', () => {
|
|
777
|
+
const n = createRectangle();
|
|
778
|
+
normalizeRectangle(n, r);
|
|
779
|
+
expect(n.x).toBe(r.x);
|
|
780
|
+
expect(n.y).toBe(r.y);
|
|
781
|
+
expect(n.width).toBe(r.width);
|
|
782
|
+
expect(n.height).toBe(r.height);
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it('allows rectangle-like objects', () => {
|
|
786
|
+
const r = { x: 10, y: 20, width: -5, height: -15 };
|
|
787
|
+
const n = { x: 0, y: 0, width: 0, height: 0 };
|
|
788
|
+
normalizeRectangle(n, r);
|
|
789
|
+
expect(n.x).toBe(5);
|
|
790
|
+
expect(n.y).toBe(5);
|
|
791
|
+
expect(n.width).toBe(5);
|
|
792
|
+
expect(n.height).toBe(15);
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
describe('offsetRectangle', () => {
|
|
797
|
+
it('moves rectangle', () => {
|
|
798
|
+
const result = createRectangle();
|
|
799
|
+
offsetRectangle(result, r, 5, 10);
|
|
800
|
+
expect(result.x).toBe(5);
|
|
801
|
+
expect(result.y).toBe(10);
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
it('correctly offsets the rectangle when it is both source and target', () => {
|
|
805
|
+
const r1 = createRectangle(0, 0, 10, 10);
|
|
806
|
+
offsetRectangle(r1, r1, 5, 10); // r1 is both source and target
|
|
807
|
+
|
|
808
|
+
// Ensure r1 is correctly offset
|
|
809
|
+
expect(r1.x).toBe(5);
|
|
810
|
+
expect(r1.y).toBe(10);
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
it('allows rectangle-like objects', () => {
|
|
814
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
815
|
+
const result = { x: 0, y: 0, width: 0, height: 0 };
|
|
816
|
+
offsetRectangle(result, r, 5, 10);
|
|
817
|
+
expect(result.x).toBe(5);
|
|
818
|
+
expect(result.y).toBe(10);
|
|
819
|
+
});
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
describe('offsetRectangleByPoint', () => {
|
|
823
|
+
it('moves rectangle by Vector2', () => {
|
|
824
|
+
const out = createRectangle();
|
|
825
|
+
offsetRectangleByPoint(out, r, createVector2(3, 4));
|
|
826
|
+
expect(out.x).toBe(3);
|
|
827
|
+
expect(out.y).toBe(4);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
it('allows rectangle- and point-like objects', () => {
|
|
831
|
+
const r = { x: 0, y: 0, width: 100, height: 100 };
|
|
832
|
+
const p = { x: 3, y: 4 };
|
|
833
|
+
const out = { x: 0, y: 0, width: 0, height: 0 };
|
|
834
|
+
offsetRectangleByPoint(out, r, p);
|
|
835
|
+
expect(out.x).toBe(3);
|
|
836
|
+
expect(out.y).toBe(4);
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
describe('setEmptyRectangle', () => {
|
|
841
|
+
it('sets rectangle to zero', () => {
|
|
842
|
+
setEmptyRectangle(r);
|
|
843
|
+
expect(r.x).toBe(0);
|
|
844
|
+
expect(r.y).toBe(0);
|
|
845
|
+
expect(r.width).toBe(0);
|
|
846
|
+
expect(r.height).toBe(0);
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
it('allows rectangle-like objects', () => {
|
|
850
|
+
const r = { x: 10, y: 20, width: -5, height: -15 };
|
|
851
|
+
setEmptyRectangle(r);
|
|
852
|
+
expect(r.x).toBe(0);
|
|
853
|
+
expect(r.y).toBe(0);
|
|
854
|
+
expect(r.width).toBe(0);
|
|
855
|
+
expect(r.height).toBe(0);
|
|
856
|
+
});
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
describe('setRectangle', () => {
|
|
860
|
+
it('sets rectangle to specified values', () => {
|
|
861
|
+
setRectangle(r, 1, 2, 3, 4);
|
|
862
|
+
expect(r.x).toBe(1);
|
|
863
|
+
expect(r.y).toBe(2);
|
|
864
|
+
expect(r.width).toBe(3);
|
|
865
|
+
expect(r.height).toBe(4);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
it('allows rectangle-like objects', () => {
|
|
869
|
+
const r = { x: 10, y: 20, width: -5, height: -15 };
|
|
870
|
+
setRectangle(r, 1, 2, 3, 4);
|
|
871
|
+
expect(r.x).toBe(1);
|
|
872
|
+
expect(r.y).toBe(2);
|
|
873
|
+
expect(r.width).toBe(3);
|
|
874
|
+
expect(r.height).toBe(4);
|
|
875
|
+
});
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
describe('setRectangleBottom', () => {
|
|
879
|
+
it('adjusts height so that y + height equals value', () => {
|
|
880
|
+
const rect = createRectangle(0, 10, 5, 5);
|
|
881
|
+
setRectangleBottom(rect, 30);
|
|
882
|
+
expect(rect.height).toBe(20);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('can set bottom to equal y (zero height)', () => {
|
|
886
|
+
const rect = createRectangle(0, 5, 10, 10);
|
|
887
|
+
setRectangleBottom(rect, 5);
|
|
888
|
+
expect(rect.height).toBe(0);
|
|
889
|
+
});
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
describe('setRectangleBottomRight', () => {
|
|
893
|
+
it('adjusts width and height', () => {
|
|
894
|
+
setRectangleBottomRight(r, createVector2(15, 25));
|
|
895
|
+
expect(r.width).toBe(15);
|
|
896
|
+
expect(r.height).toBe(25);
|
|
897
|
+
});
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
describe('setRectangleLeft', () => {
|
|
901
|
+
it('adjusts width correctly', () => {
|
|
902
|
+
setRectangleLeft(r, 5);
|
|
903
|
+
expect(r.x).toBe(5);
|
|
904
|
+
expect(r.width).toBe(5);
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
describe('setRectangleRight', () => {
|
|
909
|
+
it('adjusts width', () => {
|
|
910
|
+
setRectangleRight(r, 15);
|
|
911
|
+
expect(r.width).toBe(15);
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
it('accounts for x', () => {
|
|
915
|
+
r.x = 10;
|
|
916
|
+
setRectangleRight(r, 15);
|
|
917
|
+
expect(r.width).toBe(5);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
it('can create negative width (flipped rectangle)', () => {
|
|
921
|
+
setRectangleRight(r, -5);
|
|
922
|
+
expect(r.width).toBe(-5);
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
describe('setRectangleSize', () => {
|
|
927
|
+
it('setter adjusts width and height', () => {
|
|
928
|
+
setRectangleSize(r, createVector2(5, 6));
|
|
929
|
+
expect(r.width).toBe(5);
|
|
930
|
+
expect(r.height).toBe(6);
|
|
931
|
+
});
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
describe('setRectangleTop', () => {
|
|
935
|
+
it('adjusts height correctly', () => {
|
|
936
|
+
setRectangleTop(r, 5);
|
|
937
|
+
expect(r.y).toBe(5);
|
|
938
|
+
expect(r.height).toBe(15);
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
it('can create negative height (flipped rectangle)', () => {
|
|
942
|
+
setRectangleTop(r, 25);
|
|
943
|
+
expect(r.height).toBe(-5);
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
describe('setRectangleTopLeft', () => {
|
|
948
|
+
it('setter updates x and y', () => {
|
|
949
|
+
const out = createRectangle();
|
|
950
|
+
setRectangleTopLeft(out, createVector2(3, 4));
|
|
951
|
+
expect(out.x).toBe(3);
|
|
952
|
+
expect(out.y).toBe(4);
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
it('allows point-like objects', () => {
|
|
956
|
+
const r = { x: 0, y: 0, height: 0, width: 0 };
|
|
957
|
+
let tl = { x: 10, y: 10 };
|
|
958
|
+
setRectangleTopLeft(r, tl);
|
|
959
|
+
expect(r.x).toBe(10);
|
|
960
|
+
expect(r.y).toBe(10);
|
|
961
|
+
});
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
describe('setTo', () => {
|
|
965
|
+
it('assigns all four properties', () => {
|
|
966
|
+
const rect = createRectangle();
|
|
967
|
+
setRectangle(rect, 1, 2, 3, 4);
|
|
968
|
+
expect(rect.x).toBe(1);
|
|
969
|
+
expect(rect.y).toBe(2);
|
|
970
|
+
expect(rect.width).toBe(3);
|
|
971
|
+
expect(rect.height).toBe(4);
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
it('overwrites existing values', () => {
|
|
975
|
+
const rect = createRectangle(10, 20, 30, 40);
|
|
976
|
+
setRectangle(rect, 0, 0, 0, 0);
|
|
977
|
+
expect(rect.x).toBe(0);
|
|
978
|
+
expect(rect.y).toBe(0);
|
|
979
|
+
expect(rect.width).toBe(0);
|
|
980
|
+
expect(rect.height).toBe(0);
|
|
981
|
+
});
|
|
982
|
+
});
|