/*
* Copyright (c) 2014 tabletoptool.com team.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* rptools.com team - initial implementation
* tabletoptool.com team - further development
*/
package com.t3.model.grid;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.Action;
import javax.swing.KeyStroke;
import com.t3.client.AppPreferences;
import com.t3.client.tool.PointerTool;
import com.t3.client.ui.zone.ZoneRenderer;
import com.t3.client.walker.ZoneWalker;
import com.t3.client.walker.astar.AStarHorizHexEuclideanWalker;
import com.t3.model.CellPoint;
import com.t3.model.MovementKey;
import com.t3.model.TokenFootprint;
import com.t3.model.TokenFootprint.OffsetTranslator;
import com.t3.model.ZonePoint;
import com.t3.xstreamversioned.version.SerializationVersion;
@SerializationVersion(0)
public class HexGridHorizontal extends HexGrid {
/*
* Facings are set when a new map is created with a particular grid and these facings affect all maps with the same
* grid. Other maps with different grids will remain the same.
*
* Facings are set when maps are loaded to the current preferences.
*/
private static int[] FACING_ANGLES; // = new int[] {-150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180};
private static final int[] ALL_ANGLES = new int[] { -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180 };
private static List<TokenFootprint> footprintList;
private static final OffsetTranslator OFFSET_TRANSLATOR = new OffsetTranslator() {
@Override
public void translate(CellPoint originPoint, CellPoint offsetPoint) {
if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) {
offsetPoint.x++;
}
}
};
public HexGridHorizontal() {
super();
if (FACING_ANGLES == null) {
boolean faceEdges = AppPreferences.getFaceEdge();
boolean faceVertices = AppPreferences.getFaceVertex();
setFacings(faceEdges, faceVertices);
}
}
public HexGridHorizontal(boolean faceEdges, boolean faceVertices) {
super();
setFacings(faceEdges, faceVertices);
}
/**
* Set available facings based on the passed parameters.
*
* @param faceEdges
* - Tokens can face cell faces if true.
* @param faceVertices
* - Tokens can face cell vertices if true.
*/
@Override
public void setFacings(boolean faceEdges, boolean faceVertices) {
if (faceEdges && faceVertices) {
FACING_ANGLES = ALL_ANGLES;
} else if (!faceEdges && faceVertices) {
FACING_ANGLES = new int[] { -150, -90, -30, 30, 90, 150 };
} else if (faceEdges && !faceVertices) {
FACING_ANGLES = new int[] { -120, -60, 0, 60, 120, 180 };
} else {
FACING_ANGLES = new int[] { 90 };
}
}
@Override
public int[] getFacingAngles() {
return FACING_ANGLES;
}
/*
* For a horizontal hex grid we want the following layout:
* @formatter:off
*
* 7 - 9
* 4 5 6
* 1 - 3
*
* @formatter:off
* (non-Javadoc)
* @see com.t3.model.Grid#installMovementKeys(com.t3.client.tool.PointerTool, java.util.Map)
*/
@Override
public void installMovementKeys(PointerTool callback, Map<KeyStroke, Action> actionMap) {
if (movementKeys == null) {
movementKeys = new HashMap<KeyStroke, Action>(12); // parameter is 9/0.75 (load factor)
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD7, 0), new MovementKey(callback, -1, -1));
// movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD8, 0), new MovementKey(callback, 0, -1));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD9, 0), new MovementKey(callback, 1, -1));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD4, 0), new MovementKey(callback, -1, 0));
// movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD5, 0), new MovementKey(callback, 0, 0));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD6, 0), new MovementKey(callback, 1, 0));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, 0), new MovementKey(callback, -1, 1));
// movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0), new MovementKey(callback, 0, 1));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD3, 0), new MovementKey(callback, 1, 1));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new MovementKey(callback, -1, 0));
movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new MovementKey(callback, 1, 0));
// movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new MovementKey(callback, 0, -1));
// movementKeys.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new MovementKey(callback, 0, 1));
}
actionMap.putAll(movementKeys);
}
@Override
public void uninstallMovementKeys(Map<KeyStroke, Action> actionMap) {
if (movementKeys != null) {
for (KeyStroke key : movementKeys.keySet()) {
actionMap.remove(key);
}
}
}
@Override
public List<TokenFootprint> getFootprints() {
if (footprintList == null)
footprintList = loadFootprints("hexGridHorizFootprints.xml", getOffsetTranslator());
return footprintList;
}
@Override
public BufferedImage getCellHighlight() {
// rotate the default path highlight 90 degrees
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(90.0), pathHighlight.getHeight() / 2, pathHighlight.getHeight() / 2);
AffineTransformOp atOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
return atOp.filter(pathHighlight, null);
}
@Override
public double getCellHeight() {
return getURadius() * 2;
}
@Override
public double getCellWidth() {
return getVRadius() * 2;
}
@Override
public ZoneWalker createZoneWalker() {
return new AStarHorizHexEuclideanWalker(getZone());
}
@Override
protected Dimension setCellOffset() {
return new Dimension((int) getCellOffsetV(), (int) getCellOffsetU());
}
@Override
protected void orientHex(GeneralPath hex) {
// flip the half-hex over y = x
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(90.0));
at.scale(1, -1);
hex.transform(at);
}
@Override
protected void setGridDrawTranslation(Graphics2D g, double U, double V) {
g.translate(V, U);
}
@Override
protected double getRendererSizeV(ZoneRenderer renderer) {
return renderer.getSize().getWidth();
}
@Override
protected double getRendererSizeU(ZoneRenderer renderer) {
return renderer.getSize().getHeight();
}
@Override
protected int getOffV(ZoneRenderer renderer) {
return (int) (renderer.getViewOffsetX() + getOffsetX() * renderer.getScale());
}
@Override
protected int getOffU(ZoneRenderer renderer) {
return (int) (renderer.getViewOffsetY() + getOffsetY() * renderer.getScale());
}
@Override
public CellPoint convert(ZonePoint zp) {
CellPoint cp = convertZP(zp.y, zp.x);
return new CellPoint(cp.y, cp.x);
}
@Override
protected int getOffsetU() {
return getOffsetY();
}
@Override
protected int getOffsetV() {
return getOffsetX();
}
@Override
public ZonePoint convert(CellPoint cp) {
ZonePoint zp = convertCP(cp.y, cp.x);
return new ZonePoint(zp.y, zp.x);
}
@Override
protected OffsetTranslator getOffsetTranslator() {
return OFFSET_TRANSLATOR;
}
}