File: src/BB.Vector2.js

    // This class is a direct copy of the Three.js Vector2 class
    // from March 14, 2015 @ 1f97cfaa5d931ae34229ff8fa9c632e99a3b8249
    
    /**
     * A vector in 2 dimensional space. A direct copy of Three.js's Vector2 class.
     * @module BB.Vector2
     * @author mrdoob / http://mrdoob.com/
     * @author philogb / http://blog.thejit.org/
     * @author egraether / http://egraether.com/
     * @author zz85 / http://www.lab4games.net/zz85/blog
     */
    
    /**
     * A vector in 2 dimensional space. A direct copy of Three.js's THREE.Vector2 class.
     * @class BB.Vector2
     * @constructor
     * @param {Number} x Represents the x value of the vector
     * @param {Number} y Represents the y value of the vector
     */
    
    /**
     * This vector's x value
     * @property x
     */
    
    /**
     * This vector's y value
     * @property y
     */
    
    /**
     * Sets value of this vector.
     * @method set
     * @chainable
     * @param {Number} x Represents the x value of the vector
     * @param {Number} y Represents the y value of the vector
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Replace this vector's x value with x.
     * @method setX
     * @chainable
     * @param {Number} x Represents the x value of the vector.
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Replace this vector's y value with y.
     * @method setY
     * @chainable
     * @param {Number} y Represents the y value of the vector.
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Sets this vector's x and y values by index (0 and 1 respectively).
     * If index equals 0 method replaces this.x with value. 
     * If index equals 1 method replaces this.y with value.
     * @method setComponent
     * @param {Number} index 0 or 1
     * @param {Number} value Value to be assigned to corresponding index
     */
    
    /**
     * Get this vector's x and y values by index (0 and 1 respectively).
     * If index equals 0 method returns vector's x value.
     * If index equals 1 method returns vector's y value.
     * @method getComponent
     * @param  {[type]} index 0 or 1
     * @return {Number} Vector's x or y dependent on index
     */
    
    /**
     * Copies value of v to this vector. Note: Does not return a copy of this vector.
     * @method copy
     * @chainable
     * @param  {BB.Vector2} v
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Adds vector v to this vector.
     * @method add
     * @chainable
     * @param {BB.Vector2} v The vector to add to this vector
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Add the scalar value s to this vector's x and y values.
     * @method addScalar
     * @chainable
     * @return {BB.Vector2} this vector.
     * @param {Number} s Scalar to add vector with.
     */
    
    /**
     * Sets this vector to a + b.
     * @method addVectors
     * @chainable
     * @param {BB.Vector2} a The first vector.
     * @param {BB.Vector2} b The second vector.
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Subtracts vector v from this vector.
     * @method sub
     * @chainable
     * @param {BB.Vector2} v The vector to subtract from this vector
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Subtracts the scalar value s from this vector's x and y values.
     * @method subScalar
     * @chainable
     * @return {BB.Vector2} this vector.
     * @param {Number} s Scalar to subract vector by.
     */
    
    /**
     * Sets this vector to a - b.
     * @method subVectors
     * @chainable
     * @param {BB.Vector2} a The first vector.
     * @param {BB.Vector2} b The second vector.
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Multiplies this vector by v.
     * @method multiply
     * @chainable
     * @param {BB.Vector2} v The vector to subtract from this vector
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Multiplies this vector by scalar s.
     * @method mutliplyScalar
     * @param  {Number} s The scalar to multiply this vector by.
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Divides this vector by v.
     * @method divide
     * @chainable
     * @param {BB.Vector2} v The vector to subtract from this vector
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Divides this vector by scalar s.
     * @method divideScalar
     * @param  {Number} s The scalar to divide this vector by.
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * If this vector's x or y value is less than v's x or y value, replace that value with the corresponding min value.
     * @method min
     * @chainable
     * @param  {BB.Vector2} v The vector to check and assign min values from
     * @return {BB.Vector2}   This vector.
     */
    
    /**
     * If this vector's x or y value is less than v's x or y value, replace that value with the corresponding min value.
     * @method max
     * @chainable
     * @param  {BB.Vector2} v The vector to check and assign max values from
     * @return {BB.Vector2}   This vector.
     */
    
    /**
     * If this vector's x or y value is greater than the max vector's x or y
     * value, it is replaced by the corresponding value. If this vector's x
     * or y value is less than the min vector's x or y value, it is replace
     * by the corresponding value. Note: This function assumes min < max, if
     * this assumption isn't true it will not operate correctly
     * @method clamp
     * @chainable
     * @param  {BB.Vector2} min The vector containing the min x and y values in the desired range.
     * @param  {BB.Vector2} max The vector containing the max x and y values in the desired range.
     * @return {BB.Vector2}     This vector.
     */
    
    /**
     * If this vector's x or y values are greater than the max value, they
     * are replaced by the max value. If this vector's x or y values are
     * less than the min value, they are replace by the min value.
     * @method clampScalar
     * @chainable
     * @param  {Number} min the minimum value the components will be clamped to.
     * @param  {Number} max the minimum value the components will be clamped to.
     * @return {BB.Vector2}     This vector.
     */
    
    /**
     * The components of the vector are rounded downwards (towards negative infinity) to an integer value.
     * @method floor
     * @chainable
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * The components of the vector are rounded upwards (towards positive infinity) to an integer value.
     * @method ceil
     * @chainable
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * The components of the vector are rounded towards the nearest integer value.
     * @method round
     * @chainable
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.
     * @method roundToZero
     * @chainable
     * @return {BB.Vector2} This vector.
     */
    
     /**
     * Inverts this vector.
     * @method negate
     * @chainable
     * @return {BB.Vector2} this vector.
     */
    
    /**
     * Computes dot product of this vector and v.
     * @method dot
     * @param  {BB.Vector2} v
     * @return {Number}   The dot product of this vector and v.
     */
    
    /**
     * Computes squared length of this vector.
     * @method lengthSq
     * @return {Number}  The squared length of this vector.
     */
    
    /**
     * Computes the length of this vector.
     * @method length
     * @return {Number}   The length of this vector.
     */
    
    /**
     * Normalizes this vector.
     * @method normalize
     * @chainable
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Computes distance of this vector to v.
     * @method distanceTo
     * @param  {BB.Vector2} v 
     * @return {Number}   Distance from this vector to v.
     */
    
    /**
     * Computes squared distance of this vector to v.
     * @method distanceToSquared
     * @param  {BB.Vector2} v 
     * @return {Number}   Squared distance from this vector to v.
     */
    
    /**
     * Normalizes this vector and multiplies it by l.
     * @method setLength
     * @chainable
     * @param {Number} l The new length of the vector.
     * @return {BB.Vector2} This vector.
     */
    
    /**
     * Linear interpolation between this vector and v, where alpha is the
     * percent along the line.
     * @method lerp
     * @chainable
     * @param  {BB.Vector2} v  The vector to lerp this vector with.
     * @param  {Number} alpha Percentage along the line (0 - 1).
     * @return {BB.Vector2}  This vector.
     */
    
    /**
     * Sets this vector to be the vector linearly interpolated between v1
     * and v2 with alpha factor.
     * @method lerpVectors
     * @chainable
     * @param  {BB.Vector2} v1  The first vector.
     * @param  {BB.Vector2} v2  The second vector.
     * @param  {Number} alpha Percentage along the line (0 - 1).
     * @return {BB.Vector2}  This vector.
     */
    
    /**
     * Checks for strict equality of this vector and v.
     * @method equals
     * @param  {BB.Vector2} v The vector to check equality against.
     * @return {Boolean}
     */
    
    /**
     * Sets this vector's x value to be array[0] and y value to be array[1].
     * @method fromArray
     * @chainable
     * @param  {[type]} array  Array of length 2.
     * @return {BB.Vector2}  This vector.
     */
    
    /**
     * Returns an array [x, y].
     * @method toArray
     * @param  {Array} [array] Optional array that will be filled if provided.
     * @return {Array}  Array [x, y].
     */
    
    /**
     * Clones this vector.
     * @method clone
     * @return {BB.Vector2} A new vector with this vectors x and y values.
     */
        
    // note: fromAttribute(...) is not documented because the Three.js website
    // provides no documentation for it and it doesn't really make sense without
    // our library.
    
    define(['./BB'],
    function(  BB) { 
    
        'use strict';
    
        BB.Vector2 = function ( x, y ) {
    
            this.x = x || 0;
            this.y = y || 0;
    
        };
    
        BB.Vector2.prototype = {
    
            constructor: BB.Vector2,
    
            set: function ( x, y ) {
    
                this.x = x;
                this.y = y;
    
                return this;
    
            },
    
            setX: function ( x ) {
    
                this.x = x;
    
                return this;
    
            },
    
            setY: function ( y ) {
    
                this.y = y;
    
                return this;
    
            },
    
            setComponent: function ( index, value ) {
    
                switch ( index ) {
    
                    case 0: this.x = value; break;
                    case 1: this.y = value; break;
                    default: throw new Error( 'BB.Vector2.setComponent: index is out of range: ' + index );
    
                }
    
            },
    
            getComponent: function ( index ) {
    
                switch ( index ) {
    
                    case 0: return this.x;
                    case 1: return this.y;
                    default: throw new Error( 'BB.Vector2.getComponent: index is out of range: ' + index );
    
                }
    
            },
    
            copy: function ( v ) {
    
                this.x = v.x;
                this.y = v.y;
    
                return this;
    
            },
    
            add: function ( v, w ) {
    
                if ( w !== undefined ) {
                    return this.addVectors( v, w );
    
                }
    
                this.x += v.x;
                this.y += v.y;
    
                return this;
    
            },
    
            addScalar: function ( s ) {
    
                this.x += s;
                this.y += s;
    
                return this;
    
            },
    
            addVectors: function ( a, b ) {
    
                this.x = a.x + b.x;
                this.y = a.y + b.y;
    
                return this;
    
            },
    
            sub: function ( v, w ) {
    
                if ( w !== undefined ) {
    
                    return this.subVectors( v, w );
    
                }
    
                this.x -= v.x;
                this.y -= v.y;
    
                return this;
    
            },
    
            subScalar: function ( s ) {
    
                this.x -= s;
                this.y -= s;
    
                return this;
    
            },
    
            subVectors: function ( a, b ) {
    
                this.x = a.x - b.x;
                this.y = a.y - b.y;
    
                return this;
    
            },
    
            multiply: function ( v ) {
    
                this.x *= v.x;
                this.y *= v.y;
    
                return this;
    
            },
    
            multiplyScalar: function ( s ) {
    
                this.x *= s;
                this.y *= s;
    
                return this;
    
            },
    
            divide: function ( v ) {
    
                this.x /= v.x;
                this.y /= v.y;
    
                return this;
    
            },
    
            divideScalar: function ( scalar ) {
    
                if ( scalar !== 0 ) {
    
                    var invScalar = 1 / scalar;
    
                    this.x *= invScalar;
                    this.y *= invScalar;
    
                } else {
    
                    this.x = 0;
                    this.y = 0;
    
                }
    
                return this;
    
            },
    
            min: function ( v ) {
    
                if ( this.x > v.x ) {
    
                    this.x = v.x;
    
                }
    
                if ( this.y > v.y ) {
    
                    this.y = v.y;
    
                }
    
                return this;
    
            },
    
            max: function ( v ) {
    
                if ( this.x < v.x ) {
    
                    this.x = v.x;
    
                }
    
                if ( this.y < v.y ) {
    
                    this.y = v.y;
    
                }
    
                return this;
    
            },
    
            clamp: function ( min, max ) {
    
                // This function assumes min < max, if this assumption isn't true it will not operate correctly
    
                if ( this.x < min.x ) {
    
                    this.x = min.x;
    
                } else if ( this.x > max.x ) {
    
                    this.x = max.x;
    
                }
    
                if ( this.y < min.y ) {
    
                    this.y = min.y;
    
                } else if ( this.y > max.y ) {
    
                    this.y = max.y;
    
                }
    
                return this;
            },
    
            clampScalar: ( function () {
    
                var min, max;
    
                return function ( minVal, maxVal ) {
    
                    if ( min === undefined ) {
    
                        min = new BB.Vector2();
                        max = new BB.Vector2();
    
                    }
    
                    min.set( minVal, minVal );
                    max.set( maxVal, maxVal );
    
                    return this.clamp( min, max );
    
                };
    
            } )(),
    
           
            floor: function () {
    
                this.x = Math.floor( this.x );
                this.y = Math.floor( this.y );
    
                return this;
    
            },
    
            ceil: function () {
    
                this.x = Math.ceil( this.x );
                this.y = Math.ceil( this.y );
    
                return this;
    
            },
    
            round: function () {
    
                this.x = Math.round( this.x );
                this.y = Math.round( this.y );
    
                return this;
    
            },
    
            roundToZero: function () {
    
                this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
                this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
    
                return this;
    
            },
    
            negate: function () {
    
                this.x = - this.x;
                this.y = - this.y;
    
                return this;
    
            },
    
            dot: function ( v ) {
    
                return this.x * v.x + this.y * v.y;
    
            },
    
            lengthSq: function () {
    
                return this.x * this.x + this.y * this.y;
    
            },
    
            length: function () {
    
                return Math.sqrt( this.x * this.x + this.y * this.y );
    
            },
    
            normalize: function () {
    
                return this.divideScalar( this.length() );
    
            },
    
            distanceTo: function ( v ) {
    
                return Math.sqrt( this.distanceToSquared( v ) );
    
            },
    
            distanceToSquared: function ( v ) {
    
                var dx = this.x - v.x, dy = this.y - v.y;
                return dx * dx + dy * dy;
    
            },
    
            setLength: function ( l ) {
    
                var oldLength = this.length();
    
                if ( oldLength !== 0 && l !== oldLength ) {
    
                    this.multiplyScalar( l / oldLength );
                }
    
                return this;
    
            },
    
            lerp: function ( v, alpha ) {
    
                this.x += ( v.x - this.x ) * alpha;
                this.y += ( v.y - this.y ) * alpha;
    
                return this;
    
            },
    
            lerpVectors: function ( v1, v2, alpha ) {
    
                this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
    
                return this;
    
            },
    
            equals: function ( v ) {
    
                return ( ( v.x === this.x ) && ( v.y === this.y ) );
    
            },
    
            fromArray: function ( array, offset ) {
    
                if ( offset === undefined ) offset = 0;
    
                this.x = array[ offset ];
                this.y = array[ offset + 1 ];
    
                return this;
    
            },
    
            toArray: function ( array, offset ) {
    
                if ( array === undefined ) array = [];
                if ( offset === undefined ) offset = 0;
    
                array[ offset ] = this.x;
                array[ offset + 1 ] = this.y;
    
                return array;
    
            },
    
            fromAttribute: function ( attribute, index, offset ) {
    
                if ( offset === undefined ) offset = 0;
    
                index = index * attribute.itemSize + offset;
    
                this.x = attribute.array[ index ];
                this.y = attribute.array[ index + 1 ];
    
                return this;
    
            },
    
            clone: function () {
    
                return new BB.Vector2( this.x, this.y );
    
            }
        };
    
        return BB.Vector2;
    });