|
// Note: you need an appropriate implementation of the functions mentioned here. Also // note that zero heading vector and its normal could be hardcoded if needed. For the sake of // example, let's not do that here. |
|
/** Note: you need an appropriate implementation of the functions mentioned here. Also * note that zero heading vector and its normal could be hardcoded if needed. For the sake of * example, let's not do that here. * @param angle The angle to be normalized * @return Normalized angle value, in the range (-PI, PI] */ |
|
Using dot product etc is quite a good way to do away with awkward angle normalization. I have not seen that using classes such as Vector and more operations slow things down. -- filmil |
|
Using dot product etc is quite a good way to do away with awkward angle normalization. I have not seen that using classes such as Vector and more operations slow things down. -- filmil |
public class Utils {
/**
* Constant for circle / 360 degree
*/
public final static double CIRCLE = 2 * Math.PI;
/**
* Constant for half circle 180 degree
*/
public final static double HALF_CIRCLE = Math.PI;
/**
* Classify the angle : angle in one of the nbPas classes determined using maxB, the maximum angle and minB the minimum angle
*
* You should prefer using getOutput array
*
*@param angle angle to classify
*@param minB minimum angle
*@param maxB maximimum angle
*@param nbPas number of different classes
*@return the class of angle
*/
public static int getOutput(double angle, double minB, double maxB, int nbPas) {
double diffAngle = getMinDiff(minB, maxB);
double diffB = getMinDiff(minB, angle);
double re = diffB / diffAngle * (double) nbPas;
if (Math.abs(re - nbPas) < 0.03) {
return nbPas - 1;
}
if (re < 0 || re >= nbPas) {
return -1;
}
return (int) re;
}
/**
* Classify angle in the nbPas classes determined using maxB, the maximum angle and minB the minimum angle
*
* return an array that can holds 0 or 1. 1 mean that the angle is contained in this class
*
*@param angle angle to classify
*@param error Acceptable error to classify the angle that can be Math.atan(ROBOT_RADIUS/robot_distance)
*@param minB minimum angle
*@param maxB maximimum angle
*@param nbPas number of different classes
*@return an array containing 0 and 1
*/
public static double[] getArrayOutput(double angle, double error, double minB, double maxB, int nbPas) {
double[] out = new double[nbPas];
double diffTotal = getMinDiff(minB, maxB);
int minIndex = (int) (getMinDiff(minB, angle - error) / diffTotal * (double) nbPas);
int maxIndex = (int) (getMinDiff(minB, angle + error) / diffTotal * (double) nbPas);
if ((minIndex < 0 || minIndex >= nbPas) && (maxIndex < 0 || maxIndex >= nbPas)) {
return out;
}
minIndex = Math.max(0, Math.min(nbPas - 1, minIndex));
maxIndex = Math.max(0, Math.min(nbPas - 1, maxIndex));
int limit = Math.max(minIndex, maxIndex) + 1;
for (int i = Math.min(maxIndex, minIndex); i < limit; i++) {
out[i] = 1;
}
return out;
}
/**
* Return the minimum angular difference between min and max
*
*@param min first angle
*@param max the other one
*@return minimum angular difference, can be negative
*/
public static double getMinDiff(double min, double max) {
double diffAngle = max - min;
if (Math.abs(diffAngle) > HALF_CIRCLE) {
if (max > min) {
return -(CIRCLE - max + min);
} else {
return (CIRCLE - min + max);
}
}
return diffAngle;
}
/**
* Exaclty inverse of getOuput
*
*@param minB minimum angle
*@param maxB maximimum angle
*@param index class of the angle we want to find
*@param nbPas number of different classes
*@return angle found
*/
public static double getAngleFromIndex(double min, double max, int index, int nbPas) {
double diff = getMinDiff(min, max) / (double) nbPas;
return absoluteAngle(((double) index * diff + (double) (index + 1) * diff) / 2 + min);
}
/**
* return an angle between 0 and Math.PI*2
*
*@param angle angle
*@return
*/
public static double absoluteAngle(double angle) {
while (angle < 0) {
angle += CIRCLE;
}
return angle % CIRCLE;
}
/**
* return an angle between -Math.PI and Math.PI
*
*@param angle Description of the Parameter
*@return Description of the Return Value
*/
public static double relativeAngle(double angle) {
while (angle > HALF_CIRCLE) {
angle -= CIRCLE;
}
while (angle < -HALF_CIRCLE) {
angle += CIRCLE;
}
return angle;
}
/**
* return the max distance that a bot can do in a certain time
*
*@param velocity velocity of the bot
*@param time time that the bot is going
*@param sign 1 for going forward, -1 for backward
*@return distance max
*/
public static double getMaxDist(double velocity, double time, int sign) {
double dist = 0;
while (time > 0) {
dist += Math.max(-8, Math.min(8, ((sign * velocity) > 0 ? (velocity += sign) : (velocity += sign * 2))));
time--;
}
return dist;
}
/**
* get the maximum angle that a bot can go assuming is going always at the same distance (on a circle of radius robot_distance)
*
*@param heading heading of the bot should be absolute
*@param bearing bearing of the bot
*@param velocity velocity of the bot
*@param distance distance of the bot
*@param time the time for the bullet to reach the bot
*@param sign 1 for forward, -1 for backward
*@return The maxAngle value
*/
public static double getMaxAngle(double heading, double bearing, double velocity, double distance, double time, int sign) {
bearing = absoluteAngle(bearing);
return absoluteAngle(bearing+(heading>Math.PI?-sign:sign)* ((bearing>Math.PI/2&&bearing<1.5*Math.PI)?-1:1)* Math.abs(Utils.getMaxDist(velocity,time, sign))/distance);
}
}
====Comment suggestions welcome====
This code is a bit risky:
public static double absoluteAngle(double angle) {
while (angle < 0) {
angle += CIRCLE;
}
return angle % CIRCLE;
}
I once used something similar and got caught more than once in infinite loops, when angle == Double.NEGATIVE_INFINITY. I sugest something like this:
public static double absoluteAngle(double angle) {
angle %= CIRCLE;
if (angle < 0) angle += CIRCLE;
return angle;
}
-- ABC
Shouldn't the Math.IEEERemainder() (I think that's where it is) function normalize the absolute angle to positive for you? -- Vuen
I don't get it exactly but as I understand IEEERemainder it keep the sign of the dividend. but it could be used as a first step. I never had problem with infinite loop with this. --Synnalagma
Maybe if you try fighting WhatTheHeck? :-p -- Kawigi
Math.IEEERemainder is in fact normalizeAngle just do Math.IEEERemainder(angle,2*Math.PI). --Synnalagma
Solving the problem in a direct way.
/** Note: you need an appropriate implementation of the functions mentioned here. Also
* note that zero heading vector and its normal could be hardcoded if needed. For the sake of
* example, let's not do that here.
* @param angle The angle to be normalized
* @return Normalized angle value, in the range (-PI, PI]
*/
public double absoluteAngle(double angle) {
Vector unit = Math.unitvec(angle); // get the unit vector with angle as bearing
Vector zero = Math.unitvec(0); // get the vector with angle 0
Vector norm = Math.getNormal(zero);// get the normal to unit, rotated in positive direction
double cosangle = Math.cosangle(unit,zero); // get the cosine of the angle, using dot product
int sign = Math.sign( Math.dot(unit, norm) );
double absangle = sign * java.lang.Math.acos(cosangle);
return absangle;
}
Using dot product etc is quite a good way to do away with awkward angle normalization. I have not seen that using classes such as Vector and more operations slow things down. -- filmil