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 3 Dimensional Vector
25 * @name vec3
26 */
27var vec3 = {};
28
29/**
30 * Creates a new, empty vec3
31 *
32 * @returns {vec3} a new 3D vector
33 */
34vec3.create = function() {
35    var out = new glMatrix.ARRAY_TYPE(3);
36    out[0] = 0;
37    out[1] = 0;
38    out[2] = 0;
39    return out;
40};
41
42/**
43 * Creates a new vec3 initialized with values from an existing vector
44 *
45 * @param {vec3} a vector to clone
46 * @returns {vec3} a new 3D vector
47 */
48vec3.clone = function(a) {
49    var out = new glMatrix.ARRAY_TYPE(3);
50    out[0] = a[0];
51    out[1] = a[1];
52    out[2] = a[2];
53    return out;
54};
55
56/**
57 * Creates a new vec3 initialized with the given values
58 *
59 * @param {Number} x X component
60 * @param {Number} y Y component
61 * @param {Number} z Z component
62 * @returns {vec3} a new 3D vector
63 */
64vec3.fromValues = function(x, y, z) {
65    var out = new glMatrix.ARRAY_TYPE(3);
66    out[0] = x;
67    out[1] = y;
68    out[2] = z;
69    return out;
70};
71
72/**
73 * Copy the values from one vec3 to another
74 *
75 * @param {vec3} out the receiving vector
76 * @param {vec3} a the source vector
77 * @returns {vec3} out
78 */
79vec3.copy = function(out, a) {
80    out[0] = a[0];
81    out[1] = a[1];
82    out[2] = a[2];
83    return out;
84};
85
86/**
87 * Set the components of a vec3 to the given values
88 *
89 * @param {vec3} out the receiving vector
90 * @param {Number} x X component
91 * @param {Number} y Y component
92 * @param {Number} z Z component
93 * @returns {vec3} out
94 */
95vec3.set = function(out, x, y, z) {
96    out[0] = x;
97    out[1] = y;
98    out[2] = z;
99    return out;
100};
101
102/**
103 * Adds two vec3's
104 *
105 * @param {vec3} out the receiving vector
106 * @param {vec3} a the first operand
107 * @param {vec3} b the second operand
108 * @returns {vec3} out
109 */
110vec3.add = function(out, a, b) {
111    out[0] = a[0] + b[0];
112    out[1] = a[1] + b[1];
113    out[2] = a[2] + b[2];
114    return out;
115};
116
117/**
118 * Subtracts vector b from vector a
119 *
120 * @param {vec3} out the receiving vector
121 * @param {vec3} a the first operand
122 * @param {vec3} b the second operand
123 * @returns {vec3} out
124 */
125vec3.subtract = function(out, a, b) {
126    out[0] = a[0] - b[0];
127    out[1] = a[1] - b[1];
128    out[2] = a[2] - b[2];
129    return out;
130};
131
132/**
133 * Alias for {@link vec3.subtract}
134 * @function
135 */
136vec3.sub = vec3.subtract;
137
138/**
139 * Multiplies two vec3's
140 *
141 * @param {vec3} out the receiving vector
142 * @param {vec3} a the first operand
143 * @param {vec3} b the second operand
144 * @returns {vec3} out
145 */
146vec3.multiply = function(out, a, b) {
147    out[0] = a[0] * b[0];
148    out[1] = a[1] * b[1];
149    out[2] = a[2] * b[2];
150    return out;
151};
152
153/**
154 * Alias for {@link vec3.multiply}
155 * @function
156 */
157vec3.mul = vec3.multiply;
158
159/**
160 * Divides two vec3's
161 *
162 * @param {vec3} out the receiving vector
163 * @param {vec3} a the first operand
164 * @param {vec3} b the second operand
165 * @returns {vec3} out
166 */
167vec3.divide = function(out, a, b) {
168    out[0] = a[0] / b[0];
169    out[1] = a[1] / b[1];
170    out[2] = a[2] / b[2];
171    return out;
172};
173
174/**
175 * Alias for {@link vec3.divide}
176 * @function
177 */
178vec3.div = vec3.divide;
179
180/**
181 * Returns the minimum of two vec3's
182 *
183 * @param {vec3} out the receiving vector
184 * @param {vec3} a the first operand
185 * @param {vec3} b the second operand
186 * @returns {vec3} out
187 */
188vec3.min = function(out, a, b) {
189    out[0] = Math.min(a[0], b[0]);
190    out[1] = Math.min(a[1], b[1]);
191    out[2] = Math.min(a[2], b[2]);
192    return out;
193};
194
195/**
196 * Returns the maximum of two vec3's
197 *
198 * @param {vec3} out the receiving vector
199 * @param {vec3} a the first operand
200 * @param {vec3} b the second operand
201 * @returns {vec3} out
202 */
203vec3.max = function(out, a, b) {
204    out[0] = Math.max(a[0], b[0]);
205    out[1] = Math.max(a[1], b[1]);
206    out[2] = Math.max(a[2], b[2]);
207    return out;
208};
209
210/**
211 * Scales a vec3 by a scalar number
212 *
213 * @param {vec3} out the receiving vector
214 * @param {vec3} a the vector to scale
215 * @param {Number} b amount to scale the vector by
216 * @returns {vec3} out
217 */
218vec3.scale = function(out, a, b) {
219    out[0] = a[0] * b;
220    out[1] = a[1] * b;
221    out[2] = a[2] * b;
222    return out;
223};
224
225/**
226 * Adds two vec3's after scaling the second operand by a scalar value
227 *
228 * @param {vec3} out the receiving vector
229 * @param {vec3} a the first operand
230 * @param {vec3} b the second operand
231 * @param {Number} scale the amount to scale b by before adding
232 * @returns {vec3} out
233 */
234vec3.scaleAndAdd = function(out, a, b, scale) {
235    out[0] = a[0] + (b[0] * scale);
236    out[1] = a[1] + (b[1] * scale);
237    out[2] = a[2] + (b[2] * scale);
238    return out;
239};
240
241/**
242 * Calculates the euclidian distance between two vec3's
243 *
244 * @param {vec3} a the first operand
245 * @param {vec3} b the second operand
246 * @returns {Number} distance between a and b
247 */
248vec3.distance = function(a, b) {
249    var x = b[0] - a[0],
250        y = b[1] - a[1],
251        z = b[2] - a[2];
252    return Math.sqrt(x*x + y*y + z*z);
253};
254
255/**
256 * Alias for {@link vec3.distance}
257 * @function
258 */
259vec3.dist = vec3.distance;
260
261/**
262 * Calculates the squared euclidian distance between two vec3's
263 *
264 * @param {vec3} a the first operand
265 * @param {vec3} b the second operand
266 * @returns {Number} squared distance between a and b
267 */
268vec3.squaredDistance = function(a, b) {
269    var x = b[0] - a[0],
270        y = b[1] - a[1],
271        z = b[2] - a[2];
272    return x*x + y*y + z*z;
273};
274
275/**
276 * Alias for {@link vec3.squaredDistance}
277 * @function
278 */
279vec3.sqrDist = vec3.squaredDistance;
280
281/**
282 * Calculates the length of a vec3
283 *
284 * @param {vec3} a vector to calculate length of
285 * @returns {Number} length of a
286 */
287vec3.length = function (a) {
288    var x = a[0],
289        y = a[1],
290        z = a[2];
291    return Math.sqrt(x*x + y*y + z*z);
292};
293
294/**
295 * Alias for {@link vec3.length}
296 * @function
297 */
298vec3.len = vec3.length;
299
300/**
301 * Calculates the squared length of a vec3
302 *
303 * @param {vec3} a vector to calculate squared length of
304 * @returns {Number} squared length of a
305 */
306vec3.squaredLength = function (a) {
307    var x = a[0],
308        y = a[1],
309        z = a[2];
310    return x*x + y*y + z*z;
311};
312
313/**
314 * Alias for {@link vec3.squaredLength}
315 * @function
316 */
317vec3.sqrLen = vec3.squaredLength;
318
319/**
320 * Negates the components of a vec3
321 *
322 * @param {vec3} out the receiving vector
323 * @param {vec3} a vector to negate
324 * @returns {vec3} out
325 */
326vec3.negate = function(out, a) {
327    out[0] = -a[0];
328    out[1] = -a[1];
329    out[2] = -a[2];
330    return out;
331};
332
333/**
334 * Returns the inverse of the components of a vec3
335 *
336 * @param {vec3} out the receiving vector
337 * @param {vec3} a vector to invert
338 * @returns {vec3} out
339 */
340vec3.inverse = function(out, a) {
341  out[0] = 1.0 / a[0];
342  out[1] = 1.0 / a[1];
343  out[2] = 1.0 / a[2];
344  return out;
345};
346
347/**
348 * Normalize a vec3
349 *
350 * @param {vec3} out the receiving vector
351 * @param {vec3} a vector to normalize
352 * @returns {vec3} out
353 */
354vec3.normalize = function(out, a) {
355    var x = a[0],
356        y = a[1],
357        z = a[2];
358    var len = x*x + y*y + z*z;
359    if (len > 0) {
360        //TODO: evaluate use of glm_invsqrt here?
361        len = 1 / Math.sqrt(len);
362        out[0] = a[0] * len;
363        out[1] = a[1] * len;
364        out[2] = a[2] * len;
365    }
366    return out;
367};
368
369/**
370 * Calculates the dot product of two vec3's
371 *
372 * @param {vec3} a the first operand
373 * @param {vec3} b the second operand
374 * @returns {Number} dot product of a and b
375 */
376vec3.dot = function (a, b) {
377    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
378};
379
380/**
381 * Computes the cross product of two vec3's
382 *
383 * @param {vec3} out the receiving vector
384 * @param {vec3} a the first operand
385 * @param {vec3} b the second operand
386 * @returns {vec3} out
387 */
388vec3.cross = function(out, a, b) {
389    var ax = a[0], ay = a[1], az = a[2],
390        bx = b[0], by = b[1], bz = b[2];
391
392    out[0] = ay * bz - az * by;
393    out[1] = az * bx - ax * bz;
394    out[2] = ax * by - ay * bx;
395    return out;
396};
397
398/**
399 * Performs a linear interpolation between two vec3's
400 *
401 * @param {vec3} out the receiving vector
402 * @param {vec3} a the first operand
403 * @param {vec3} b the second operand
404 * @param {Number} t interpolation amount between the two inputs
405 * @returns {vec3} out
406 */
407vec3.lerp = function (out, a, b, t) {
408    var ax = a[0],
409        ay = a[1],
410        az = a[2];
411    out[0] = ax + t * (b[0] - ax);
412    out[1] = ay + t * (b[1] - ay);
413    out[2] = az + t * (b[2] - az);
414    return out;
415};
416
417/**
418 * Performs a hermite interpolation with two control points
419 *
420 * @param {vec3} out the receiving vector
421 * @param {vec3} a the first operand
422 * @param {vec3} b the second operand
423 * @param {vec3} c the third operand
424 * @param {vec3} d the fourth operand
425 * @param {Number} t interpolation amount between the two inputs
426 * @returns {vec3} out
427 */
428vec3.hermite = function (out, a, b, c, d, t) {
429  var factorTimes2 = t * t,
430      factor1 = factorTimes2 * (2 * t - 3) + 1,
431      factor2 = factorTimes2 * (t - 2) + t,
432      factor3 = factorTimes2 * (t - 1),
433      factor4 = factorTimes2 * (3 - 2 * t);
434
435  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
436  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
437  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
438
439  return out;
440};
441
442/**
443 * Performs a bezier interpolation with two control points
444 *
445 * @param {vec3} out the receiving vector
446 * @param {vec3} a the first operand
447 * @param {vec3} b the second operand
448 * @param {vec3} c the third operand
449 * @param {vec3} d the fourth operand
450 * @param {Number} t interpolation amount between the two inputs
451 * @returns {vec3} out
452 */
453vec3.bezier = function (out, a, b, c, d, t) {
454  var inverseFactor = 1 - t,
455      inverseFactorTimesTwo = inverseFactor * inverseFactor,
456      factorTimes2 = t * t,
457      factor1 = inverseFactorTimesTwo * inverseFactor,
458      factor2 = 3 * t * inverseFactorTimesTwo,
459      factor3 = 3 * factorTimes2 * inverseFactor,
460      factor4 = factorTimes2 * t;
461
462  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
463  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
464  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
465
466  return out;
467};
468
469/**
470 * Generates a random vector with the given scale
471 *
472 * @param {vec3} out the receiving vector
473 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
474 * @returns {vec3} out
475 */
476vec3.random = function (out, scale) {
477    scale = scale || 1.0;
478
479    var r = glMatrix.RANDOM() * 2.0 * Math.PI;
480    var z = (glMatrix.RANDOM() * 2.0) - 1.0;
481    var zScale = Math.sqrt(1.0-z*z) * scale;
482
483    out[0] = Math.cos(r) * zScale;
484    out[1] = Math.sin(r) * zScale;
485    out[2] = z * scale;
486    return out;
487};
488
489/**
490 * Transforms the vec3 with a mat4.
491 * 4th vector component is implicitly '1'
492 *
493 * @param {vec3} out the receiving vector
494 * @param {vec3} a the vector to transform
495 * @param {mat4} m matrix to transform with
496 * @returns {vec3} out
497 */
498vec3.transformMat4 = function(out, a, m) {
499    var x = a[0], y = a[1], z = a[2],
500        w = m[3] * x + m[7] * y + m[11] * z + m[15];
501    w = w || 1.0;
502    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
503    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
504    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
505    return out;
506};
507
508/**
509 * Transforms the vec3 with a mat3.
510 *
511 * @param {vec3} out the receiving vector
512 * @param {vec3} a the vector to transform
513 * @param {mat4} m the 3x3 matrix to transform with
514 * @returns {vec3} out
515 */
516vec3.transformMat3 = function(out, a, m) {
517    var x = a[0], y = a[1], z = a[2];
518    out[0] = x * m[0] + y * m[3] + z * m[6];
519    out[1] = x * m[1] + y * m[4] + z * m[7];
520    out[2] = x * m[2] + y * m[5] + z * m[8];
521    return out;
522};
523
524/**
525 * Transforms the vec3 with a quat
526 *
527 * @param {vec3} out the receiving vector
528 * @param {vec3} a the vector to transform
529 * @param {quat} q quaternion to transform with
530 * @returns {vec3} out
531 */
532vec3.transformQuat = function(out, a, q) {
533    // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
534
535    var x = a[0], y = a[1], z = a[2],
536        qx = q[0], qy = q[1], qz = q[2], qw = q[3],
537
538        // calculate quat * vec
539        ix = qw * x + qy * z - qz * y,
540        iy = qw * y + qz * x - qx * z,
541        iz = qw * z + qx * y - qy * x,
542        iw = -qx * x - qy * y - qz * z;
543
544    // calculate result * inverse quat
545    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
546    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
547    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
548    return out;
549};
550
551/**
552 * Rotate a 3D vector around the x-axis
553 * @param {vec3} out The receiving vec3
554 * @param {vec3} a The vec3 point to rotate
555 * @param {vec3} b The origin of the rotation
556 * @param {Number} c The angle of rotation
557 * @returns {vec3} out
558 */
559vec3.rotateX = function(out, a, b, c){
560   var p = [], r=[];
561	  //Translate point to the origin
562	  p[0] = a[0] - b[0];
563	  p[1] = a[1] - b[1];
564  	p[2] = a[2] - b[2];
565
566	  //perform rotation
567	  r[0] = p[0];
568	  r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);
569	  r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);
570
571	  //translate to correct position
572	  out[0] = r[0] + b[0];
573	  out[1] = r[1] + b[1];
574	  out[2] = r[2] + b[2];
575
576  	return out;
577};
578
579/**
580 * Rotate a 3D vector around the y-axis
581 * @param {vec3} out The receiving vec3
582 * @param {vec3} a The vec3 point to rotate
583 * @param {vec3} b The origin of the rotation
584 * @param {Number} c The angle of rotation
585 * @returns {vec3} out
586 */
587vec3.rotateY = function(out, a, b, c){
588  	var p = [], r=[];
589  	//Translate point to the origin
590  	p[0] = a[0] - b[0];
591  	p[1] = a[1] - b[1];
592  	p[2] = a[2] - b[2];
593
594  	//perform rotation
595  	r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);
596  	r[1] = p[1];
597  	r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);
598
599  	//translate to correct position
600  	out[0] = r[0] + b[0];
601  	out[1] = r[1] + b[1];
602  	out[2] = r[2] + b[2];
603
604  	return out;
605};
606
607/**
608 * Rotate a 3D vector around the z-axis
609 * @param {vec3} out The receiving vec3
610 * @param {vec3} a The vec3 point to rotate
611 * @param {vec3} b The origin of the rotation
612 * @param {Number} c The angle of rotation
613 * @returns {vec3} out
614 */
615vec3.rotateZ = function(out, a, b, c){
616  	var p = [], r=[];
617  	//Translate point to the origin
618  	p[0] = a[0] - b[0];
619  	p[1] = a[1] - b[1];
620  	p[2] = a[2] - b[2];
621
622  	//perform rotation
623  	r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);
624  	r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
625  	r[2] = p[2];
626
627  	//translate to correct position
628  	out[0] = r[0] + b[0];
629  	out[1] = r[1] + b[1];
630  	out[2] = r[2] + b[2];
631
632  	return out;
633};
634
635/**
636 * Perform some operation over an array of vec3s.
637 *
638 * @param {Array} a the array of vectors to iterate over
639 * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
640 * @param {Number} offset Number of elements to skip at the beginning of the array
641 * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
642 * @param {Function} fn Function to call for each vector in the array
643 * @param {Object} [arg] additional argument to pass to fn
644 * @returns {Array} a
645 * @function
646 */
647vec3.forEach = (function() {
648    var vec = vec3.create();
649
650    return function(a, stride, offset, count, fn, arg) {
651        var i, l;
652        if(!stride) {
653            stride = 3;
654        }
655
656        if(!offset) {
657            offset = 0;
658        }
659
660        if(count) {
661            l = Math.min((count * stride) + offset, a.length);
662        } else {
663            l = a.length;
664        }
665
666        for(i = offset; i < l; i += stride) {
667            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
668            fn(vec, vec, arg);
669            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
670        }
671
672        return a;
673    };
674})();
675
676/**
677 * Get the angle between two 3D vectors
678 * @param {vec3} a The first operand
679 * @param {vec3} b The second operand
680 * @returns {Number} The angle in radians
681 */
682vec3.angle = function(a, b) {
683
684    var tempA = vec3.fromValues(a[0], a[1], a[2]);
685    var tempB = vec3.fromValues(b[0], b[1], b[2]);
686
687    vec3.normalize(tempA, tempA);
688    vec3.normalize(tempB, tempB);
689
690    var cosine = vec3.dot(tempA, tempB);
691
692    if(cosine > 1.0){
693        return 0;
694    } else {
695        return Math.acos(cosine);
696    }
697};
698
699/**
700 * Returns a string representation of a vector
701 *
702 * @param {vec3} vec vector to represent as a string
703 * @returns {String} string representation of the vector
704 */
705vec3.str = function (a) {
706    return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
707};
708
709module.exports = vec3;
710