001package squidpony.squidgrid; 002 003import squidpony.squidmath.Coord; 004 005/** 006 * Represents the eight grid directions and the deltaX, deltaY values associated 007 * with those directions. 008 * 009 * The grid referenced has x positive to the right and y positive downwards on 010 * screen. 011 * 012 * @author Eben Howard - http://squidpony.com - howard@squidpony.com 013 */ 014public enum Direction { 015 016 UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0), UP_LEFT(-1, -1), UP_RIGHT(1, -1), DOWN_LEFT(-1, 1), DOWN_RIGHT(1, 1), NONE(0, 0); 017 /** 018 * An array which holds only the four cardinal directions. 019 */ 020 public static final Direction[] CARDINALS = {UP, DOWN, LEFT, RIGHT}; 021 /** 022 * An array which holds only the four diagonal directions. 023 */ 024 public static final Direction[] DIAGONALS = {UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT}; 025 /** 026 * An array which holds all eight OUTWARDS directions. 027 */ 028 public static final Direction[] OUTWARDS = {UP, DOWN, LEFT, RIGHT, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT}; 029 /** 030 * The x coordinate difference for this direction. 031 */ 032 public final int deltaX; 033 /** 034 * The y coordinate difference for this direction. 035 */ 036 public final int deltaY; 037 038 /** 039 * Returns the direction that most closely matches the input. 040 * 041 * This can be used to get the primary magnitude intercardinal direction 042 * from an origin point to an event point, such as a mouse click on a grid. 043 * 044 * If the point given is exactly on a boundary between directions then the 045 * direction clockwise is returned. 046 * 047 * @param x 048 * @param y 049 * @return 050 */ 051 public static Direction getDirection(int x, int y) { 052 if (x == 0 && y == 0) { 053 return NONE; 054 } 055 056 double angle = Math.atan2(y, x); 057 double degree = Math.toDegrees(angle); 058 degree += 450;//rotate to all positive and 0 is up 059 degree %= 360;//normalize 060 if (degree < 22.5) { 061 return UP; 062 } else if (degree < 67.5) { 063 return UP_RIGHT; 064 } else if (degree < 112.5) { 065 return RIGHT; 066 } else if (degree < 157.5) { 067 return DOWN_RIGHT; 068 } else if (degree < 202.5) { 069 return DOWN; 070 } else if (degree < 247.5) { 071 return DOWN_LEFT; 072 } else if (degree < 292.5) { 073 return LEFT; 074 } else if (degree < 337.5) { 075 return UP_LEFT; 076 } else { 077 return UP; 078 } 079 } 080 081 /** 082 * Returns the direction that most closely matches the input. 083 * 084 * This can be used to get the primary magnitude cardinal direction from an 085 * origin point to an event point, such as a mouse click on a grid. 086 * 087 * If the point given is directly diagonal then the direction clockwise is 088 * returned. 089 * 090 * @param x 091 * @param y 092 * @return 093 */ 094 public static Direction getCardinalDirection(int x, int y) { 095 if (x == 0 && y == 0) { 096 return NONE; 097 } 098 099 int absx = Math.abs(x); 100 101 if (y > absx) { 102 return UP; 103 } 104 105 int absy = Math.abs(y); 106 107 if (absy > absx) { 108 return DOWN; 109 } 110 111 if (x > 0) { 112 if (-y == x) {//on diagonal 113 return DOWN; 114 } 115 return RIGHT; 116 } 117 118 if (y == x) {//on diagonal 119 return UP; 120 } 121 return LEFT; 122 123 } 124 125 /** 126 * @param from 127 * The starting point. 128 * @param to 129 * The desired point to reach. 130 * @return The direction to follow to go from {@code from} to {@code to}. It 131 * can be cardinal or diagonal. 132 */ 133 public static Direction toGoTo(Coord from, Coord to) { 134 return getDirection(to.x - from.x, to.y - from.y); 135 } 136 137 /** 138 * Returns the Direction one step clockwise including diagonals. 139 * 140 * If considering only Cardinal directions, calling this twice will get the 141 * next clockwise cardinal direction. 142 * 143 * @return 144 */ 145 public Direction clockwise() { 146 switch (this) { 147 case UP: 148 return UP_RIGHT; 149 case DOWN: 150 return DOWN_LEFT; 151 case LEFT: 152 return UP_LEFT; 153 case RIGHT: 154 return DOWN_RIGHT; 155 case UP_LEFT: 156 return UP; 157 case UP_RIGHT: 158 return RIGHT; 159 case DOWN_LEFT: 160 return LEFT; 161 case DOWN_RIGHT: 162 return DOWN; 163 case NONE: 164 default: 165 return NONE; 166 } 167 } 168 169 /** 170 * Returns the Direction one step counterclockwise including diagonals. 171 * 172 * If considering only Cardinal directions, calling this twice will get the 173 * next counterclockwise cardinal direction. 174 * 175 * @return 176 */ 177 public Direction counterClockwise() { 178 switch (this) { 179 case UP: 180 return UP_LEFT; 181 case DOWN: 182 return DOWN_RIGHT; 183 case LEFT: 184 return DOWN_LEFT; 185 case RIGHT: 186 return UP_RIGHT; 187 case UP_LEFT: 188 return LEFT; 189 case UP_RIGHT: 190 return UP; 191 case DOWN_LEFT: 192 return DOWN; 193 case DOWN_RIGHT: 194 return RIGHT; 195 case NONE: 196 default: 197 return NONE; 198 } 199 } 200 201 /** 202 * Returns the direction directly opposite of this one. 203 * 204 * @return 205 */ 206 public Direction opposite() { 207 switch (this) { 208 case UP: 209 return DOWN; 210 case DOWN: 211 return UP; 212 case LEFT: 213 return RIGHT; 214 case RIGHT: 215 return LEFT; 216 case UP_LEFT: 217 return DOWN_RIGHT; 218 case UP_RIGHT: 219 return DOWN_LEFT; 220 case DOWN_LEFT: 221 return UP_RIGHT; 222 case DOWN_RIGHT: 223 return UP_LEFT; 224 case NONE: 225 default: 226 return NONE; 227 } 228 } 229 230 /** 231 * @return Whether this is a diagonal move. 232 */ 233 public boolean isDiagonal() { 234 switch (this) { 235 case DOWN_LEFT: 236 case DOWN_RIGHT: 237 case UP_LEFT: 238 case UP_RIGHT: 239 return true; 240 case DOWN: 241 case LEFT: 242 case NONE: 243 case RIGHT: 244 case UP: 245 return false; 246 } 247 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 248 } 249 250 /** 251 * @return {@code true} if {@code this} has an upward component. 252 */ 253 public boolean hasUp() { 254 switch (this) { 255 case UP: 256 case UP_LEFT: 257 case UP_RIGHT: 258 return true; 259 case DOWN: 260 case DOWN_LEFT: 261 case DOWN_RIGHT: 262 case LEFT: 263 case NONE: 264 case RIGHT: 265 return false; 266 } 267 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 268 } 269 270 /** 271 * @return {@code true} if {@code this} has a downward component. 272 */ 273 public boolean hasDown() { 274 switch (this) { 275 case DOWN: 276 case DOWN_LEFT: 277 case DOWN_RIGHT: 278 return true; 279 case LEFT: 280 case NONE: 281 case RIGHT: 282 case UP: 283 case UP_LEFT: 284 case UP_RIGHT: 285 return false; 286 } 287 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 288 } 289 290 /** 291 * @return {@code true} if {@code this} has a left component. 292 */ 293 public boolean hasLeft() { 294 switch (this) { 295 case DOWN_LEFT: 296 case LEFT: 297 case UP_LEFT: 298 return true; 299 case DOWN: 300 case DOWN_RIGHT: 301 case NONE: 302 case RIGHT: 303 case UP: 304 case UP_RIGHT: 305 return false; 306 } 307 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 308 } 309 310 /** 311 * @return {@code true} if {@code this} has a right component. 312 */ 313 public boolean hasRight() { 314 switch (this) { 315 case RIGHT: 316 case DOWN_RIGHT: 317 case UP_RIGHT: 318 return true; 319 case DOWN: 320 case NONE: 321 case UP: 322 case DOWN_LEFT: 323 case LEFT: 324 case UP_LEFT: 325 return false; 326 } 327 throw new IllegalStateException("Unmatched " + getClass().getSimpleName() + ": " + this); 328 } 329 330 331 Direction(int x, int y) { 332 deltaX = x; 333 deltaY = y; 334 } 335}