public final class

MathUtils

extends Object
implements MathConstants
package org.andengine.util.math;

import java.util.Random;

import android.util.FloatMath;

/**
 * (c) 2010 Nicolas Gramlich 
 * (c) 2011 Zynga Inc.
 * 
 * @author Nicolas Gramlich
 * @since 20:42:15 - 17.12.2009
 */
public final class MathUtils implements MathConstants {
	// ===========================================================
	// Constants
	// ===========================================================

	public static final Random RANDOM = new Random(System.nanoTime());

	// ===========================================================
	// Fields
	// ===========================================================

	// ===========================================================
	// Constructors
	// ===========================================================

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	// ===========================================================
	// Methods
	// ===========================================================

	public static final float atan2(final float dY, final float dX) {
		return (float)Math.atan2(dY, dX);
	}

	public static final float radToDeg(final float pRad) {
		return RAD_TO_DEG * pRad;
	}

	public static final float degToRad(final float pDegree) {
		return DEG_TO_RAD * pDegree;
	}

	public static final int signum(final int n) {
		if(n == 0) {
			return 0;
		} else if(n > 0) {
			return 1;
		} else {
			return -1;
		}
	}

	public static final int randomSign() {
		if(RANDOM.nextBoolean()) {
			return 1;
		} else {
			return -1;
		}
	}

	public static final float random(final float pMin, final float pMax) {
		return pMin + RANDOM.nextFloat() * (pMax - pMin);
	}

	/**
	 * @param pMin inclusive!
	 * @param pMax inclusive!
	 * @return
	 */
	public static final int random(final int pMin, final int pMax) {
		return pMin + RANDOM.nextInt(pMax - pMin + 1);
	}

	public static final boolean isPowerOfTwo(final int n) {
		return ((n != 0) && (n & (n - 1)) == 0);
	}

	public static final int nextPowerOfTwo(final float f) {
		return MathUtils.nextPowerOfTwo((int)(FloatMath.ceil(f)));
	}

	public static final int nextPowerOfTwo(final int n) {
		int k = n;

		if (k == 0) {
			return 1;
		}

		k--;

		for (int i = 1; i < 32; i <<= 1) {
			k = k | k >> i;
		}

		return k + 1;
	}

	public static final int sum(final int[] pValues) {
		int sum = 0;
		for(int i = pValues.length - 1; i >= 0; i--) {
			sum += pValues[i];
		}

		return sum;
	}

	public static final void arraySumInternal(final int[] pValues) {
		final int valueCount = pValues.length;
		for(int i = 1; i < valueCount; i++) {
			pValues[i] = pValues[i-1] + pValues[i];
		}
	}

	public static final void arraySumInternal(final long[] pValues) {
		final int valueCount = pValues.length;
		for(int i = 1; i < valueCount; i++) {
			pValues[i] = pValues[i-1] + pValues[i];
		}
	}

	public static final void arraySumInternal(final long[] pValues, final long pFactor) {
		pValues[0] = pValues[0] * pFactor;
		final int valueCount = pValues.length;
		for(int i = 1; i < valueCount; i++) {
			pValues[i] = pValues[i-1] + pValues[i] * pFactor;
		}
	}

	public static final void arraySumInto(final long[] pValues, final long[] pTargetValues, final long pFactor) {
		pTargetValues[0] = pValues[0] * pFactor;
		final int valueCount = pValues.length;
		for(int i = 1; i < valueCount; i++) {
			pTargetValues[i] = pTargetValues[i-1] + pValues[i] * pFactor;
		}
	}

	public static final float arraySum(final float[] pValues) {
		float sum = 0;
		final int valueCount = pValues.length;
		for(int i = 0; i < valueCount; i++) {
			sum += pValues[i];
		}
		return sum;
	}

	public static final float arrayAverage(final float[] pValues) {
		return MathUtils.arraySum(pValues) / pValues.length;
	}

