/*
* Copyright (c) 2003-onwards Shaven Puppy Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'Shaven Puppy' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.shavenpuppy.jglib.util;
import java.util.*;
import org.lwjgl.opengl.Display;
/**
* $Id: Util.java,v 1.13 2011/04/18 23:28:06 cix_foo Exp $
*
* Static utilities.
*
* @author cix_foo <cix_foo@users.sourceforge.net>
* @version $Revision: 1.13 $
*/
public class Util {
private static final Random random = new Random();
/**
* NO constructor for Util.
*/
private Util() {
super();
}
/**
* Returns the nearest power of 2, which is either n if n is already
* a power of 2, or the next higher number than n which is a power of 2.
*/
public static int nextPowerOf2(int n) {
int x = 1;
while (x < n) {
x <<= 1;
}
return x;
}
/**
* Returns a random number
*/
public static int random(int min, int max) {
// return ((int)(Math.random() * (1 + max - min))) + min;
if (max - min == 0) {
return min;
}
int rmin = Math.min(max, min);
int rmax = Math.max(max, min);
return random.nextInt(1 + rmax - rmin) + rmin;
// return ((int)(random.nextFloat() * (1 + max - min))) + min;
}
public static float random() {
return random.nextFloat();
}
/**
* Sets the seed for the random number generator
* @param seed The new seed
*/
public static void setSeed(long seed) {
random.setSeed(seed);
}
/**
* Create a consistent seed from the machine.
*/
@SuppressWarnings("rawtypes")
public static long getMachineSeed() {
long ret = 0L;
int lsb = 0, msb = 0;
// Get the hashcode of all the System properties
Properties props = System.getProperties();
for (Iterator i = props.entrySet().iterator(); i.hasNext(); ) {
Map.Entry entry = (Map.Entry) i.next();
lsb ^= entry.getKey().hashCode();
lsb ^= entry.getValue().hashCode();
}
// Get hashcode of some other bits and bobs
String adapter = Display.getAdapter();
String version = Display.getVersion();
msb ^= adapter != null ? adapter.hashCode() : 0;
msb ^= version != null ? version.hashCode() : 0;
ret = lsb | ((long)msb << 32L);
return ret;
}
public static float angleFromDirection(float dirX, float dirY)
{
if (dirX == 0f) {
return 0f;
}
float inv = dirY / dirX;
float ang = (float)Math.atan(inv);
// Extra half rotation if we're past 180
if (dirX < 0) {
ang += (float)Math.PI;
}
// Offset so that angle of 0 is straight up
ang -= (float)Math.PI * 0.5f;
return ang;
}
/** Does a spherical linear interpolation of two angles (in rads)
* Works for any angles ie. doesn't have to be in [0, 2PI] range.
* Will correctly handle wrapping around from 2PI -> 0
*/
public static float slerpAngle(float angle1, float angle2, float weight)
{
assert (weight >= 0f && weight <= 1f);
float oneMinus = 1f - weight;
if (Math.abs(angle1 - angle2) > Math.PI)
{
float a = angle1;
float b = angle2;
float twoPi = (float)Math.PI * 2f;
if (weight < 0.5f)
{
if (a > b) {
b += twoPi;
} else {
b -= twoPi;
}
}
else
{
if (b > a) {
a += twoPi;
} else {
a -= twoPi;
}
}
return a*weight + b*oneMinus;
}
else
{
return angle1*weight + angle2*oneMinus;
}
}
/**
* Turn a thing that is currently facing at <code>currentAngle</code> to face
* <code>targetAngle</code> at a maximum rate of <code>rate</code> degrees. The
* shortest turn is performed.
* @param currentAngle Current angle, in Yakly degrees
* @param targetAngle Target angle, in Yakly degrees
* @param rate The rate of turn
* @return the new angle
*/
public static int moveToAngle(int currentAngle, int targetAngle, int rate) {
int newAngle;
int diff = Math.abs(targetAngle - currentAngle);
if (diff < rate) {
newAngle = targetAngle;
} else if (diff > 32768) {
// Go the other way
if (targetAngle < currentAngle) {
newAngle = currentAngle + rate;
} else {
newAngle = currentAngle - rate;
}
} else {
if (targetAngle < currentAngle) {
newAngle = currentAngle - rate;
} else {
newAngle = currentAngle + rate;
}
}
while (newAngle < 0) {
newAngle += 65536;
}
return newAngle & 0xFFFF;
}
public static int getAngleDifference(int currentAngle, int targetAngle) {
currentAngle &= 0xFFFF;
while (currentAngle < 0) {
currentAngle += 65536;
}
targetAngle &= 0xFFFF;
while (targetAngle < 0) {
targetAngle += 65536;
}
int diff = Math.abs(targetAngle - currentAngle);
if (diff <= 32768) {
return diff;
} else {
if (targetAngle < currentAngle) {
return targetAngle + 65536 - currentAngle;
} else {
return currentAngle + 65536 - targetAngle;
}
}
}
public static double getAngleDifference(double currentAngle, double targetAngle) {
while (currentAngle >= Math.PI * 2.0) {
currentAngle -= Math.PI * 2.0;
}
while (targetAngle >= Math.PI * 2.0) {
targetAngle -= Math.PI * 2.0;
}
while (currentAngle < 0.0) {
currentAngle += Math.PI * 2.0;
}
while (targetAngle < 0.0) {
targetAngle += Math.PI * 2.0;
}
double diff = Math.abs(targetAngle - currentAngle);
if (diff <= Math.PI) {
return diff;
} else {
if (targetAngle < currentAngle) {
return targetAngle + Math.PI * 2.0 - currentAngle;
} else {
return currentAngle + Math.PI * 2.0 - targetAngle;
}
}
}
/**
* Turn a thing that is currently facing at <code>currentAngle</code> to face
* <code>targetAngle</code> at a maximum rate of <code>rate</code> degrees. The
* shortest turn is performed.
* @param currentAngle Current angle, in radians
* @param targetAngle Target angle, in radians
* @param rate The rate of turn
* @return the new angle, in radians
*/
public static double moveToAngle(double currentAngle, double targetAngle, double rate) {
double newAngle;
double diff = Math.abs(targetAngle - currentAngle);
if (diff < rate) {
newAngle = targetAngle;
} else if (diff > Math.PI) {
// Go the other way
if (targetAngle < currentAngle) {
newAngle = currentAngle + rate;
} else {
newAngle = currentAngle - rate;
}
} else {
if (targetAngle < currentAngle) {
newAngle = currentAngle - rate;
} else {
newAngle = currentAngle + rate;
}
}
while (newAngle < 0.0) {
newAngle += Math.PI * 2.0;
}
while (newAngle > Math.PI * 2.0) {
newAngle -= Math.PI * 2.0;
}
return newAngle;
}
/**
* Get the shortest distance from a line segment to a point
* @param x1
* @param y1
* @param z1
* @param x2
* @param y2
* @param z3
* @param px
* @param py
* @param pz
* @return the distance, which will be >= 0.0; or -1.0, if the point is beyond the segment's ends
*/
public static double distanceFromLineToPoint(double x1, double y1, double z1, double x2, double y2, double z2, double px, double py, double pz) {
double ddx = x2 - x1;
double ddy = y2 - y1;
double ddz = z2 - z1;
double lineMag = ddx * ddx + ddy * ddy + ddz * ddz;
double u = (((px - x1) * ddx) + ((py - y1) * ddy) + ((pz - z1) * ddz)) / lineMag;
if (u < 0.0f || u > 1.0f) {
return -1.0; // closest point does not fall within the line segment
}
double ix = x1 + u * (x2 - x1);
double iy = y1 + u * (y2 - y1);
double iz = z1 + u * (z2 - z1);
ddx = ix - px;
ddy = iy - py;
ddz = iz - pz;
return Math.sqrt(ddx * ddx + ddy * ddy + ddz * ddz);
}
public static double distanceFromLineToPoint(double x1, double y1, double x2, double y2, double px, double py) {
return distanceFromLineToPoint(x1, y1, 0.0, x2, y2, 0.0, px, py, 0.0);
}
}