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(); +}