Modified getDirection() to use arc tangent so that it maps angles smoothly
to their nearest compass direction instead of the wacky way it did before. Also added getFineDirection() along with rotateCW() and rotateCCW() to rotate through (fine) directions (though coarse directions can be rotated as well, simply by always requesting two ticks of rotation). Also wrote some test code to make sure everything works. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1545 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: DirectionUtil.java,v 1.4 2002/05/17 21:12:14 mdb Exp $
|
||||
// $Id: DirectionUtil.java,v 1.5 2002/06/26 02:54:56 mdb Exp $
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
@@ -23,7 +23,7 @@ public class DirectionUtil implements DirectionCodes
|
||||
*/
|
||||
public static String toString (int direction)
|
||||
{
|
||||
return ((direction >= SOUTHWEST) && (direction <= SOUTH)) ?
|
||||
return ((direction >= 0) && (direction < FINE_DIRECTION_COUNT)) ?
|
||||
DIR_STRINGS[direction] : "INVALID";
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class DirectionUtil implements DirectionCodes
|
||||
*/
|
||||
public static String toShortString (int direction)
|
||||
{
|
||||
return ((direction >= SOUTHWEST) && (direction <= SOUTH)) ?
|
||||
return ((direction >= 0) && (direction < FINE_DIRECTION_COUNT)) ?
|
||||
SHORT_DIR_STRINGS[direction] : "?";
|
||||
}
|
||||
|
||||
@@ -54,9 +54,36 @@ public class DirectionUtil implements DirectionCodes
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction that point <code>b</code> lies in from point
|
||||
* <code>a</code> as one of the {@link DirectionCodes} direction
|
||||
* constants.
|
||||
* Rotates the requested <em>fine</em> direction constant clockwise by
|
||||
* the requested number of ticks.
|
||||
*/
|
||||
public static int rotateCW (int direction, int ticks)
|
||||
{
|
||||
for (int ii = 0; ii < ticks; ii++) {
|
||||
direction = FINE_CW_ROTATE[direction];
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the requested <em>fine</em> direction constant
|
||||
* counter-clockwise by the requested number of ticks.
|
||||
*/
|
||||
public static int rotateCCW (int direction, int ticks)
|
||||
{
|
||||
for (int ii = 0; ii < ticks; ii++) {
|
||||
direction = FINE_CCW_ROTATE[direction];
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the eight compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (Point a, Point b)
|
||||
{
|
||||
@@ -64,44 +91,89 @@ public class DirectionUtil implements DirectionCodes
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction that point <code>b</code> lies in from point
|
||||
* <code>a</code> as one of the {@link DirectionCodes} direction
|
||||
* constants.
|
||||
* Returns which of the eight compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (int ax, int ay, int bx, int by)
|
||||
{
|
||||
if (ax == bx && ay > by) {
|
||||
return NORTH;
|
||||
} else if (ax == bx && ay < by) {
|
||||
return SOUTH;
|
||||
double theta = Math.atan2(by-ay, bx-ax);
|
||||
theta = ((theta + Math.PI) * 4) / Math.PI;
|
||||
return (int)(Math.round(theta) + WEST) % 8;
|
||||
}
|
||||
|
||||
} else if (ax < bx && ay > by) {
|
||||
return NORTHEAST;
|
||||
} else if (ax < bx && ay == by) {
|
||||
return EAST;
|
||||
} else if (ax < bx && ay < by) {
|
||||
return SOUTHEAST;
|
||||
/**
|
||||
* Returns which of the sixteen compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getFineDirection (Point a, Point b)
|
||||
{
|
||||
return getFineDirection(a.x, a.y, b.x, b.y);
|
||||
}
|
||||
|
||||
} else if (ax > bx && ay < by) {
|
||||
return SOUTHWEST;
|
||||
} else if (ax > bx && ay == by) {
|
||||
return WEST;
|
||||
} else if (ax > bx && ay > by) {
|
||||
return NORTHWEST;
|
||||
|
||||
} else {
|
||||
return NONE;
|
||||
}
|
||||
/**
|
||||
* Returns which of the sixteen compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getFineDirection (int ax, int ay, int bx, int by)
|
||||
{
|
||||
double theta = Math.atan2(by-ay, bx-ax);
|
||||
theta = ((theta + Math.PI) * 8) / Math.PI;
|
||||
return ANGLE_MAP[(int)Math.round(theta) % FINE_DIRECTION_COUNT];
|
||||
}
|
||||
|
||||
/** Direction constant string names. */
|
||||
protected static final String[] DIR_STRINGS = {
|
||||
"SOUTHWEST", "WEST", "NORTHWEST", "NORTH",
|
||||
"NORTHEAST", "EAST", "SOUTHEAST", "SOUTH"
|
||||
"NORTHEAST", "EAST", "SOUTHEAST", "SOUTH",
|
||||
"WESTSOUTHWEST", "WESTNORTHWEST", "NORTHNORTHWEST", "NORTHNORTHEAST",
|
||||
"EASTNORTHEAST", "EASTSOUTHEAST", "SOUTHSOUTHEAST", "SOUTHSOUTHWEST",
|
||||
};
|
||||
|
||||
/** Abbreviated direction constant string names. */
|
||||
protected static final String[] SHORT_DIR_STRINGS = {
|
||||
"SW", "W", "NW", "N", "NE", "E", "SE", "S"
|
||||
"SW", "W", "NW", "N", "NE", "E", "SE", "S",
|
||||
"WSW", "WNW", "NNW", "NNE", "ENE", "ESE", "SSE", "SSW",
|
||||
};
|
||||
}
|
||||
|
||||
/** Used to rotate a fine compass direction clockwise. */
|
||||
protected static final int[] FINE_CW_ROTATE = {
|
||||
/* SW -> */ WESTSOUTHWEST, /* W -> */ WESTNORTHWEST,
|
||||
/* NW -> */ NORTHNORTHWEST, /* N -> */ NORTHNORTHEAST,
|
||||
/* NE -> */ EASTNORTHEAST, /* E -> */ EASTSOUTHEAST,
|
||||
/* SE -> */ SOUTHSOUTHEAST, /* S -> */ SOUTHSOUTHWEST,
|
||||
/* WSW -> */ WEST, /* WNW -> */ NORTHWEST,
|
||||
/* NNW -> */ NORTH, /* NNE -> */ NORTHEAST,
|
||||
/* ENE -> */ EAST, /* ESE -> */ SOUTHEAST,
|
||||
/* SSE -> */ SOUTH, /* SSW -> */ SOUTHWEST
|
||||
};
|
||||
|
||||
/** Used to rotate a fine compass direction counter-clockwise. */
|
||||
protected static final int[] FINE_CCW_ROTATE = {
|
||||
/* SW -> */ SOUTHSOUTHWEST, /* W -> */ WESTSOUTHWEST,
|
||||
/* NW -> */ WESTNORTHWEST, /* N -> */ NORTHNORTHWEST,
|
||||
/* NE -> */ NORTHNORTHEAST, /* E -> */ EASTNORTHEAST,
|
||||
/* SE -> */ EASTSOUTHEAST, /* S -> */ SOUTHSOUTHEAST,
|
||||
/* WSW -> */ SOUTHWEST, /* WNW -> */ WEST,
|
||||
/* NNW -> */ NORTHWEST, /* NNE -> */ NORTH,
|
||||
/* ENE -> */ NORTHEAST, /* ESE -> */ EAST,
|
||||
/* SSE -> */ SOUTHEAST, /* SSW -> */ SOUTH
|
||||
};
|
||||
|
||||
/** Used to map an angle to a fine compass direction. */
|
||||
protected static final int[] ANGLE_MAP = {
|
||||
WEST, WESTNORTHWEST, NORTHWEST, NORTHNORTHWEST, NORTH, NORTHNORTHEAST,
|
||||
NORTHEAST, EASTNORTHEAST, EAST, EASTSOUTHEAST, SOUTHEAST,
|
||||
SOUTHSOUTHEAST, SOUTH, SOUTHSOUTHWEST, SOUTHWEST, WESTSOUTHWEST };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// $Id: DirectionTest.java,v 1.1 2002/06/26 02:54:56 mdb Exp $
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests the {@link Direction} class.
|
||||
*/
|
||||
public class DirectionTest extends TestCase
|
||||
implements DirectionCodes
|
||||
{
|
||||
public DirectionTest ()
|
||||
{
|
||||
super(DirectionTest.class.getName());
|
||||
}
|
||||
|
||||
public void runTest ()
|
||||
{
|
||||
int orient = NORTH;
|
||||
|
||||
for (int i = 0; i < FINE_DIRECTION_COUNT; i++) {
|
||||
// System.out.print(DirectionUtil.toShortString(orient) + " -> ");
|
||||
orient = DirectionUtil.rotateCW(orient, 1);
|
||||
}
|
||||
// System.out.println(DirectionUtil.toShortString(orient));
|
||||
assertTrue("CW rotate", orient == NORTH);
|
||||
|
||||
for (int i = 0; i < FINE_DIRECTION_COUNT; i++) {
|
||||
// System.out.print(DirectionUtil.toShortString(orient) + " -> ");
|
||||
orient = DirectionUtil.rotateCCW(orient, 1);
|
||||
}
|
||||
// System.out.println(DirectionUtil.toShortString(orient));
|
||||
assertTrue("CCW rotate", orient == NORTH);
|
||||
}
|
||||
|
||||
public static Test suite ()
|
||||
{
|
||||
return new DirectionTest();
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
DirectionTest test = new DirectionTest();
|
||||
test.runTest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// $Id: DirectionViz.java,v 1.1 2002/06/26 02:54:56 mdb Exp $
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Point;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* Renders the output of {@link DirectionUtil#getDirection} just for
|
||||
* kicks.
|
||||
*/
|
||||
public class DirectionViz extends JPanel
|
||||
implements MouseMotionListener
|
||||
{
|
||||
public DirectionViz ()
|
||||
{
|
||||
addMouseMotionListener(this);
|
||||
}
|
||||
|
||||
public void doLayout ()
|
||||
{
|
||||
super.doLayout();
|
||||
_center = new Point(getWidth() / 2, getHeight() / 2);
|
||||
}
|
||||
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
|
||||
g.setColor(Color.blue);
|
||||
g.drawLine(_center.x, _center.y, _spot.x, _spot.y);
|
||||
|
||||
int orient = DirectionUtil.getFineDirection(_center, _spot);
|
||||
g.drawString(DirectionUtil.toShortString(orient), _spot.x, _spot.y);
|
||||
}
|
||||
|
||||
public void mouseDragged (MouseEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseMoved (MouseEvent event)
|
||||
{
|
||||
_spot.x = event.getX();
|
||||
_spot.y = event.getY();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.getContentPane().add(new DirectionViz(), BorderLayout.CENTER);
|
||||
frame.setSize(300, 300);
|
||||
frame.show();
|
||||
}
|
||||
|
||||
protected Point _center;
|
||||
protected Point _spot = new Point();
|
||||
}
|
||||
Reference in New Issue
Block a user