Source: math/mathf.js

if (typeof(define) !== "function") {
    var define = require("amdefine")(module);
}
define(
    function() {
        "use strict";


        var random = Math.random,
            abs = Math.abs,
            cos = Math.cos,
            pow = Math.pow,
            floor = Math.floor,
            ceil = Math.ceil,
            atan2 = Math.atan2,
            EPSILON = 0.000001,
            PI = 3.1415926535897932384626433832795028841968,
            TWO_PI = PI * 2,
            HALF_PI = PI * 0.5,
            TO_RADS = PI / 180,
            TO_DEGS = 180 / PI,
            keys = Object.keys,
            modulo, clamp01, standardRadian, standardAngle, radsToDegs;


        /**
         * @class Mathf
         * collection of common math functions
         */
        function Mathf() {

            /**
             * @property Number PI
             * The infamous 3.1415926535897932384626433832795028841968
             * @memberof Odin.Mathf
             */
            this.PI = PI;

            /**
             * @property Number TWO_PI
             * 2 * PI
             * @memberof Odin.Mathf
             */
            this.TWO_PI = TWO_PI;

            /**
             * @property Number HALF_PI
             * PI / 2
             * @memberof Odin.Mathf
             */
            this.HALF_PI = HALF_PI;

            /**
             * @property Number EPSILON
             * A small number value
             * @memberof Odin.Mathf
             */
            this.EPSILON = EPSILON;

            /**
             * @property Number TO_RADS
             * Degrees to radians conversion constant
             * @memberof Odin.Mathf
             */
            this.TO_RADS = TO_RADS;

            /**
             * @property Number TO_DEGS
             * Radians to degrees conversion constant
             * @memberof Odin.Mathf
             */
            this.TO_DEGS = TO_DEGS;


            this._classes = {};
        }


        Mathf.prototype.acos = Math.acos;
        Mathf.prototype.asin = Math.asin;
        Mathf.prototype.atan = Math.atan;
        Mathf.prototype.atan2 = Math.atan2;

        Mathf.prototype.cos = Math.cos;
        Mathf.prototype.sin = Math.sin;
        Mathf.prototype.tan = Math.tan;

        Mathf.prototype.abs = Math.abs;
        Mathf.prototype.ceil = Math.ceil;
        Mathf.prototype.exp = Math.exp;
        Mathf.prototype.floor = Math.floor;
        Mathf.prototype.log = Math.log;
        Mathf.prototype.max = Math.max;
        Mathf.prototype.min = Math.min;
        Mathf.prototype.pow = Math.pow;
        Mathf.prototype.random = Math.random;
        Mathf.prototype.round = Math.round;
        Mathf.prototype.sqrt = Math.sqrt;

        /**
         * @method equals
         * @memberof Odin.Mathf
         * returns if a = b within some value, defaults to Mathf.EPSILON
         * @param Number a
         * @param Number b
         * @param Number e
         * @return Boolean
         */
        Mathf.prototype.equals = function(a, b, e) {

            return abs(a - b) < (e || EPSILON);
        };

        /**
         * @method modulo
         * @memberof Odin.Mathf
         * returns remainder of a / b
         * @param Number a
         * @param Number b
         * @return Number
         */
        Mathf.prototype.modulo = modulo = function(a, b) {
            var r = a % b;

            return (r * b < 0) ? r + b : r;
        };

        /**
         * @method standardRadian
         * @memberof Odin.Mathf
         * convertes x to radian where 0 <= x < 2PI
         * @param Number x
         * @return Number
         */
        Mathf.prototype.standardRadian = standardRadian = function(x) {

            return modulo(x, TWO_PI);
        };

        /**
         * @method standardAngle
         * @memberof Odin.Mathf
         * convertes x to angle where 0 <= x < 360
         * @param Number x
         * @return Number
         */
        Mathf.prototype.standardAngle = standardAngle = function(x) {

            return modulo(x, 360);
        };

        /**
         * @method sign
         * @memberof Odin.Mathf
         * gets sign of x
         * @param Number x
         * @return Number
         */
        Mathf.prototype.sign = function(x) {

            return x < 0 ? -1 : 1;
        };

        /**
         * @method clamp
         * @memberof Odin.Mathf
         * clamp x between min and max
         * @param Number x
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.clamp = function(x, min, max) {

            return x < min ? min : x > max ? max : x;
        };

        /**
         * @method clampBottom
         * @memberof Odin.Mathf
         * clamp x between min and Infinity
         * @param Number x
         * @param Number min
         * @return Number
         */
        Mathf.prototype.clampBottom = function(x, min) {

            return x < min ? min : x;
        };

        /**
         * @method clampTop
         * @memberof Odin.Mathf
         * clamp x between -Infinity and max
         * @param Number x
         * @param Number max
         * @return Number
         */
        Mathf.prototype.clampTop = function(x, max) {

            return x > max ? max : x;
        };

        /**
         * @method clamp01
         * @memberof Odin.Mathf
         * clamp x between 0 and 1
         * @param Number x
         * @return Number
         */
        Mathf.prototype.clamp01 = clamp01 = function(x) {

            return x < 0 ? 0 : x > 1 ? 1 : x;
        };

        /**
         * @method truncate
         * @memberof Odin.Mathf
         * truncate x to have n number of decial places
         * @param Number x
         * @param Number n
         * @return Number
         */
        Mathf.prototype.truncate = function(x, n) {
            var p = pow(10, n),
                num = x * p;

            return (num < 0 ? ceil(num) : floor(num)) / p;
        };

        /**
         * @method lerp
         * @memberof Odin.Mathf
         * linear interpolation between a and b by x
         * @param Number a
         * @param Number b
         * @param Number x
         * @return Number
         */
        Mathf.prototype.lerp = function(a, b, x) {

            return a + (b - a) * x;
        };

        /**
         * @method lerpAngle
         * @memberof Odin.Mathf
         * linear interpolation between a and b by x insures 0 <= x < 2PI
         * @param Number a
         * @param Number b
         * @param Number x
         * @return Number
         */
        Mathf.prototype.lerpAngle = function(a, b, x) {

            return standardRadian(a + (b - a) * x);
        };

        /**
         * @method cosLerp
         * @memberof Odin.Mathf
         * cosine interpolation between a and b by x
         * @param Number a
         * @param Number b
         * @param Number x
         * @return Number
         */
        Mathf.prototype.lerpCos = function(a, b, x) {
            var ft = x * PI,
                f = (1 - cos(ft)) * 0.5;

            return a * (1 - f) + b * f;
        };

        /**
         * @method lerpCubic
         * @memberof Odin.Mathf
         * cubic interpolation between v1 and v2 by x
         * @param Number v0
         * @param Number v1
         * @param Number v2
         * @param Number v3
         * @param Number x
         * @return Number
         */
        Mathf.prototype.lerpCubic = function(v0, v1, v2, v3, x) {
            v0 || (v0 = v1);
            v3 || (v3 = v2);
            var P = (v3 - v2) - (v0 - v1),
                Q = (v0 - v1) - P,
                R = v2 - v0,
                S = v1,

                Px = P * x,
                Qx = Q * x,
                Rx = R * x;

            return (Px * Px * Px) + (Qx * Qx) + Rx + S;
        };

        /**
         * smooth step, if input is between min and max this returns a value proportionately between 0 and 1
         * @method smoothStep
         * @memberof Odin.Mathf
         * @param Number x
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.smoothStep = function(x, min, max) {
            if (x <= min) return 0;
            if (x >= max) return 1;

            x = (x - min) / (max - min);

            return x * x * (3 - 2 * x);
        };

        /**
         * @method smootherStep
         * @memberof Odin.Mathf
         * smoother step, if input is between min and max this returns a value proportionately between 0 and 1
         * @param Number x
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.smootherStep = function(x, min, max) {
            if (x <= min) return 0;
            if (x >= max) return 1;

            x = (x - min) / (max - min);

            return x * x * x * (x * (x * 6 - 15) + 10);
        };

        /**
         * @method pingPong
         * @memberof Odin.Mathf
         * PingPongs the value x, so that it is never larger than length and never smaller than 0.
         * @param Number x
         * @param Number length
         * @return Number
         */
        Mathf.prototype.pingPong = function(x, length) {
            length || (length = 1);

            return length - abs(x % (2 * length) - length);
        };

        /**
         * @method degsToRads
         * @memberof Odin.Mathf
         * convertes degrees to radians
         * @param Number x
         * @return Number
         */
        Mathf.prototype.degsToRads = function(x) {

            return standardRadian(x * TO_RADS);
        };

        /**
         * @method radsToDegs
         * @memberof Odin.Mathf
         * convertes radians to degrees
         * @param Number x
         * @return Number
         */
        Mathf.prototype.radsToDegs = radsToDegs = function(x) {

            return standardAngle(x * TO_DEGS);
        };

        /**
         * @method randInt
         * @memberof Odin.Mathf
         * returns random number between min and max
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.randInt = function(min, max) {

            return floor(min + (random() * (max + 1 - min)));
        };

        /**
         * @method randFloat
         * @memberof Odin.Mathf
         * returns random number between min and max
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.randFloat = function(min, max) {

            return min + (random() * (max - min));
        };

        /**
         * @method randSign
         * @memberof Odin.Mathf
         * returns either -1 or 1
         * @param Number min
         * @param Number max
         * @return Number
         */
        Mathf.prototype.randSign = function() {

            return random() < 0.5 ? 1 : -1;
        };

        /**
         * @method randChoice
         * @memberof Odin.Mathf
         * returns random item from array
         * @param Array array
         * @return Number
         */
        Mathf.prototype.randChoice = function(array) {

            return array[(random() * array.length) | 0];
        };

        /**
         * @method shuffle
         * @memberof Odin.Mathf
         * shuffles array
         * @param Array array
         * @return Array
         */
        Mathf.prototype.shuffle = function(array) {

            for (var j, x, i = array.length; i; j = (random() * i) | 0, x = array[--i], array[i] = array[j], array[j] = x);
            return array;
        };

        /**
         * @method randArg
         * @memberof Odin.Mathf
         * returns random argument from arguments
         * @return Number
         */
        Mathf.prototype.randArg = function() {

            return arguments[(random() * arguments.length) | 0];
        };

        /**
         * @method randChoiceObject
         * @memberof Odin.Mathf
         * returns random key from object
         * @param Object obj
         * @return Number
         */
        Mathf.prototype.randChoiceObject = function(obj) {
            var array = keys(obj);

            return array[(random() * array.length) | 0];
        };

        /**
         * @method isPowerOfTwo
         * @memberof Odin.Mathf
         * checks if x is a power of 2
         * @param Number x
         * @return Number
         */
        Mathf.prototype.isPowerOfTwo = function(x) {

            return (x & -x) === x;
        };

        /**
         * @method toPowerOfTwo
         * @memberof Odin.Mathf
         * returns number's next power of 2
         * @param Number x
         * @return Number
         */
        Mathf.prototype.toPowerOfTwo = function(x) {
            var i = 2;

            while (i < x) {
                i *= 2;
            }

            return i;
        };

        /**
         * @method fromJSON
         * @memberof Odin.Mathf
         * returns Math class based on json _className
         * @param Object json
         * @return MATH_CLASS
         */
        Mathf.prototype.fromJSON = function(json) {

            return new this._classes[json._className]().fromJSON(json);
        };


        var RIGHT = "right",
            UP_RIGHT = "up_right",
            UP = "up",
            UP_LEFT = "up_left",
            LEFT = "left",
            DOWN_LEFT = "down_left",
            DOWN = "down",
            DOWN_RIGHT = "down_right";
        /**
         * @method directionAngle
         * @memberof Odin.Mathf
         * returns direction string of an angle in radians
         * @param Number x
         * @param Number y
         * @return String
         */

        var n225 = 0.39269908169872414,
            n675 = 1.1780972450961724,
            n1125 = 1.9634954084936207,
            n1575 = 2.748893571891069,
            n2025 = 3.5342917352885173,
            n2475 = 4.319689898685966,
            n2925 = 5.105088062083414,
            n3375 = 5.8904862254808625;

        Mathf.prototype.directionAngle = function(a) {
            a = standardRadian(a);

            if (a >= n3375 && a < n225) return RIGHT;
            if (a >= n225 && a < n675) return UP_RIGHT;
            if (a >= n675 && a < n1125) return UP;
            if (a >= n1125 && a < n1575) return UP_LEFT;
            if (a >= n1575 && a < n2025) return LEFT;
            if (a >= n2025 && a < n2475) return DOWN_LEFT;
            if (a >= n2475 && a < n2925) return DOWN;
            if (a >= n2925 && a < n3375) return DOWN_RIGHT;

            return RIGHT;
        };

        /**
         * @method direction
         * @memberof Odin.Mathf
         * returns direction string from an x and a y coordinate
         * @param Number x
         * @param Number y
         * @return String
         */
        Mathf.prototype.direction = function(x, y) {
            var a = standardRadian(atan2(y, x));

            if (a >= n3375 && a < n225) return RIGHT;
            if (a >= n225 && a < n675) return UP_RIGHT;
            if (a >= n675 && a < n1125) return UP;
            if (a >= n1125 && a < n1575) return UP_LEFT;
            if (a >= n1575 && a < n2025) return LEFT;
            if (a >= n2025 && a < n2475) return DOWN_LEFT;
            if (a >= n2475 && a < n2925) return DOWN;
            if (a >= n2925 && a < n3375) return DOWN_RIGHT;

            return RIGHT;
        };


        return new Mathf;
    }
);