diff --git a/src/java/com/threerings/util/DirectionUtil.java b/src/java/com/threerings/util/DirectionUtil.java
index a56c318e0..a52029b54 100644
--- a/src/java/com/threerings/util/DirectionUtil.java
+++ b/src/java/com/threerings/util/DirectionUtil.java
@@ -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 b lies in from point
- * a as one of the {@link DirectionCodes} direction
- * constants.
+ * Rotates the requested fine 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 fine 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
+ * b lies in from point a as one of the
+ * {@link DirectionCodes} direction constants. Note: that the
+ * coordinates supplied are assumed to be logical (screen) rather than
+ * cartesian coordinates and NORTH 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 b lies in from point
- * a as one of the {@link DirectionCodes} direction
- * constants.
+ * Returns which of the eight compass directions that point
+ * b lies in from point a as one of the
+ * {@link DirectionCodes} direction constants. Note: that the
+ * coordinates supplied are assumed to be logical (screen) rather than
+ * cartesian coordinates and NORTH 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
+ * b lies in from point a as one of the
+ * {@link DirectionCodes} direction constants. Note: that the
+ * coordinates supplied are assumed to be logical (screen) rather than
+ * cartesian coordinates and NORTH 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
+ * b lies in from point a as one of the
+ * {@link DirectionCodes} direction constants. Note: that the
+ * coordinates supplied are assumed to be logical (screen) rather than
+ * cartesian coordinates and NORTH 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 };
+}
diff --git a/tests/src/java/com/threerings/util/DirectionTest.java b/tests/src/java/com/threerings/util/DirectionTest.java
new file mode 100644
index 000000000..ebac4571f
--- /dev/null
+++ b/tests/src/java/com/threerings/util/DirectionTest.java
@@ -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();
+ }
+}
diff --git a/tests/src/java/com/threerings/util/DirectionViz.java b/tests/src/java/com/threerings/util/DirectionViz.java
new file mode 100644
index 000000000..c90ecbb97
--- /dev/null
+++ b/tests/src/java/com/threerings/util/DirectionViz.java
@@ -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();
+}