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
21var glMatrix = require("./common.js");
22
23/**
24 * @class 2 Dimensional Vector
25 * @name vec2
26 */
27var vec2 = {};
28
29/**
30 * Creates a new, empty vec2
31 *
32 * @returns {vec2} a new 2D vector
33 */
34vec2.create = function() {
35    var out = new glMatrix.ARRAY_TYPE(2);
36    out[0] = 0;
37    out[1] = 0;
38    return out;
39};
40
41/**
42 * Creates a new vec2 initialized with values from an existing vector
43 *
44 * @param {vec2} a vector to clone
45 * @returns {vec2} a new 2D vector
46 */
47vec2.clone = function(a) {
48    var out = new glMatrix.ARRAY_TYPE(2);
49    out[0] = a[0];
50    out[1] = a[1];
51    return out;
52};
53
54/**
55 * Creates a new vec2 initialized with the given values
56 *
57 * @param {Number} x X component
58 * @param {Number} y Y component
59 * @returns {vec2} a new 2D vector
60 */
61vec2.fromValues = function(x, y) {
62    var out = new glMatrix.ARRAY_TYPE(2);
63    out[0] = x;
64    out[1] = y;
65    return out;
66};
67
68/**
69 * Copy the values from one vec2 to another
70 *
71 * @param {vec2} out the receiving vector
72 * @param {vec2} a the source vector
73 * @returns {vec2} out
74 */
75vec2.copy = function(out, a) {
76    out[0] = a[0];
77    out[1] = a[1];
78    return out;
79};
80
81/**
82 * Set the components of a vec2 to the given values
83 *
84 * @param {vec2} out the receiving vector
85 * @param {Number} x X component
86 * @param {Number} y Y component
87 * @returns {vec2} out
88 */
89vec2.set = function(out, x, y) {
90    out[0] = x;
91    out[1] = y;
92    return out;
93};
94
95/**
96 * Adds two vec2's
97 *
98 * @param {vec2} out the receiving vector
99 * @param {vec2} a the first operand
100 * @param {vec2} b the second operand
101 * @returns {vec2} out
102 */
103vec2.add = function(out, a, b) {
104    out[0] = a[0] + b[0];
105    out[1] = a[1] + b[1];
106    return out;
107};
108
109/**
110 * Subtracts vector b from vector a
111 *
112 * @param {vec2} out the receiving vector
113 * @param {vec2} a the first operand
114 * @param {vec2} b the second operand
115 * @returns {vec2} out
116 */
117vec2.subtract = function(out, a, b) {
118    out[0] = a[0] - b[0];
119    out[1] = a[1] - b[1];
120    return out;
121};
122
123/**
124 * Alias for {@link vec2.subtract}
125 * @function
126 */
127vec2.sub = vec2.subtract;
128
129/**
130 * Multiplies two vec2's
131 *
132 * @param {vec2} out the receiving vector
133 * @param {vec2} a the first operand
134 * @param {vec2} b the second operand
135 * @returns {vec2} out
136 */
137vec2.multiply = function(out, a, b) {
138    out[0] = a[0] * b[0];
139    out[1] = a[1] * b[1];
140    return out;
141};
142
143/**
144 * Alias for {@link vec2.multiply}
145 * @function
146 */
147vec2.mul = vec2.multiply;
148
149/**
150 * Divides two vec2's
151 *
152 * @param {vec2} out the receiving vector
153 * @param {vec2} a the first operand
154 * @param {vec2} b the second operand
155 * @returns {vec2} out
156 */
157vec2.divide = function(out, a, b) {
158    out[0] = a[0] / b[0];
159    out[1] = a[1] / b[1];
160    return out;
161};
162
163/**
164 * Alias for {@link vec2.divide}
165 * @function
166 */
167vec2.div = vec2.divide;
168
169/**
170 * Returns the minimum of two vec2's
171 *
172 * @param {vec2} out the receiving vector
173 * @param {vec2} a the first operand
174 * @param {vec2} b the second operand
175 * @returns {vec2} out
176 */
177vec2.min = function(out, a, b) {
178    out[0] = Math.min(a[0], b[0]);
179    out[1] = Math.min(a[1], b[1]);
180    return out;
181};
182
183/**
184 * Returns the maximum of two vec2's
185 *
186 * @param {vec2} out the receiving vector
187 * @param {vec2} a the first operand
188 * @param {vec2} b the second operand
189 * @returns {vec2} out
190 */
191vec2.max = function(out, a, b) {
192    out[0] = Math.max(a[0], b[0]);
193    out[1] = Math.max(a[1], b[1]);
194    return out;
195};
196
197/**
198 * Scales a vec2 by a scalar number
199 *
200 * @param {vec2} out the receiving vector
201 * @param {vec2} a the vector to scale
202 * @param {Number} b amount to scale the vector by
203 * @returns {vec2} out
204 */
205vec2.scale = function(out, a, b) {
206    out[0] = a[0] * b;
207    out[1] = a[1] * b;
208    return out;
209};
210
211/**
212 * Adds two vec2's after scaling the second operand by a scalar value
213 *
214 * @param {vec2} out the receiving vector
215 * @param {vec2} a the first operand
216 * @param {vec2} b the second operand
217 * @param {Number} scale the amount to scale b by before adding
218 * @returns {vec2} out
219 */
220vec2.scaleAndAdd = function(out, a, b, scale) {
221    out[0] = a[0] + (b[0] * scale);
222    out[1] = a[1] + (b[1] * scale);
223    return out;
224};
225
226/**
227 * Calculates the euclidian distance between two vec2's
228 *
229 * @param {vec2} a the first operand
230 * @param {vec2} b the second operand
231 * @returns {Number} distance between a and b
232 */
233vec2.distance = function(a, b) {
234    var x = b[0] - a[0],
235        y = b[1] - a[1];
236    return Math.sqrt(x*x + y*y);
237};
238
239/**
240 * Alias for {@link vec2.distance}
241 * @function
242 */
243vec2.dist = vec2.distance;
244
245/**
246 * Calculates the squared euclidian distance between two vec2's
247 *
248 * @param {vec2} a the first operand
249 * @param {vec2} b the second operand
250 * @returns {Number} squared distance between a and b
251 */
252vec2.squaredDistance = function(a, b) {
253    var x = b[0] - a[0],
254        y = b[1] - a[1];
255    return x*x + y*y;
256};
257
258/**
259 * Alias for {@link vec2.squaredDistance}
260 * @function
261 */
262vec2.sqrDist = vec2.squaredDistance;
263
264/**
265 * Calculates the length of a vec2
266 *
267 * @param {vec2} a vector to calculate length of
268 * @returns {Number} length of a
269 */
270vec2.length = function (a) {
271    var x = a[0],
272        y = a[1];
273    return Math.sqrt(x*x + y*y);
274};
275
276/**
277 * Alias for {@link vec2.length}
278 * @function
279 */
280vec2.len = vec2.length;
281
282/**
283 * Calculates the squared length of a vec2
284 *
285 * @param {vec2} a vector to calculate squared length of
286 * @returns {Number} squared length of a
287 */
288vec2.squaredLength = function (a) {
289    var x = a[0],
290        y = a[1];
291    return x*x + y*y;
292};
293
294/**
295 * Alias for {@link vec2.squaredLength}
296 * @function
297 */
298vec2.sqrLen = vec2.squaredLength;
299
300/**
301 * Negates the components of a vec2
302 *
303 * @param {vec2} out the receiving vector
304 * @param {vec2} a vector to negate
305 * @returns {vec2} out
306 */
307vec2.negate = function(out, a) {
308    out[0] = -a[0];
309    out[1] = -a[1];
310    return out;
311};
312
313/**
314 * Returns the inverse of the components of a vec2
315 *
316 * @param {vec2} out the receiving vector
317 * @param {vec2} a vector to invert
318 * @returns {vec2} out
319 */
320vec2.inverse = function(out, a) {
321  out[0] = 1.0 / a[0];
322  out[1] = 1.0 / a[1];
323  return out;
324};
325
326/**
327 * Normalize a vec2
328 *
329 * @param {vec2} out the receiving vector
330 * @param {vec2} a vector to normalize
331 * @returns {vec2} out
332 */
333vec2.normalize = function(out, a) {
334    var x = a[0],
335        y = a[1];
336    var len = x*x + y*y;
337    if (len > 0) {
338        //TODO: evaluate use of glm_invsqrt here?
339        len = 1 / Math.sqrt(len);
340        out[0] = a[0] * len;
341        out[1] = a[1] * len;
342    }
343    return out;
344};
345
346/**
347 * Calculates the dot product of two vec2's
348 *
349 * @param {vec2} a the first operand
350 * @param {vec2} b the second operand
351 * @returns {Number} dot product of a and b
352 */
353vec2.dot = function (a, b) {
354    return a[0] * b[0] + a[1] * b[1];
355};
356
357/**
358 * Computes the cross product of two vec2's
359 * Note that the cross product must by definition produce a 3D vector
360 *
361 * @param {vec3} out the receiving vector
362 * @param {vec2} a the first operand
363 * @param {vec2} b the second operand
364 * @returns {vec3} out
365 */
366vec2.cross = function(out, a, b) {
367    var z = a[0] * b[1] - a[1] * b[0];
368    out[0] = out[1] = 0;
369    out[2] = z;
370    return out;
371};
372
373/**
374 * Performs a linear interpolation between two vec2's
375 *
376 * @param {vec2} out the receiving vector
377 * @param {vec2} a the first operand
378 * @param {vec2} b the second operand
379 * @param {Number} t interpolation amount between the two inputs
380 * @returns {vec2} out
381 */
382vec2.lerp = function (out, a, b, t) {
383    var ax = a[0],
384        ay = a[1];
385    out[0] = ax + t * (b[0] - ax);
386    out[1] = ay + t * (b[1] - ay);
387    return out;
388};
389
390/**
391 * Generates a random vector with the given scale
392 *
393 * @param {vec2} out the receiving vector
394 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
395 * @returns {vec2} out
396 */
397vec2.random = function (out, scale) {
398    scale = scale || 1.0;
399    var r = glMatrix.RANDOM() * 2.0 * Math.PI;
400    out[0] = Math.cos(r) * scale;
401    out[1] = Math.sin(r) * scale;
402    return out;
403};
404
405/**
406 * Transforms the vec2 with a mat2
407 *
408 * @param {vec2} out the receiving vector
409 * @param {vec2} a the vector to transform
410 * @param {mat2} m matrix to transform with
411 * @returns {vec2} out
412 */
413vec2.transformMat2 = function(out, a, m) {
414    var x = a[0],
415        y = a[1];
416    out[0] = m[0] * x + m[2] * y;
417    out[1] = m[1] * x + m[3] * y;
418    return out;
419};
420
421/**
422 * Transforms the vec2 with a mat2d
423 *
424 * @param {vec2} out the receiving vector
425 * @param {vec2} a the vector to transform
426 * @param {mat2d} m matrix to transform with
427 * @returns {vec2} out
428 */
429vec2.transformMat2d = function(out, a, m) {
430    var x = a[0],
431        y = a[1];
432    out[0] = m[0] * x + m[2] * y + m[4];
433    out[1] = m[1] * x + m[3] * y + m[5];
434    return out;
435};
436
437/**
438 * Transforms the vec2 with a mat3
439 * 3rd vector component is implicitly '1'
440 *
441 * @param {vec2} out the receiving vector
442 * @param {vec2} a the vector to transform
443 * @param {mat3} m matrix to transform with
444 * @returns {vec2} out
445 */
446vec2.transformMat3 = function(out, a, m) {
447    var x = a[0],
448        y = a[1];
449    out[0] = m[0] * x + m[3] * y + m[6];
450    out[1] = m[1] * x + m[4] * y + m[7];
451    return out;
452};
453
454/**
455 * Transforms the vec2 with a mat4
456 * 3rd vector component is implicitly '0'
457 * 4th vector component is implicitly '1'
458 *
459 * @param {vec2} out the receiving vector
460 * @param {vec2} a the vector to transform
461 * @param {mat4} m matrix to transform with
462 * @returns {vec2} out
463 */
464vec2.transformMat4 = function(out, a, m) {
465    var x = a[0],
466        y = a[1];
467    out[0] = m[0] * x + m[4] * y + m[12];
468    out[1] = m[1] * x + m[5] * y + m[13];
469    return out;
470};
471
472/**
473 * Perform some operation over an array of vec2s.
474 *
475 * @param {Array} a the array of vectors to iterate over
476 * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
477 * @param {Number} offset Number of elements to skip at the beginning of the array
478 * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
479 * @param {Function} fn Function to call for each vector in the array
480 * @param {Object} [arg] additional argument to pass to fn
481 * @returns {Array} a
482 * @function
483 */
484vec2.forEach = (function() {
485    var vec = vec2.create();
486
487    return function(a, stride, offset, count, fn, arg) {
488        var i, l;
489        if(!stride) {
490            stride = 2;
491        }
492
493        if(!offset) {
494            offset = 0;
495        }
496
497        if(count) {
498            l = Math.min((count * stride) + offset, a.length);
499        } else {
500            l = a.length;
501        }
502
503        for(i = offset; i < l; i += stride) {
504            vec[0] = a[i]; vec[1] = a[i+1];
505            fn(vec, vec, arg);
506            a[i] = vec[0]; a[i+1] = vec[1];
507        }
508
509        return a;
510    };
511})();
512
513/**
514 * Returns a string representation of a vector
515 *
516 * @param {vec2} vec vector to represent as a string
517 * @returns {String} string representation of the vector
518 */
519vec2.str = function (a) {
520    return 'vec2(' + a[0] + ', ' + a[1] + ')';
521};
522
523module.exports = vec2;
524