[tiled] r737 - in trunk: . src/tiled/core src/tiled/mapeditor/dialogs src/tiled/view

tiled-svn at biggeruniverse.com tiled-svn at biggeruniverse.com
Fri Apr 11 02:30:37 PDT 2008


Author: aturk
Date: 2008-04-11 04:30:37 -0500 (Fri, 11 Apr 2008)
New Revision: 737

Modified:
   trunk/build.xml
   trunk/src/tiled/core/AnimatedTile.java
   trunk/src/tiled/mapeditor/dialogs/NewMapDialog.java
   trunk/src/tiled/view/HexMapView.java
Log:
I have merged Matthias Kievernagel's HexMapView changes in, and re-enabled hex maps in NewMapDialog. It's incomplete, but by putting it in there I hope to stimulate some development.

Modified: trunk/build.xml
===================================================================
--- trunk/build.xml	2008-04-09 22:40:26 UTC (rev 736)
+++ trunk/build.xml	2008-04-11 09:30:37 UTC (rev 737)
@@ -75,8 +75,9 @@
 
   <target name="core" depends="compile"
     description="Generate a core I/O distribution for use in games, etc.">
+    <mkdir dir="${dist}"/>
     <jar jarfile="${dist}/tiled-core.jar"
-      basedir="${build}" includes="tiled/core/**/*.class,tiled/io/**,tiled/mapeditor/util/cutter/**,tiled/util/Util.class,tiled/util/Base64.class,tiled/util/NumberedSet.class,tiled/mapeditor/util/TransparentImageFilter.class"/>
+      basedir="${build}" includes="tiled/core/**/*.class,tiled/io/**,tiled/mapeditor/util/cutter/**,tiled/mapeditor/util/MapChangeListener.class,tiled/mapeditor/util/MapChangedEvent.class,tiled/util/Util.class,tiled/util/Base64.class,tiled/util/NumberedSet.class,tiled/mapeditor/util/TransparentImageFilter.class"/>
   </target>
 
   <target name="dist_dep" depends="compile_dep"