	public static float[] rotateAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY) {
		if(pRotation != 0) {
			final float rotationRad = MathUtils.degToRad(pRotation);
			final float sinRotationRad = FloatMath.sin(rotationRad);
			final float cosRotationInRad = FloatMath.cos(rotationRad);

			for(int i = pVertices.length - 2; i >= 0; i -= 2) {
				final float pX = pVertices[i];
				final float pY = pVertices[i + 1];
				pVertices[i] = pRotationCenterX + (cosRotationInRad * (pX - pRotationCenterX) - sinRotationRad * (pY - pRotationCenterY));
				pVertices[i + 1] = pRotationCenterY + (sinRotationRad * (pX - pRotationCenterX) + cosRotationInRad * (pY - pRotationCenterY));
			}
		}
		return pVertices;
	}

	public static float[] scaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
		if(pScaleX != 1 || pScaleY != 1) {
			for(int i = pVertices.length - 2; i >= 0; i -= 2) {
				pVertices[i] = pScaleCenterX + (pVertices[i] - pScaleCenterX) * pScaleX;
				pVertices[i + 1] = pScaleCenterY + (pVertices[i + 1] - pScaleCenterY) * pScaleY;
			}
		}

		return pVertices;
	}

	public static float[] rotateAndScaleAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
		MathUtils.rotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
		return MathUtils.scaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
	}

	public static float[] revertScaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
		return MathUtils.scaleAroundCenter(pVertices, 1 / pScaleX, 1 / pScaleY, pScaleCenterX, pScaleCenterY);
	}

	public static float[] revertRotateAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY) {
		return MathUtils.rotateAroundCenter(pVertices, -pRotation, pRotationCenterX, pRotationCenterY);
	}

	public static float[] revertRotateAndScaleAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
		MathUtils.revertScaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
		return MathUtils.revertRotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
	}

	public static final boolean isInBounds(final int pMinValue, final int pMaxValue, final int pValue) {
		return pValue >= pMinValue && pValue <= pMaxValue;
	}

	public static final boolean isInBounds(final float pMinValue, final float pMaxValue, final float pValue) {
		return pValue >= pMinValue && pValue <= pMaxValue;
	}

	/**
	 * @param pMinValue inclusive!
	 * @param pMaxValue inclusive!
	 * @param pValue
	 * @return
	 */
	public static final int bringToBounds(final int pMinValue, final int pMaxValue, final int pValue) {
		return Math.max(pMinValue, Math.min(pMaxValue, pValue));
	}

	/**
	 * @param pMinValue inclusive!
	 * @param pMaxValue inclusive!
	 * @param pValue
	 * @return
	 */
	public static final float bringToBounds(final float pMinValue, final float pMaxValue, final float pValue) {
		return Math.max(pMinValue, Math.min(pMaxValue, pValue));
	}

	/**
	 * @return the euclidean distance between the points (pX1, pY1) and (pX2, pY2).
	 */
	public static final float distance(final float pX1, final float pY1, final float pX2, final float pY2){
		final float dX = pX2 - pX1;
		final float dY = pY2 - pY1;
		return FloatMath.sqrt((dX * dX) + (dY * dY));
	}

	/**
	 * @return the euclidean distance between the origin (0, 0) and (pX, pY).
	 */
	public static final float length(final float pX, final float pY){
		return FloatMath.sqrt((pX * pX) + (pY * pY));
	}

	/**
	 * @param pX
	 * @param pY
	 * @param pMix [0...1]
	 * @return pX * (1 - pMix) + pY * pMix
	 */
	public static final float mix(final float pX, final float pY, final float pMix) {
		return pX * (1 - pMix) + pY * pMix;
	}

	/**
	 * @param pX
	 * @param pY
	 * @param pMix [0...1]
	 * @return (int)Math.round(pX * (1 - pMix) + pY * pMix)
	 */
	public static final int mix(final int pX, final int pY, final float pMix) {
		return (int)Math.round(pX * (1 - pMix) + pY * pMix);
	}

	public static final boolean isEven(final int n) {
		return n % 2 == 0;
	}

	public static final boolean isOdd(final int n) {
		return n % 2 == 1;
	}

	public static float dot(final float pXA, final float pYA, final float pXB, final float pYB) { 
		return pXA * pXB + pYA * pYB;
	}

	public static float cross(final float pXA, final float pYA, final float pXB, final float pYB) { 
		return pXA * pYB - pXB * pYA;
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}