/* * 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; } }