Modified: trunk/src/tiled/core/AnimatedTile.java
===================================================================
--- trunk/src/tiled/core/AnimatedTile.java	2008-04-09 22:40:26 UTC (rev 736)
+++ trunk/src/tiled/core/AnimatedTile.java	2008-04-11 09:30:37 UTC (rev 737)
@@ -1,5 +1,5 @@
 /*
- *  Tiled Map Editor, (c) 2005
+ *  Tiled Map Editor, (c) 2004-2008
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by

Modified: trunk/src/tiled/mapeditor/dialogs/NewMapDialog.java
===================================================================
--- trunk/src/tiled/mapeditor/dialogs/NewMapDialog.java	2008-04-09 22:40:26 UTC (rev 736)
+++ trunk/src/tiled/mapeditor/dialogs/NewMapDialog.java	2008-04-11 09:30:37 UTC (rev 737)
@@ -135,8 +135,8 @@
         mapTypeChooser = new JComboBox();
         mapTypeChooser.addItem(ORTHOGONAL_MAPTYPE);
         mapTypeChooser.addItem(ISOMETRIC_MAPTYPE);
+        mapTypeChooser.addItem(HEXAGONAL_MAPTYPE);
         // TODO: Enable views when implemented decently
-        //mapTypeChooser.addItem(HEXAGONAL_MAPTYPE);
         //mapTypeChooser.addItem(SHIFTED_MAPTYPE);
 
         JPanel miscPropPanel = new VerticalStaticJPanel();

Modified: trunk/src/tiled/view/HexMapView.java
===================================================================
--- trunk/src/tiled/view/HexMapView.java	2008-04-09 22:40:26 UTC (rev 736)
+++ trunk/src/tiled/view/HexMapView.java	2008-04-11 09:30:37 UTC (rev 737)
@@ -1,5 +1,5 @@
 /*
- *  Tiled Map Editor, (c) 2004-2006
+ *  Tiled Map Editor, (c) 2004-2008
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -12,153 +12,364 @@
 
 package tiled.view;
 
+// for console logging
+import java.util.logging.*;
+import java.io.IOException;
+
 import java.awt.*;
-import java.awt.geom.Point2D;
+import java.awt.geom.*;
+
 import javax.swing.SwingConstants;
 
-import tiled.core.Map;
-import tiled.core.ObjectGroup;
-import tiled.core.Tile;
-import tiled.core.TileLayer;
+import tiled.core.*;
+//import tiled.io.TiledLogger;
 import tiled.mapeditor.selection.SelectionLayer;
 
 /**
  * A View for displaying Hex based maps.
- * The Hexs are layed out horizontally (i.e. the pointy sides are on the sides
- * and the flat sides are on the bottom).
+ * There are four possible layouts for the hexes. These are called
+ * tile alignment and are named 'top', 'bottom', 'left' and 'right'.
+ * The name designates the border where the first row or column of
+ * hexes is aligned with a flat side. I.e. 'left' and 'right' result
+ * in hexes with the pointy sides up and down and the first row
+ * either aligned left or right:
  * <pre>
- *       ___
- * e.g. /   \
- *      \---/
+ *   /\
+ *  |  |
+ *   \/
  * </pre>
+ * And 'top' and 'bottom' result in hexes with the pointy sides to
+ * the left and right and the first column either aligned top or bottom:
+ * <pre>
+ *   __
+ *  /  \
+ *  \__/
  *
- * Even numbered columns are staggered downwards by half a hex.
+ * </pre>
+
+ * <p>Here is an example 2x2 map with top alignment:
  * <pre>
- * e.g.
- *     1,0     3,0
- * 0,0     2,0     4,0
- *     1,1     3,1
- * 0,1     2,1     4,1
+ *   ___
+ *  /0,0\___
+ *  \___/1,0\
+ *  /0,1\___/
+ *  \___/1,1\
+ *      \___/
  * </pre>
  *
- * <p>The icon width (as returned by Map.getTileWidth()) refers to the total
- * width of a hex (i.e from the left most corner to the right most corner). The
- * actual distance between two adjacent hexes is equal to 3/4 of this figure.
+ * <p>The icon width and height refer to the total width and height
+ * of a hex (i.e the size of the enclosing rectangle).
  *
- * <p>The icon height (as returned by Map.getTileHeight()) refers to the total
- * height of a hex (i.e. from the bottom edge to the top edge).
- * This is equal to the distance between two adjacent hexes (in the same
- * column)
- *
  * @version $Id$
  */
 public class HexMapView extends MapView
 {
+    public static final int ALIGN_TOP = 1;
+    public static final int ALIGN_BOTTOM = 2;
+    public static final int ALIGN_RIGHT = 3;
+    public static final int ALIGN_LEFT = 4;
+
     private static final double HEX_SLOPE = Math.tan(Math.toRadians(60));
 
+    private int mapAlignment;
+    /* hexEdgesToTheLeft:
+     * This means a layout like this:     __
+     *                                   /  \
+     *                                   \__/
+     * as opposed to this:     /\
+     *                        |  |
+     *                         \/
+     */
+    private boolean hexEdgesToTheLeft;
+    private boolean alignedToBottomOrRight;
+
     /**
      * Creates a new hexagonal map view that displays the specified map.
      *
-     * @param map the map to be displayed by this map view
+     * @param map The map to be displayed by this map view.
      */
     public HexMapView(Map map) {
         super(map, null);
+
+        //mapAlignment = map.getAlignment();
+        mapAlignment = ALIGN_TOP;
+        hexEdgesToTheLeft = false;
+        if ( mapAlignment == ALIGN_TOP
+            || mapAlignment == ALIGN_BOTTOM ) {
+            hexEdgesToTheLeft = true;
+        }
+        alignedToBottomOrRight = false;
+        if ( mapAlignment == ALIGN_BOTTOM
+            || mapAlignment == ALIGN_RIGHT ) {
+            alignedToBottomOrRight = true;
+        }
+
+        //TiledLogger.getLogger().info("HexMapView created");
     }
 
+    /**
+     * The scroll increment when clicking in the trough of a scrollbar,
+     * that is scrolling a page. The amount is set to the size
+     * of the completely visible hexes in the viewport.
+     *
+     * @param visibleRect Current viewport rectangle.
+     * @param orientation SwingConstants.VERTICAL or HORIZONTAL.
+     * @param direction > 0 = scrolling down; < 0 = scrolling up.
+     *
+     * @return Scroll amount in pixels.
+     */
     public int getScrollableBlockIncrement(Rectangle visibleRect,
             int orientation, int direction) {
-        Dimension tsize = getTileSize();
+        Dimension tsize = getEffectiveTileSize();
+        int border = showGrid ? 1 : 0;
+        int tq = getThreeQuarterHex();
+        int hWidth = (int)(tsize.width / 2 + 0.49) + border;
+        int hHeight = (int)(tsize.height / 2 + 0.49) + border;
 
-        if (orientation == SwingConstants.VERTICAL) {
-            return (visibleRect.height / tsize.height) * tsize.height;
+        //TiledLogger.getLogger().info(
+        //    "ScrollBlock " + orientation + "/" + direction);
+        //TiledLogger.getLogger().info(
+        //    "visibleRect " + visibleRect.width + "," + visibleRect.height );
+        //TiledLogger.getLogger().info(
+        //    "tq " + tq + " border " + border + " height " + tsize.height);
+        //TiledLogger.getLogger().info(
+        //    "BlockInc w "
+        //    + ((int)(visibleRect.width / (tq + border)) * (tq + border))
+        //    + ", h "
+        //    + ((int)(visibleRect.height / (tsize.height + border))
+        //        * (tsize.height + border)));
+
+        if (orientation == SwingConstants.VERTICAL ) {
+            if ( hexEdgesToTheLeft ) {
+                return (int)((visibleRect.height - hHeight)
+                    / (tsize.height + border))
+                    * (tsize.height + border);
+            } else {
+                return (int)((visibleRect.height -hHeight) / (tq + border))
+                    * (tq + border);
+            }
         } else {
-            return (visibleRect.width / tsize.width) * tsize.width;
+            if ( hexEdgesToTheLeft ) {
+                return (int)((visibleRect.width - hWidth) / (tq + border))
+                    * (tq + border);
+            } else {
+                return (int)((visibleRect.width - hWidth)
+                    / (tsize.width + border))
+                    * (tsize.width + border);
+            }
         }
     }
 
+    /**
+     * The scroll increment when clicking on the arrows of a scrollbar,
+     * that is scrolling one hex horizontically or vertically.
+     *
+     * @param visibleRect Current viewport rectangle.
+     * @param orientation SwingConstants.VERTICAL or HORIZONTAL.
+     * @param direction > 0 = scrolling down; < 0 = scrolling up.
+     *
+     * @return Scroll amount in pixels.
+     */
     public int getScrollableUnitIncrement(Rectangle visibleRect,
             int orientation, int direction) {
-        Dimension tsize = getTileSize();
-        if (orientation == SwingConstants.VERTICAL) {
-            return tsize.height;
+        //TiledLogger.getLogger().info(
+        //    "ScrollUnit " + orientation + "/" + direction);
+        Dimension tsize = getEffectiveTileSize();
+        int border = showGrid ? 1 : 0;
+        int tq = getThreeQuarterHex();
+        if (orientation == SwingConstants.VERTICAL ) {
+            if ( hexEdgesToTheLeft ) {
+                return tsize.height + border;
+            } else {
+                return tq + border;
+            }
         } else {
-            return tsize.width;
+            if ( hexEdgesToTheLeft ) {
+                return tq + border;
+            } else {
+                return tsize.width + border;
+            }
         }
     }
 
+    /**
+     * The total size of the viewport so that all tiles of
+     * the map fit in.
+     *
+     * @return Width and Height as Dimension.
+     */
     public Dimension getPreferredSize() {
-        Dimension tsize = getTileSize();
+        Dimension tsize = getEffectiveTileSize();
+        int w;
+        int h;
         int border = showGrid ? 1 : 0;
-        int wbhc = (int) getWidthBetweenHexCentres();
+        int tq = getThreeQuarterHex();
+        int oq = getOneQuarterHex();
 
-        return new Dimension(
-                map.getWidth() * wbhc + border + wbhc,
-                map.getHeight() * tsize.height + border +
-                tsize.height / 2);
+        if ( hexEdgesToTheLeft ) {
+            //TiledLogger.getLogger().info(
+            //    " twidth*3/4 " + tq
+            //    + " twidth/4 " + oq
+            //    + " theight/2 " + ((int)(tsize.height / 2 + 0.49)));
+
+            w = map.getWidth() * (tq + border) + oq + border;
+            h = map.getHeight() * (tsize.height + border)
+                + (int)(tsize.height / 2 + 0.49) + border;
+        } else {
+            w = map.getWidth() * (tsize.width + border)
+                + (int)(tsize.width / 2 + 0.49) + border;
+            h = map.getHeight() * (tq + border) + oq + border;
+        }
+
+        //TiledLogger.getLogger().info("size " + w + "," + h);
+
+        return new Dimension(w, h);
     }
 
+    /**
+     * Paint one layer to the viewport.
+     *
+     * @param g2d The graphics context, i.e. where to paint.
+     * @param layer The layer to paint. Can be a special layer
+     *        like the selection layer.
+     */
     protected void paintLayer(Graphics2D g2d, TileLayer layer) {
         // Determine area to draw from clipping rectangle
-        Dimension tsize = getTileSize();
-        int toffset = showGrid ? 1 : 0;
+        Dimension tsize = getEffectiveTileSize();
+        // int toffset = showGrid ? 1 : 0;
 
         Rectangle clipRect = g2d.getClipBounds();
-        int startX = clipRect.x / tsize.width;
-        int startY = clipRect.y / tsize.height - 1;
-        int endX = (int)(((clipRect.x + clipRect.width) / tsize.width) * 1.5) + 2;
-        int endY = ((clipRect.y + clipRect.height) / tsize.height) * 3 + 2;
 
-        int gy = startY * tsize.height + toffset;
-        for (int y = startY; y < endY; y++) {
-            Polygon gridPoly = createGridPolygon(0, y, 1);
-            gridPoly.translate(0, -(int)(tsize.getHeight() / 2));
-            int gx = startX * tsize.width + toffset;
-            for (int x = startX; x < endX; x++) {
+        //TiledLogger.getLogger().info("clip " + clipRect.x + "," + clipRect.y
+        //    + "-" + clipRect.width + "," + clipRect.height);
+
+        Point topLeft = screenToTileCoords(
+                (int)clipRect.getMinX(), (int)clipRect.getMinY());
+        Point bottomRight = screenToTileCoords(
+                (int)clipRect.getMaxX(), (int)clipRect.getMaxY());
+        int startX = (int)topLeft.getX();
+        int startY = (int)topLeft.getY();
+        int endX = (int)(bottomRight.getX());
+        int endY = (int)(bottomRight.getY());
+        if ( startX < 0 ) {
+            startX = 0;
+        }
+        if ( startY < 0 ) {
+            startY = 0;
+        }
+        if ( endX >= map.getWidth()) {
+            endX = map.getWidth() - 1;
+        }
+        if ( endY >= map.getHeight()) {
+            endY = map.getHeight() - 1;
+        }
+
+        //TiledLogger.getLogger().info("index " + startX + "," + startY
+        //    + "-" + endX + "," + endY);
+
+        Polygon gridPoly;
+        double gx;
+        double gy;
+        for (int y = startY; y <= endY; y++) {
+            for (int x = startX; x <= endX; x++) {
                 Tile t = layer.getTileAt(x, y);
 
                 if (t != null) {
                     if (layer.getClass() == SelectionLayer.class) {
+                        //TiledLogger.getLogger().info(
+                        //    "selection tile at " + x + "," + y);
+                        gridPoly = createGridPolygon(x, y, 0);
                         g2d.fillPolygon(gridPoly);
                     } else {
-                        t.draw(g2d, gx, (int)(gy + (tsize.getHeight() / 2) *
-                                    (1 - x % 2)), zoom);
+                        Point screenCoords = getTopLeftCornerOfTile(x, y);
+                        gx = screenCoords.getX();
+                        gy = screenCoords.getY();
+                        //TiledLogger.getLogger().info(
+                        //    "image tile at " + x + "," + y
+                        //    + " at " + gx + "," + gy);
+                        t.draw(g2d, (int)gx, (int)(gy + tsize.height),
+                            zoom);
                     }
                 }
-                if (x % 2 == 0) {
-                    gridPoly.translate(
-                            (int)(tsize.getWidth() * .75),
-                            -(int)(tsize.getHeight() / 2));
-                } else {
-                    gridPoly.translate(
-                            (int)(tsize.getWidth() * .75),
-                            (int)(tsize.getHeight() / 2));
-                }
-                gx += tsize.getWidth() * .75;
             }
-            gy += tsize.getHeight();
         }
     }
 
-    protected void paintObjectGroup(Graphics2D g2d, ObjectGroup og) {
+    /**
+     * Paint one layer to the viewport. Is this function used?
+     * Not implemented!
+     *
+     * @param g2d The graphics context, i.e. where to paint.
+     * @param og What is that?
+     */
+    protected void paintLayer(Graphics2D g2d, ObjectGroup og) {
+        //TiledLogger.getLogger().info("called ?");
     }
 
     /**
-     * Returns the distance between the centres of two horizontally adjacent
-     * Hexes.
+     * @return The tile size in the view without border as Dimension.
      */
-    private double getWidthBetweenHexCentres() {
-        return map.getTileWidth() * 3 / 4;
+    private Dimension getEffectiveTileSize() {
+        //TiledLogger.getLogger().info("size "
+        //    + ((int)(map.getTileWidth() * zoom + 0.999)) + ","
+        //    + ((int)(map.getTileHeight() * zoom + 0.999)));
+        return new Dimension((int)(map.getTileWidth() * zoom + 0.999),
+            (int)(map.getTileHeight() * zoom + 0.999));
     }
 
-    private Dimension getTileSize() {
-        return new Dimension(
-                (int)(map.getTileWidth() * zoom),
-                (int)(map.getTileHeight() * zoom));
+    /**
+     * Together with getOneQuarterHex this gives the sizes of
+     * one and three quarters in pixels in the interesting dimension.
+     * If the layout is such that the hex edges point left and right
+     * the interesting dimension is the width, otherwise it is the height.
+     * The sum of one and three quarters equals always the total size
+     * of the hex in this dimension.
+     *
+     * @return Three quarter of the tile size width or height (see above)
+     * as integer.
+     */
+    private int getThreeQuarterHex() {
+        int tq;
+        if ( hexEdgesToTheLeft ) {
+            tq = (int)(getEffectiveTileSize().width * 3.0 / 4.0 + 0.49);
+        } else {
+            tq = (int)(getEffectiveTileSize().height * 3.0 / 4.0 + 0.49);
+        }
+
+        return tq;
     }
 
+    /**
+     * Together with getThreeQuarterHex this gives the sizes of
+     * one and three quarters in pixels in the interesting dimension.
+     * If the layout is such that the hex edges point left and right
+     * the interesting dimension is the width, otherwise it is the height.
+     * The sum of one and three quarters equals always the total size
+     * of the hex in this dimension.
+     *
+     * @return One quarter of the tile size width or height (see above)
+     * as integer.
+     */
+    private int getOneQuarterHex() {
+        int oq;
+        if ( hexEdgesToTheLeft ) {
+            oq = getEffectiveTileSize().width;
+        } else {
+            oq = getEffectiveTileSize().height;
+        }
+
+        return oq - getThreeQuarterHex();
+    }
+
+    /**
+     * Paint the grid to the viewport.
+     *
+     * @param g2d The graphics context, i.e. where to paint.
+     */
     protected void paintGrid(Graphics2D g2d) {
         g2d.setColor(Color.black);
-        Dimension tileSize = getTileSize();
+        Dimension tileSize = getEffectiveTileSize();
+
         // Determine area to draw from clipping rectangle
         Rectangle clipRect = g2d.getClipBounds();
         Point topLeft = screenToTileCoords(
@@ -167,166 +378,325 @@
                 (int)clipRect.getMaxX(), (int)clipRect.getMaxY());
         int startX = (int)topLeft.getX();
         int startY = (int)topLeft.getY();
-        int endX = (int)(bottomRight.getX() * 1.5) + 1;
-        int endY = (int)bottomRight.getY() * 2 + 1;
+        int endX = (int)(bottomRight.getX());
+        int endY = (int)(bottomRight.getY());
+
+        //TiledLogger.getLogger().info(
+        //    "  scrn " + clipRect.getMinX() + "," + clipRect.getMinY()
+        //    + "-" + clipRect.getMaxX() + "," + clipRect.getMaxY());
+        //TiledLogger.getLogger().info(
+        //    "  tile " + startX + "," + startY + "-" + endX + "," + endY);
+
+        if ( startX < 0 ) {
+            startX = 0;
+        }
+        if ( startY < 0 ) {
+            startY = 0;
+        }
+        if ( endX >= map.getWidth()) {
+            endX = map.getWidth() - 1;
+        }
+        if ( endY >= map.getHeight()) {
+            endY = map.getHeight() - 1;
+        }
+
+        //TiledLogger.getLogger().info("  tile " + startX + "," + startY
+        //    + "-" + endX + "," + endY);
+
         int dy = 0;
+        int dx = 0;
         Polygon grid;
 
-        for (int y = startY; y < endY; y++, dy += tileSize.getHeight()) {
-            grid = createGridPolygon(0, 0, 1);
-            grid.translate(0,dy);
-            for (int x = startX; x < endX; x++) {
-                grid.translate(0,
-                        (int)((tileSize.getHeight() / 2) * (1 - x % 2)));
-                g2d.drawPolygon(grid);
-                grid.translate((int)(tileSize.getWidth() * .75), 0);
-                grid.translate(0,
-                        -(int)((tileSize.getHeight() / 2) * (1 - x % 2)));
+        if ( hexEdgesToTheLeft ) {
+            for (int x = startX; x <= endX; x++) {
+                grid = createGridPolygon(x, startY, 1);
+                for (int y = startY; y <= endY; y++) {
+                    g2d.drawPolygon(grid);
+                    grid.translate(0, tileSize.height + 1);
+                }
             }
+        } else {
+            for (int y = startY; y <= endY; y++) {
+                grid = createGridPolygon(startX, y, 1);
+                for (int x = startX; x <= endX; x++) {
+                    g2d.drawPolygon(grid);
+                    grid.translate(tileSize.width + 1, 0);
+                }
+            }
         }
     }
 
+    /**
+     * Paint coordinates.
+     * This should draw tiny coordinates in every hex tile.
+     * Not implemented.
+     *
+     * @param g2d The graphics context, i.e. where to paint.
+     */
     protected void paintCoordinates(Graphics2D g2d) {
         // TODO: Implement paintCoordinates for HexMapView
+        //TiledLogger.getLogger().info("NOT IMPLEMENTED");
     }
 
-    protected void paintPropertyFlags(Graphics2D g2d, TileLayer layer) {
-        throw new RuntimeException("Not yet implemented");    // todo
-    }
-
+    /**
+     * Compute the resulting tile coords, i.e. map coordinates,
+     * from a point in the viewport. This function works for some
+     * coords off the map, i.e. it works for the tile coord -1
+     * and for coords larger than the map size.
+     *
+     * @param screenX The x coordinate of a point in the viewport.
+     * @param screenY The y coordinate of a point in the viewport.
+     *
+     * @return The corresponding tile coords as Point.
+     */
     public Point screenToTileCoords(int screenX, int screenY) {
-        // An algorithm copied from the net years ago
-        // Note the C style short variable names :-)
-        int x = (int)(screenX / zoom);
-        int y = (int)(screenY / zoom);
-        double hexWidth = getWidthBetweenHexCentres();
-        double hexHeight = map.getTileHeight();
+        //TiledLogger.getLogger().info(
+          //  "screen coords " + screenX + "," + screenY);
 
-        double tw = hexWidth * 2 / 3;
-        double cw = hexWidth / 3;
+        int tx = 0;
+        int ty = 0;
+        int border = showGrid ? 1 : 0;
+        Dimension tileSize = getEffectiveTileSize();
+        int tileWidth = tileSize.width + border;
+        int tileHeight = tileSize.height + border;
+        int hWidth = (int)(tileWidth / 2 + 0.49) + border;
+        int hHeight = (int)(tileHeight / 2 + 0.49) + border;
+        Point [] fourPoints = new Point [4];
+        Point [] fourTiles = new Point [4];
 
-        int adjustyhexes = 10;
+        int x = screenX;
+        int y = screenY;
 
-        // Note: We adjust my & mx so they are always positive.
-        // The algorithm returns incorrect values for negative my
-        // The value adjustyhexes is arbitrary.
-        // my is only ever negative for offboard hexes at the top of the map
-        // We adjust it back further down
-        int my = (int)(y + hexHeight * adjustyhexes);
-        int mx = (int)(x + cw + hexWidth * adjustyhexes);
-        int tx = (int)(mx / hexWidth);
-        int rx = (int)(mx % hexWidth);
+        // determine the two columns of hexes we are between
+        // we are between col and col+1.
+        // col == -1 means we are in the strip to the left
+        //   of the centers of the hexes of column 0.
+        int col = 0;
+        if ( x < hWidth ) {
+            col = -1;
+        } else {
+            if ( hexEdgesToTheLeft ) {
+                col = (int)((x - hWidth)
+                    / (double)(getThreeQuarterHex() + border) + 0.001);
+            } else {
+                col = (int)((x - hWidth) / (double)tileWidth + 0.001);
+            }
+        }
 
-        if (tx % 2 == 1) {
-            my += hexHeight / 2;
+        // determine the two rows of hexes we are between
+        int row = 0;
+        if ( y < hHeight ) {
+            row = -1;
+        } else {
+            if ( hexEdgesToTheLeft ) {
+                row = (int)((y - hHeight) / (double)tileHeight + 0.001);
+            } else {
+                row = (int)((y - hHeight)
+                    / (double)(getThreeQuarterHex() + border) + 0.001);
+            }
         }
 
-        int ty = (int)(my / hexHeight);
-        int ry = (int)(my % hexHeight);
+        //TiledLogger.getLogger().info("  columns " + col + "/" + (col + 1));
+        //TiledLogger.getLogger().info("  rows " + row + "/" + (row + 1));
 
-        if (rx > tw) {
-            double newX = rx - tw;
-            double height = (cw - newX) * HEX_SLOPE;
-            if (ry < hexHeight / 2 - height) {
-                tx++;
-                if (tx % 2 == 0) {
-                    ty--;
-                }
+        // now take the four surrounding points and
+        // find the one having the minimum distance to x,y
+        fourTiles [0] = new Point(col, row);
+        fourTiles [1] = new Point(col, row + 1);
+        fourTiles [2] = new Point(col + 1, row);
+        fourTiles [3] = new Point(col + 1, row + 1);
+
+        fourPoints [0] = tileToScreenCoords(col, row);
+        fourPoints [1] = tileToScreenCoords(col, row + 1);
+        fourPoints [2] = tileToScreenCoords(col + 1, row);
+        fourPoints [3] = tileToScreenCoords(col + 1, row + 1);
+
+        // find point with min.distance
+        double minDist = 2 * (map.getTileWidth() + map.getTileHeight());
+        int minI = 5;
+        //TiledLogger.getLogger().info("  init Min " + minDist);
+        for ( int i = 0; i < fourPoints.length; i++ ) {
+            if ( fourPoints [i].distance(x, y) < minDist ) {
+                minDist = fourPoints [i].distance(x, y);
+                minI = i;
             }
-            if (ry > hexHeight / 2 + height) {
-                tx++;
-                if (tx % 2 == 1) {
-                    ty++;
-                }
-            }
+
+            //TiledLogger.getLogger().info("  min.pt " + fourPoints [minI].getX()
+            //    + "," + fourPoints [minI].getY() + " index " + minI
+            //    + " at dist " + minDist);
         }
 
-        // Adjust back (see above)
-        ty -= adjustyhexes;
-        tx -= adjustyhexes;
+        // get min point
+        tx = (int)(fourTiles [minI].getX());
+        ty = (int)(fourTiles [minI].getY());
 
+        //TiledLogger.getLogger().info("  -> tile coords " + tx + "," + ty);
+
         return new Point(tx, ty);
     }
 
-    public Point screenToPixelCoords(int x, int y) {
-        // TODO: add proper implementation
-        return new Point();
-    }
-
     /**
-     * Get the point at the top left corner of the bounding rectangle of this
-     * hex.
+     * Get the height of a tile of the map.
+     * I do not know why this function is here.
+     *
+     * @return The tile height as double.
      */
-    private Point2D getTopLeftCornerOfHex(int x, int y) {
-        Dimension tileSize = getTileSize();
-        Point2D centre = tileToScreenCoords(x, y);
-        double leftX = centre.getX() - tileSize.getWidth() / 2;
-        double topY = centre.getY() - tileSize.getHeight() / 2;
-        return new Point2D.Double(leftX, topY);
-    }
-
     private double getTileHeight() {
         return map.getTileHeight();
     }
 
+    /**
+     * Repaint a region of the viewport.
+     * This function has been disabled. I have tried it
+     * but it seems to repaint with some offset.
+     *
+     * @param The rectangle of the viewport to be repainted.
+     */
     public void repaintRegion(Rectangle region) {
         super.repaintRegion(region);
-        // This code should work. I've disabled it because of general problems with the view refresh.
-        //        Point2D topLeft=getTopLeftCornerOfHex((int) region.getMinX(),(int) region.getMinY(),zoom);
-        //        Point2D bottomRight=getTopLeftCornerOfHex((int) region.getMaxX(),(int) region.getMaxY(),zoom);
-        //
-        //        Dimension tileSize=getTileSize(zoom);
-        //        int width=(int) (bottomRight.getX()-topLeft.getX()+tileSize.getWidth());
-        //        int height=(int) (bottomRight.getY()-topLeft.getY()+tileSize.getHeight());
-        //
-        //        Rectangle dirty=new Rectangle((int) topLeft.getX(),(int) topLeft.getY(),width,height);
-        //
-        //        repaint(dirty);
+
+        //TiledLogger.getLogger().info(
+        //    "region " + region.getMinX() + "," + region.getMinY()
+        //    + "-" + region.getMaxX() + "," + region.getMaxY()
+        //    + " zoom " + zoom);
+
+        // // This code should work. I've disabled it because of general problems with the view refresh.
+        // // Point2D topLeft=getTopLeftCornerOfTile((int) region.getMinX(),(int) region.getMinY(),zoom);
+        // // Point2D bottomRight=getTopLeftCornerOfTile((int) region.getMaxX(),(int) region.getMaxY(),zoom);
+        // Point2D topLeft=getTopLeftCornerOfTile((int) region.getMinX(),(int) region.getMinY());
+        // Point2D bottomRight=getTopLeftCornerOfTile((int) region.getMaxX(),(int) region.getMaxY());
+        // 
+        // // Dimension tileSize=getTileSize(zoom);
+        // Dimension tileSize=getTileSize();
+        // int width=(int) (bottomRight.getX()-topLeft.getX()+tileSize.getWidth());
+        // int height=(int) (bottomRight.getY()-topLeft.getY()+tileSize.getHeight());
+        // 
+        // Rectangle dirty=new Rectangle((int) topLeft.getX(),(int) topLeft.getY(),width,height);
+        // 
+        // repaint(dirty);
     }
 
 
+    /**
+     * Returns a hexagon at the given tile coordinates.
+     *
+     * @param tx The x coordinate of the tile.
+     * @param ty The y coordinate of the tile.
+     * @param border 0 = no border, 1 = with border line.
+     *
+     * @return A hexagon structure as Polygon.
+     */
     protected Polygon createGridPolygon(int tx, int ty, int border) {
-        double centrex, centrey;
-        Dimension tileSize = getTileSize();
+        Dimension tileSize = getEffectiveTileSize();
         Polygon poly = new Polygon();
+        Point p = getTopLeftCornerOfTile(tx, ty);
+        int topLeftX = (int)(p.getX());
+        int topLeftY = (int)(p.getY());
 
-        centrex = tx*tileSize.getWidth() + tileSize.getWidth() / 2;
-        centrey = ty*tileSize.getHeight() + tileSize.getHeight() / 2;
+        //TiledLogger.getLogger().info("hex at " + topLeftX + "," + topLeftY);
 
+        int tq = getThreeQuarterHex();
+        int oq = getOneQuarterHex();
+
         // Go round the sides clockwise
-        poly.addPoint(
-                (int)(centrex - tileSize.getWidth() / 2),
-                (int)centrey);
-        poly.addPoint(
-                (int)(centrex - tileSize.getWidth() / 4),
-                (int)(centrey - tileSize.getHeight() / 2));
-        poly.addPoint(
-                (int)(centrex + tileSize.getWidth() / 4),
-                (int)(centrey - tileSize.getHeight() / 2));
-        poly.addPoint(
-                (int)(centrex + tileSize.getWidth() / 2),
-                (int)centrey);
-        poly.addPoint(
-                (int)(centrex + tileSize.getWidth() / 4),
-                (int)(centrey + tileSize.getHeight() / 2));
-        poly.addPoint(
-                (int)(centrex - tileSize.getWidth() / 4),
-                (int)(centrey + tileSize.getHeight() / 2));
+        if ( hexEdgesToTheLeft ) {
+            int hh = (int)(tileSize.height / 2 + 0.49);
 
+            poly.addPoint(topLeftX - 1, topLeftY + hh - 1);
+            poly.addPoint(topLeftX + oq - 1, topLeftY - 1);
+            poly.addPoint(topLeftX + tq, topLeftY - 1);
+            poly.addPoint(topLeftX + tileSize.width, topLeftY + hh - 1);
+            poly.addPoint(topLeftX + tq, topLeftY + tileSize.height);
+            poly.addPoint(topLeftX + oq - 1, topLeftY + tileSize.height);
+        } else {
+            int hh = (int)(tileSize.width / 2 + 0.49);
+
+            poly.addPoint(topLeftX + hh - 1, topLeftY - 1);
+            poly.addPoint(topLeftX + tileSize.width, topLeftY + oq - 1);
+            poly.addPoint(topLeftX + tileSize.width, topLeftY + tq);
+            poly.addPoint(topLeftX + hh - 1, topLeftY + tileSize.height);
+            poly.addPoint(topLeftX - 1, topLeftY + tq);
+            poly.addPoint(topLeftX - 1, topLeftY + oq - 1);
+        }
+
         return poly;
     }
 
     /**
-     * Returns the location on screen for the given tile.
+     * Get the point at the top left corner of the bounding rectangle of this
+     * hex.
      *
-     * @return The point at the centre of the Hex.
+     * @param x The x coordinate of the tile.
+     * @param y The y coordinate of the tile.
+     *
+     * @return The top left corner of the enclosing rectangle of the hex
+     *         in screen coordinates as Point.
      */
-    public Point tileToScreenCoords(double x, double y) {
-        double xx = getWidthBetweenHexCentres() * x;
-        double yy = getTileHeight() * y;
-        if (x % 2 == 0) {
-            yy += getTileHeight() / 2;
+    private Point getTopLeftCornerOfTile(int x, int y) {
+        //TiledLogger.getLogger().info("tile coords " + x + "," + y);
+
+        Dimension tileSize = getEffectiveTileSize();
+        int w = tileSize.width;
+        int h = tileSize.height;
+        int xx;
+        int yy;
+
+        if ( hexEdgesToTheLeft ) {
+            xx = x * getThreeQuarterHex();
+            yy = y * h;
+        } else {
+            xx = x * w;
+            yy = y * getThreeQuarterHex();
         }
-        return new Point((int)(xx * zoom), (int)(yy * zoom));
+
+        if ( showGrid ) {
+            xx += x + 1;
+            yy += y + 1;
+        }
+
+        if ((Math.abs(x % 2) == 1 && mapAlignment == ALIGN_TOP)
+            || (x % 2 == 0 && mapAlignment == ALIGN_BOTTOM)) {
+            yy += (int)(h / 2.0 + 0.49);
+        }
+        if ((Math.abs(y % 2) == 1 && mapAlignment == ALIGN_LEFT)
+            || (y % 2 == 0 && mapAlignment == ALIGN_RIGHT)) {
+            xx += (int)(w / 2.0 + 0.49);
+        }
+
+        //TiledLogger.getLogger().info(
+        //    "  -> screen coords " + xx + "," + yy + " zoom " + zoom);
+
+        return new Point(xx, yy);
     }
+
+    /**
+     * Returns the location (center) on screen for the given tile.
+     * Works also for hypothetical tiles off the map.
+     * The zoom is accounted for.
+     *
+     * @param x The x coordinate of the tile.
+     * @param y The y coordinate of the tile.
+     *
+     * @return The point at the centre of the Hex as Point.
+     */
+    public Point tileToScreenCoords(double x, double y) {
+        Point p = getTopLeftCornerOfTile((int)x, (int)y);
+        Dimension tileSize = getEffectiveTileSize();
+        return new Point(
+            (int)(p.getX()) + (int)(tileSize.width / 2 + 0.49),
+            (int)(p.getY()) + (int)(tileSize.height / 2 + 0.49));
+    }
+
+    public Point screenToPixelCoords(int x, int y) {
+        // TODO: add proper implementation
+        return new Point();
+    }
+
+    protected void paintPropertyFlags(Graphics2D g2d, TileLayer layer) {
+        throw new RuntimeException("Not yet implemented");    // todo
+    }
+
+    protected void paintObjectGroup(Graphics2D g2d, ObjectGroup og) {
+        // TODO: Implement objectgroup painting for HexMapView
+    }
 }




More information about the tiled-commit mailing list