I'd have to make a pull for using the dot product too: if you take the dot product of all the direction vectors, the one that has the largest value is the direction you want to take. This also has an advantage of being scaleable, you could modify it easily to only support N/E/S/W, and also could easily support N/NNE/ENE/NE/...
public static float DotProduct(Point2D.Float p1, Point2D.Float p2)
{
return (p1.x * p2.x + p1.y * p2.y);
}
public static Direction getDirection(Point2D.Float normalizedPoint)
{
int x = Math.round(normalizedPoint.x);
int y = Math.round(normalizedPoint.y);
// Order of directions: N, NE, E, SE, S, SW, W, NW
int maxDir = 0;
float maxScalarProduct = DotProduct(normalizedPoint, Point2D(0.0, 1.0)); // Check NORTH
final int NUM_DIRECTIONS = 8; // Number of directions to look for
final float DELTA = 2.0 * 3.141592654 / NUM_DIRECTIONS; // Change in radians from one direction to another
// Go through other directions, look for largest
float angle = DELTA;
for(int i = 1; i < NUM_DIRECTIONS; i++)
{
if(DotProduct(normalizedPoint, Point2D(Math.sin(angle), Math.cos(angle)) > maxScalarProduct)
{
maxDir = i;
maxScalarProduct = DotProduct(normalizedPoint, Point2D(Math.sin(angle), Math.cos(angle))
}
}
// NOTE: It would be a LOT faster if this code is a critical point (which it probably is)
// to instead or using Point2D(Math.sin(angle), Math.cos(angle)), make an array like
// xAngles = {Math.sin(0), Math.sin(45 degrees), Math.sin(90 degrees)...} from values you find yourself
// and then load them instead. Computing the sine and cosine is expensive and unnecessary.
switch(maxDir)
{
case 0: return Direction.N; break;
case 1: return Direction.NE; break;
// ...
}
return null;
}