/******************************************************************************* * Copyright (c) 2015, 2016 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.common.movable; import jsettlers.common.position.ShortPoint2D; /** * Enumeration for directions that can be gone on the grid. * * @author Andreas Eberle */ public enum EDirection { NORTH_EAST(0, -1), EAST(1, 0), SOUTH_EAST(1, 1), SOUTH_WEST(0, 1), WEST(-1, 0), NORTH_WEST(-1, -1); private static final double TAN_67_5 = Math.tan(Math.toRadians(45 + 22.5)); private static final double TAN_22_5 = Math.tan(Math.toRadians(22.5)); public static final EDirection[] VALUES = EDirection.values(); public static final byte NUMBER_OF_DIRECTIONS = (byte) VALUES.length; public final byte gridDeltaX; public final byte gridDeltaY; public final boolean isHorizontal; public final byte ordinal; EDirection(int gridDx, int gridDy) { this.gridDeltaX = (byte) gridDx; this.gridDeltaY = (byte) gridDy; this.isHorizontal = (gridDy == 0); this.ordinal = (byte) super.ordinal(); } /** * @return delta x you have to go on the grid to go into this direction */ public byte getGridDeltaX() { return gridDeltaX; } /** * @return delta y you have to go on the grid to go into this direction */ public byte getGridDeltaY() { return gridDeltaY; } /** * LIMITATION: the given ISPosition objects need to be direct neighbors and can not be the same object!! <br> * calculates the direction between the two given ShortPoint2D objects. * * @param first * one ShortPoint2D object * @param second * another ISPisition2D object * @return EDirection if the direction exists<br> * null if it does not exist */ public static EDirection getDirection(ShortPoint2D first, ShortPoint2D second) { return getDirection(first.x, first.y, second.x, second.y); } /** * LIMITATION: the given ISPosition objects need to be direct neighbors and can not be the same object!! <br> * calculates the direction between the two given ShortPoint2D objects. * * @param sx * x of first coordinate * @param sy * y of first coordinate * @param tx * x of second coordinate * @param ty * y of second coordinate * @return EDirection if the direction exists<br> * null if it does not exist */ public static EDirection getDirection(short sx, short sy, short tx, short ty) { byte dx = (byte) (tx - sx); byte dy = (byte) (ty - sy); return getDirection(dx, dy); } /** * Returns the direction thats best to be gone to get from first to second. * <p> * If the points are equal, the result is undefined but not null. * * @param first * first position * @param second * second position * @return */ public static EDirection getApproxDirection(ShortPoint2D first, ShortPoint2D second) { return getApproxDirection(first.x, first.y, second.x, second.y); } /** * Returns the direction thats best to be gone to get from first to second. * <p> * If the points are equal, the result is undefined but not null. * * @param fx * x coordinate of first position * @param fy * y coordinate of first position * @param sx * x coordinate of second position * @param sy * y coordinate of second position * * @return */ public static EDirection getApproxDirection(int fx, int fy, int sx, int sy) { int dx = sx - fx; int dy = sy - fy; float incline = ((float) dy) / dx; if (dx == 0) { if (dy < 0) { return EDirection.NORTH_EAST; } else { return EDirection.SOUTH_WEST; } } else if (dx > 0) { if (incline < -1) { return EDirection.NORTH_EAST; } else if (incline < TAN_22_5) { return EDirection.EAST; } else if (incline < TAN_67_5) { return EDirection.SOUTH_EAST; } else { return EDirection.SOUTH_WEST; } } else { if (incline < -1) { return EDirection.SOUTH_WEST; } else if (incline < TAN_22_5) { return EDirection.WEST; } else if (incline < TAN_67_5) { return EDirection.NORTH_WEST; } else { return EDirection.NORTH_EAST; } } } public static EDirection getDirectionOfMultipleSteps(int dx, int dy) { int steps; if (dx != 0) { steps = Math.abs(dx); } else { steps = Math.abs(dy); } return getDirection(dx / steps, dy / steps); } public static EDirection getDirection(int dx, int dy) { for (EDirection currDir : VALUES) { if (currDir.gridDeltaX == dx && currDir.gridDeltaY == dy) { return currDir; } } return null; } public final int getNextTileX(int x) { return x + gridDeltaX; } public final int getNextTileY(int y) { return y + gridDeltaY; } public final int getNextTileX(int x, int steps) { return x + gridDeltaX * steps; } public final int getNextTileY(int y, int steps) { return y + gridDeltaY * steps; } /** * returns the coordinates of the next tile if you go in this direction from the given coordinates * * @param x * @param y * @return */ public ShortPoint2D getNextHexPoint(int x, int y) { return new ShortPoint2D(getNextTileX(x), getNextTileY(y)); } /** * returns the coordinates of the next tile if you go in this direction from the given location * * @param pos * @return */ public ShortPoint2D getNextHexPoint(ShortPoint2D pos) { return getNextHexPoint(pos.x, pos.y); } public ShortPoint2D getNextHexPoint(ShortPoint2D pos, int steps) { return new ShortPoint2D(getNextTileX(pos.x, steps), getNextTileY(pos.y, steps)); } /** * @param direction * direction can be in [-{@link #NUMBER_OF_DIRECTIONS}, {@link #NUMBER_OF_DIRECTIONS}]<br> * it specifies in what direction and how far away the neighbor should be taken * @return */ public EDirection getNeighbor(int direction) { return VALUES[(ordinal() + NUMBER_OF_DIRECTIONS - direction) % EDirection.NUMBER_OF_DIRECTIONS]; } public EDirection getInverseDirection() { return values()[(this.ordinal() + NUMBER_OF_DIRECTIONS / 2) % NUMBER_OF_DIRECTIONS]; } public static byte[] getXDeltaArray() { byte[] result = new byte[NUMBER_OF_DIRECTIONS]; for (int i = 0; i < NUMBER_OF_DIRECTIONS; i++) { result[i] = EDirection.VALUES[i].gridDeltaX; } return result; } public static byte[] getYDeltaArray() { byte[] result = new byte[NUMBER_OF_DIRECTIONS]; for (int i = 0; i < NUMBER_OF_DIRECTIONS; i++) { result[i] = EDirection.VALUES[i].gridDeltaY; } return result; } public final boolean isHorizontal() { return isHorizontal; } }