1/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE. */
20
21describe("vec2", function() {
22    var vec2 = require("../../src/gl-matrix/vec2.js");
23
24    var out, vecA, vecB, result;
25
26    beforeEach(function() { vecA = [1, 2]; vecB = [3, 4]; out = [0, 0]; });
27
28    describe("create", function() {
29        beforeEach(function() { result = vec2.create(); });
30        it("should return a 2 element array initialized to 0s", function() { expect(result).toBeEqualish([0, 0]); });
31    });
32
33    describe("clone", function() {
34        beforeEach(function() { result = vec2.clone(vecA); });
35        it("should return a 2 element array initialized to the values in vecA", function() { expect(result).toBeEqualish(vecA); });
36    });
37
38    describe("fromValues", function() {
39        beforeEach(function() { result = vec2.fromValues(1, 2); });
40        it("should return a 2 element array initialized to the values passed", function() { expect(result).toBeEqualish([1, 2]); });
41    });
42
43    describe("copy", function() {
44        beforeEach(function() { result = vec2.copy(out, vecA); });
45        it("should place values into out", function() { expect(out).toBeEqualish([1, 2]); });
46        it("should return out", function() { expect(result).toBe(out); });
47    });
48
49    describe("set", function() {
50        beforeEach(function() { result = vec2.set(out, 1, 2); });
51        it("should place values into out", function() { expect(out).toBeEqualish([1, 2]); });
52        it("should return out", function() { expect(result).toBe(out); });
53    });
54
55    describe("add", function() {
56        describe("with a separate output vector", function() {
57            beforeEach(function() { result = vec2.add(out, vecA, vecB); });
58
59            it("should place values into out", function() { expect(out).toBeEqualish([4, 6]); });
60            it("should return out", function() { expect(result).toBe(out); });
61            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
62            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
63        });
64
65        describe("when vecA is the output vector", function() {
66            beforeEach(function() { result = vec2.add(vecA, vecA, vecB); });
67
68            it("should place values into vecA", function() { expect(vecA).toBeEqualish([4, 6]); });
69            it("should return vecA", function() { expect(result).toBe(vecA); });
70            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
71        });
72
73        describe("when vecB is the output vector", function() {
74            beforeEach(function() { result = vec2.add(vecB, vecA, vecB); });
75
76            it("should place values into vecB", function() { expect(vecB).toBeEqualish([4, 6]); });
77            it("should return vecB", function() { expect(result).toBe(vecB); });
78            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
79        });
80    });
81
82    describe("subtract", function() {
83        it("should have an alias called 'sub'", function() { expect(vec2.sub).toEqual(vec2.subtract); });
84
85        describe("with a separate output vector", function() {
86            beforeEach(function() { result = vec2.subtract(out, vecA, vecB); });
87
88            it("should place values into out", function() { expect(out).toBeEqualish([-2, -2]); });
89            it("should return out", function() { expect(result).toBe(out); });
90            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
91            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
92        });
93
94        describe("when vecA is the output vector", function() {
95            beforeEach(function() { result = vec2.subtract(vecA, vecA, vecB); });
96
97            it("should place values into vecA", function() { expect(vecA).toBeEqualish([-2, -2]); });
98            it("should return vecA", function() { expect(result).toBe(vecA); });
99            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
100        });
101
102        describe("when vecB is the output vector", function() {
103            beforeEach(function() { result = vec2.subtract(vecB, vecA, vecB); });
104
105            it("should place values into vecB", function() { expect(vecB).toBeEqualish([-2, -2]); });
106            it("should return vecB", function() { expect(result).toBe(vecB); });
107            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
108        });
109    });
110
111    describe("multiply", function() {
112        it("should have an alias called 'mul'", function() { expect(vec2.mul).toEqual(vec2.multiply); });
113
114        describe("with a separate output vector", function() {
115            beforeEach(function() { result = vec2.multiply(out, vecA, vecB); });
116
117            it("should place values into out", function() { expect(out).toBeEqualish([3, 8]); });
118            it("should return out", function() { expect(result).toBe(out); });
119            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
120            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
121        });
122
123        describe("when vecA is the output vector", function() {
124            beforeEach(function() { result = vec2.multiply(vecA, vecA, vecB); });
125
126            it("should place values into vecA", function() { expect(vecA).toBeEqualish([3, 8]); });
127            it("should return vecA", function() { expect(result).toBe(vecA); });
128            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
129        });
130
131        describe("when vecB is the output vector", function() {
132            beforeEach(function() { result = vec2.multiply(vecB, vecA, vecB); });
133
134            it("should place values into vecB", function() { expect(vecB).toBeEqualish([3, 8]); });
135            it("should return vecB", function() { expect(result).toBe(vecB); });
136            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
137        });
138    });
139
140    describe("divide", function() {
141        it("should have an alias called 'div'", function() { expect(vec2.div).toEqual(vec2.divide); });
142
143        describe("with a separate output vector", function() {
144            beforeEach(function() { result = vec2.divide(out, vecA, vecB); });
145
146            it("should place values into out", function() { expect(out).toBeEqualish([0.3333333, 0.5]); });
147            it("should return out", function() { expect(result).toBe(out); });
148            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
149            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
150        });
151
152        describe("when vecA is the output vector", function() {
153            beforeEach(function() { result = vec2.divide(vecA, vecA, vecB); });
154
155            it("should place values into vecA", function() { expect(vecA).toBeEqualish([0.3333333, 0.5]); });
156            it("should return vecA", function() { expect(result).toBe(vecA); });
157            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
158        });
159
160        describe("when vecB is the output vector", function() {
161            beforeEach(function() { result = vec2.divide(vecB, vecA, vecB); });
162
163            it("should place values into vecB", function() { expect(vecB).toBeEqualish([0.3333333, 0.5]); });
164            it("should return vecB", function() { expect(result).toBe(vecB); });
165            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
166        });
167    });
168
169    describe("min", function() {
170        beforeEach(function() { vecA = [1, 4]; vecB = [3, 2]; });
171
172        describe("with a separate output vector", function() {
173            beforeEach(function() { result = vec2.min(out, vecA, vecB); });
174
175            it("should place values into out", function() { expect(out).toBeEqualish([1, 2]); });
176            it("should return out", function() { expect(result).toBe(out); });
177            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 4]); });
178            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 2]); });
179        });
180
181        describe("when vecA is the output vector", function() {
182            beforeEach(function() { result = vec2.min(vecA, vecA, vecB); });
183
184            it("should place values into vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
185            it("should return vecA", function() { expect(result).toBe(vecA); });
186            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 2]); });
187        });
188
189        describe("when vecB is the output vector", function() {
190            beforeEach(function() { result = vec2.min(vecB, vecA, vecB); });
191
192            it("should place values into vecB", function() { expect(vecB).toBeEqualish([1, 2]); });
193            it("should return vecB", function() { expect(result).toBe(vecB); });
194            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 4]); });
195        });
196    });
197
198    describe("max", function() {
199        beforeEach(function() { vecA = [1, 4]; vecB = [3, 2]; });
200
201        describe("with a separate output vector", function() {
202            beforeEach(function() { result = vec2.max(out, vecA, vecB); });
203
204            it("should place values into out", function() { expect(out).toBeEqualish([3, 4]); });
205            it("should return out", function() { expect(result).toBe(out); });
206            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 4]); });
207            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 2]); });
208        });
209
210        describe("when vecA is the output vector", function() {
211            beforeEach(function() { result = vec2.max(vecA, vecA, vecB); });
212
213            it("should place values into vecA", function() { expect(vecA).toBeEqualish([3, 4]); });
214            it("should return vecA", function() { expect(result).toBe(vecA); });
215            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 2]); });
216        });
217
218        describe("when vecB is the output vector", function() {
219            beforeEach(function() { result = vec2.max(vecB, vecA, vecB); });
220
221            it("should place values into vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
222            it("should return vecB", function() { expect(result).toBe(vecB); });
223            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 4]); });
224        });
225    });
226
227    describe("scale", function() {
228        describe("with a separate output vector", function() {
229            beforeEach(function() { result = vec2.scale(out, vecA, 2); });
230
231            it("should place values into out", function() { expect(out).toBeEqualish([2, 4]); });
232            it("should return out", function() { expect(result).toBe(out); });
233            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
234        });
235
236        describe("when vecA is the output vector", function() {
237            beforeEach(function() { result = vec2.scale(vecA, vecA, 2); });
238
239            it("should place values into vecA", function() { expect(vecA).toBeEqualish([2, 4]); });
240            it("should return vecA", function() { expect(result).toBe(vecA); });
241        });
242    });
243
244    describe("scaleAndAdd", function() {
245        describe("with a separate output vector", function() {
246            beforeEach(function() { result = vec2.scaleAndAdd(out, vecA, vecB, 0.5); });
247
248            it("should place values into out", function() { expect(out).toBeEqualish([2.5, 4]); });
249            it("should return out", function() { expect(result).toBe(out); });
250            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
251            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
252        });
253
254        describe("when vecA is the output vector", function() {
255            beforeEach(function() { result = vec2.scaleAndAdd(vecA, vecA, vecB, 0.5); });
256
257            it("should place values into vecA", function() { expect(vecA).toBeEqualish([2.5, 4]); });
258            it("should return vecA", function() { expect(result).toBe(vecA); });
259            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
260        });
261
262        describe("when vecB is the output vector", function() {
263            beforeEach(function() { result = vec2.scaleAndAdd(vecB, vecA, vecB, 0.5); });
264
265            it("should place values into vecB", function() { expect(vecB).toBeEqualish([2.5, 4]); });
266            it("should return vecB", function() { expect(result).toBe(vecB); });
267            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
268        });
269    });
270
271    describe("distance", function() {
272        it("should have an alias called 'dist'", function() { expect(vec2.dist).toEqual(vec2.distance); });
273
274        beforeEach(function() { result = vec2.distance(vecA, vecB); });
275
276        it("should return the distance", function() { expect(result).toBeCloseTo(2.828427); });
277    });
278
279    describe("squaredDistance", function() {
280        it("should have an alias called 'sqrDist'", function() { expect(vec2.sqrDist).toEqual(vec2.squaredDistance); });
281
282        beforeEach(function() { result = vec2.squaredDistance(vecA, vecB); });
283
284        it("should return the squared distance", function() { expect(result).toEqual(8); });
285    });
286
287    describe("length", function() {
288        it("should have an alias called 'len'", function() { expect(vec2.len).toEqual(vec2.length); });
289
290        beforeEach(function() { result = vec2.length(vecA); });
291
292        it("should return the length", function() { expect(result).toBeCloseTo(2.236067); });
293    });
294
295    describe("squaredLength", function() {
296        it("should have an alias called 'sqrLen'", function() { expect(vec2.sqrLen).toEqual(vec2.squaredLength); });
297
298        beforeEach(function() { result = vec2.squaredLength(vecA); });
299
300        it("should return the squared length", function() { expect(result).toEqual(5); });
301    });
302
303    describe("negate", function() {
304        describe("with a separate output vector", function() {
305            beforeEach(function() { result = vec2.negate(out, vecA); });
306
307            it("should place values into out", function() { expect(out).toBeEqualish([-1, -2]); });
308            it("should return out", function() { expect(result).toBe(out); });
309            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
310        });
311
312        describe("when vecA is the output vector", function() {
313            beforeEach(function() { result = vec2.negate(vecA, vecA); });
314
315            it("should place values into vecA", function() { expect(vecA).toBeEqualish([-1, -2]); });
316            it("should return vecA", function() { expect(result).toBe(vecA); });
317        });
318    });
319
320    describe("normalize", function() {
321        beforeEach(function() { vecA = [5, 0]; });
322
323        describe("with a separate output vector", function() {
324            beforeEach(function() { result = vec2.normalize(out, vecA); });
325
326            it("should place values into out", function() { expect(out).toBeEqualish([1, 0]); });
327            it("should return out", function() { expect(result).toBe(out); });
328            it("should not modify vecA", function() { expect(vecA).toBeEqualish([5, 0]); });
329        });
330
331        describe("when vecA is the output vector", function() {
332            beforeEach(function() { result = vec2.normalize(vecA, vecA); });
333
334            it("should place values into vecA", function() { expect(vecA).toBeEqualish([1, 0]); });
335            it("should return vecA", function() { expect(result).toBe(vecA); });
336        });
337    });
338
339    describe("dot", function() {
340        beforeEach(function() { result = vec2.dot(vecA, vecB); });
341
342        it("should return the dot product", function() { expect(result).toEqual(11); });
343        it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
344        it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
345    });
346
347    describe("cross", function() {
348        var out3;
349
350        beforeEach(function() {
351            out3 = [0, 0, 0];
352            result = vec2.cross(out3, vecA, vecB);
353        });
354
355        it("should place values into out", function() { expect(out3).toBeEqualish([0, 0, -2]); });
356        it("should return out", function() { expect(result).toBe(out3); });
357        it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
358        it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
359    });
360
361    describe("lerp", function() {
362        describe("with a separate output vector", function() {
363            beforeEach(function() { result = vec2.lerp(out, vecA, vecB, 0.5); });
364
365            it("should place values into out", function() { expect(out).toBeEqualish([2, 3]); });
366            it("should return out", function() { expect(result).toBe(out); });
367            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
368            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
369        });
370
371        describe("when vecA is the output vector", function() {
372            beforeEach(function() { result = vec2.lerp(vecA, vecA, vecB, 0.5); });
373
374            it("should place values into vecA", function() { expect(vecA).toBeEqualish([2, 3]); });
375            it("should return vecA", function() { expect(result).toBe(vecA); });
376            it("should not modify vecB", function() { expect(vecB).toBeEqualish([3, 4]); });
377        });
378
379        describe("when vecB is the output vector", function() {
380            beforeEach(function() { result = vec2.lerp(vecB, vecA, vecB, 0.5); });
381
382            it("should place values into vecB", function() { expect(vecB).toBeEqualish([2, 3]); });
383            it("should return vecB", function() { expect(result).toBe(vecB); });
384            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
385        });
386    });
387
388    describe("random", function() {
389        describe("with no scale", function() {
390            beforeEach(function() { result = vec2.random(out); });
391
392            it("should result in a unit length vector", function() { expect(vec2.length(out)).toBeCloseTo(1.0); });
393            it("should return out", function() { expect(result).toBe(out); });
394        });
395
396        describe("with a scale", function() {
397            beforeEach(function() { result = vec2.random(out, 5.0); });
398
399            it("should result in a unit length vector", function() { expect(vec2.length(out)).toBeCloseTo(5.0); });
400            it("should return out", function() { expect(result).toBe(out); });
401        });
402    });
403
404    describe("transformMat2", function() {
405        var matA;
406        beforeEach(function() { matA = [1, 2, 3, 4]; });
407
408        describe("with a separate output vector", function() {
409            beforeEach(function() { result = vec2.transformMat2(out, vecA, matA); });
410
411            it("should place values into out", function() { expect(out).toBeEqualish([7, 10]); });
412            it("should return out", function() { expect(result).toBe(out); });
413            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
414            it("should not modify matA", function() { expect(matA).toBeEqualish([1, 2, 3, 4]); });
415        });
416
417        describe("when vecA is the output vector", function() {
418            beforeEach(function() { result = vec2.transformMat2(vecA, vecA, matA); });
419
420            it("should place values into vecA", function() { expect(vecA).toBeEqualish([7, 10]); });
421            it("should return vecA", function() { expect(result).toBe(vecA); });
422            it("should not modify matA", function() { expect(matA).toBeEqualish([1, 2, 3, 4]); });
423        });
424    });
425
426    describe("transformMat2d", function() {
427        var matA;
428        beforeEach(function() { matA = [1, 2, 3, 4, 5, 6]; });
429
430        describe("with a separate output vector", function() {
431            beforeEach(function() { result = vec2.transformMat2d(out, vecA, matA); });
432
433            it("should place values into out", function() { expect(out).toBeEqualish([12, 16]); });
434            it("should return out", function() { expect(result).toBe(out); });
435            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
436            it("should not modify matA", function() { expect(matA).toBeEqualish([1, 2, 3, 4, 5, 6]); });
437        });
438
439        describe("when vecA is the output vector", function() {
440            beforeEach(function() { result = vec2.transformMat2d(vecA, vecA, matA); });
441
442            it("should place values into vecA", function() { expect(vecA).toBeEqualish([12, 16]); });
443            it("should return vecA", function() { expect(result).toBe(vecA); });
444            it("should not modify matA", function() { expect(matA).toBeEqualish([1, 2, 3, 4, 5, 6]); });
445        });
446    });
447
448    describe("forEach", function() {
449        var vecArray;
450
451        beforeEach(function() {
452            vecArray = [
453                1, 2,
454                3, 4,
455                0, 0
456            ];
457        });
458
459        describe("when performing operations that take no extra arguments", function() {
460            beforeEach(function() { result = vec2.forEach(vecArray, 0, 0, 0, vec2.normalize); });
461
462            it("should update all values", function() {
463                expect(vecArray).toBeEqualish([
464                    0.447214, 0.894427,
465                    0.6, 0.8,
466                    0, 0
467                ]);
468            });
469            it("should return vecArray", function() { expect(result).toBe(vecArray); });
470        });
471
472        describe("when performing operations that takes one extra arguments", function() {
473            beforeEach(function() { result = vec2.forEach(vecArray, 0, 0, 0, vec2.add, vecA); });
474
475            it("should update all values", function() {
476                expect(vecArray).toBeEqualish([
477                    2, 4,
478                    4, 6,
479                    1, 2
480                ]);
481            });
482            it("should return vecArray", function() { expect(result).toBe(vecArray); });
483            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
484        });
485
486        describe("when specifying an offset", function() {
487            beforeEach(function() { result = vec2.forEach(vecArray, 0, 2, 0, vec2.add, vecA); });
488
489            it("should update all values except the first vector", function() {
490                expect(vecArray).toBeEqualish([
491                    1, 2,
492                    4, 6,
493                    1, 2
494                ]);
495            });
496            it("should return vecArray", function() { expect(result).toBe(vecArray); });
497            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
498        });
499
500        describe("when specifying a count", function() {
501            beforeEach(function() { result = vec2.forEach(vecArray, 0, 0, 2, vec2.add, vecA); });
502
503            it("should update all values except the last vector", function() {
504                expect(vecArray).toBeEqualish([
505                    2, 4,
506                    4, 6,
507                    0, 0
508                ]);
509            });
510            it("should return vecArray", function() { expect(result).toBe(vecArray); });
511            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
512        });
513
514        describe("when specifying a stride", function() {
515            beforeEach(function() { result = vec2.forEach(vecArray, 4, 0, 0, vec2.add, vecA); });
516
517            it("should update all values except the second vector", function() {
518                expect(vecArray).toBeEqualish([
519                    2, 4,
520                    3, 4,
521                    1, 2
522                ]);
523            });
524            it("should return vecArray", function() { expect(result).toBe(vecArray); });
525            it("should not modify vecA", function() { expect(vecA).toBeEqualish([1, 2]); });
526        });
527
528        describe("when calling a function that does not modify the out variable", function() {
529            beforeEach(function() {
530                result = vec2.forEach(vecArray, 0, 0, 0, function(out, vec) {});
531            });
532
533            it("values should remain unchanged", function() {
534                expect(vecArray).toBeEqualish([
535                    1, 2,
536                    3, 4,
537                    0, 0,
538                ]);
539            });
540            it("should return vecArray", function() { expect(result).toBe(vecArray); });
541        });
542    });
543
544    describe("str", function() {
545        beforeEach(function() { result = vec2.str(vecA); });
546
547        it("should return a string representation of the vector", function() { expect(result).toEqual("vec2(1, 2)"); });
548    });
549});
550