Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

Hexagon demo

/*  * @(#)Hexagon.java  1.0 Apr 27, 2008  *  *  The MIT License  *  *  Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>  *  *  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 org.eoti.awt.geom; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RectangularShape; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.io.File; import java.io.IOException; import java.util.HashMap; import javax.imageio.ImageIO; public class Hexagon extends Polygon {   public enum Corner   {     Top, UpperRight, LowerRight, Bottom, LowerLeft, UpperLeft   }   public enum Direction   {     NorthEast, East, SouthEast, SouthWest, West, NorthWest   }   public enum BoundingCorner   {     TopLeft, TopRight, BottomLeft, BottomRight   }   protected Point2D center;   protected int size;   protected double height, width;   protected double hOffset, wOffset;   protected Rectangle2D boundingBox;   protected HashMap<Corner,Point2D> corners;   protected HashMap<BoundingCorner,Point2D> boundingCorners;   public Hexagon(double centerX, double centerY, int size)   {     this(new Point2D.Double(centerX,centerY), size);   }   public Hexagon(Point2D center, int size)   {     super();     this.center = center;     this.size = size;     /**        * MATH:        *  With the hexagon points={TOP, UPPER-RIGHT, LOWER-RIGHT, BOTTOM, LOWER-LEFT, UPPER-RIGHT}        *  size = length of each actual segment of the hexagon        *  width = bounding rectangle width        *  height = bounding rectangle height        *  each inner angle is 120 degrees        *  outside angles are 30-60-90 triangles with 30 near TOP and BOTTOM and 60 near sides        *  hOffset = height difference between 'size' edge and bounding rectangle corners        *  wOffset = width difference between TOP/BOTTOM points and bounding rectangle corners        */     double thirtyDegrees = Math.toRadians(30);     hOffset = Math.sin(thirtyDegrees) * size;     wOffset = Math.cos(thirtyDegrees) * size;     height = (2 * hOffset) + size;     width = (2 * wOffset);     double left = center.getX() - (width/2);     double right = center.getX() + (width/2);     double top = center.getY() - (height/2);     double bottom = center.getY() + (height/2);     boundingBox = new Rectangle2D.Double(left, top, width, height);     boundingCorners = new HashMap<BoundingCorner, Point2D>();     boundingCorners.put(BoundingCorner.TopRight, new Point2D.Double(right, top));     boundingCorners.put(BoundingCorner.TopLeft, new Point2D.Double(left, top));     boundingCorners.put(BoundingCorner.BottomRight, new Point2D.Double(right, bottom));     boundingCorners.put(BoundingCorner.BottomLeft, new Point2D.Double(left, bottom));     corners = new HashMap<Corner,Point2D>();     corners.put(Corner.Top, new Point2D.Double(center.getX(), top));     corners.put(Corner.UpperRight, new Point2D.Double(right, (top + hOffset)));     corners.put(Corner.LowerRight, new Point2D.Double(right, (bottom - hOffset)));     corners.put(Corner.Bottom, new Point2D.Double(center.getX(), bottom));     corners.put(Corner.LowerLeft, new Point2D.Double(left, (bottom - hOffset)));     corners.put(Corner.UpperLeft, new Point2D.Double(left, (top + hOffset)));     for(Corner corner : Corner.values())     {       Point2D p2d = corners.get(corner);       addPoint((int)p2d.getX(), (int)p2d.getY());     }   }   @Override   public String toString()   {     StringBuilder sb = new StringBuilder();     sb.append("[Hexagon: ");     sb.append(String.format(         "[Size: %d]",         size       ));     sb.append(String.format(         "[Height: %2.1f, hOffset: %2.1f]",         height, hOffset       ));     sb.append(String.format(         "[Width: %2.1f, wOffset: %2.1f]",         width, wOffset       ));     sb.append(String.format(         "[Center: %2.1fx%2.1f]",         center.getX(), center.getY()       ));     sb.append("[Corners: ");     for(Corner corner : Corner.values())     {       Point2D p2d = corners.get(corner);       sb.append(String.format(           "[%s: %2.1fx%2.1f]",           corner, p2d.getX(), p2d.getY()         ));     }     sb.append("]");     sb.append("[Bounds: ");     for(BoundingCorner corner : BoundingCorner.values())     {       Point2D p2d = boundingCorners.get(corner);       sb.append(String.format(           "[%s: %2.1fx%2.1f]",           corner, p2d.getX(), p2d.getY()         ));     }     sb.append("]");     sb.append(String.format(         "[BoundingBox: %2.1fx%2.1f to %2.1fx%2.1f]",         boundingBox.getMinX(),         boundingBox.getMinY(),         boundingBox.getMaxX(),         boundingBox.getMaxY()       ));     sb.append("]");     return sb.toString();   }   public Point2D getCenter(){return center;}   public int getSize(){return size;}   public double getHeight(){return height;}   public double getWidth(){return width;}   @Override   public Rectangle2D getBounds2D(){return boundingBox;}   public double getHeightOffset(){return hOffset;}   public double getWidthOffset(){return wOffset;}   //public HashMap<Corner,Point2D> getCorners(){return corners;}   //public HashMap<BoundingCorner,Point2D> getBoundingCorners(){return boundingCorners;}   public Hexagon resize(int newSize)   {     return new Hexagon(center, newSize);   }      @Override   public Object clone()   {     return new Hexagon(center, size);   }   public Point2D getHexPoint(Corner corner)   {     return corners.get(corner);   }   public Point2D getBoundPoint(BoundingCorner corner)   {     return boundingCorners.get(corner);   }   public void translate(double deltaX, double deltaY)   {     translate((int)deltaX, (int)deltaY);   }   @Override   public void translate(int deltaX, int deltaY)   {     super.translate(deltaX, deltaY);     boundingBox = super.getBounds2D();     double top = boundingBox.getMinY();     double left = boundingBox.getMinX();     double bottom = boundingBox.getMaxY();     double right = boundingBox.getMaxX();     double centerX = boundingBox.getCenterX();     double centerY = boundingBox.getCenterY();     center = new Point2D.Double(centerX, centerY);     boundingCorners.put(BoundingCorner.TopRight, new Point2D.Double(right, top));     boundingCorners.put(BoundingCorner.TopLeft, new Point2D.Double(left, top));     boundingCorners.put(BoundingCorner.BottomRight, new Point2D.Double(right, bottom));     boundingCorners.put(BoundingCorner.BottomLeft, new Point2D.Double(left, bottom));     corners.put(Corner.Top, new Point2D.Double(center.getX(), top));     corners.put(Corner.UpperRight, new Point2D.Double(right, (top + hOffset)));     corners.put(Corner.LowerRight, new Point2D.Double(right, (bottom - hOffset)));     corners.put(Corner.Bottom, new Point2D.Double(center.getX(), bottom));     corners.put(Corner.LowerLeft, new Point2D.Double(left, (bottom - hOffset)));     corners.put(Corner.UpperLeft, new Point2D.Double(left, (top + hOffset)));   }   public void align(Rectangle2D bounds, Direction direction)   {     // these are defined here INSTEAD of in the switch, or it won't compile     Point2D newTopRight, newTopLeft, newBottomRight, newBottomLeft;     Point2D oldTopRight, oldTopLeft, oldBottomRight, oldBottomLeft;     switch(direction)     {       case NorthEast:         newTopRight = new Point2D.Double(bounds.getMaxX(), bounds.getMinY());         oldTopRight = boundingCorners.get(BoundingCorner.TopRight);         translate(           newTopRight.getX() - oldTopRight.getX(),      // deltaX           newTopRight.getY() - oldTopRight.getY()        // deltaY         );         break;       case East:         newTopRight = new Point2D.Double(bounds.getMaxX(), bounds.getMinY());         oldTopRight = boundingCorners.get(BoundingCorner.TopRight);         translate(           newTopRight.getX() - oldTopRight.getX(),      // deltaX           0                          // deltaY         );         break;       case SouthEast:         newBottomRight = new Point2D.Double(bounds.getMaxX(), bounds.getMaxY());         oldBottomRight = boundingCorners.get(BoundingCorner.BottomRight);         translate(           newBottomRight.getX() - oldBottomRight.getX(),    // deltaX           newBottomRight.getY() - oldBottomRight.getY()    // deltaY         );         break;       case SouthWest:         newBottomLeft = new Point2D.Double(bounds.getMinX(), bounds.getMaxY());         oldBottomLeft = boundingCorners.get(BoundingCorner.BottomLeft);         translate(           newBottomLeft.getX() - oldBottomLeft.getX(),    // deltaX           newBottomLeft.getY() - oldBottomLeft.getY()      // deltaY         );         break;       case West:         newTopLeft = new Point2D.Double(bounds.getMinX(), bounds.getMinY());         oldTopLeft = boundingCorners.get(BoundingCorner.TopLeft);         translate(           newTopLeft.getX() - oldTopLeft.getX(),        // deltaX           0                          // deltaY         );         break;       case NorthWest:         newTopLeft = new Point2D.Double(bounds.getMinX(), bounds.getMinY());         oldTopLeft = boundingCorners.get(BoundingCorner.TopLeft);         translate(           newTopLeft.getX() - oldTopLeft.getX(),        // deltaX           newTopLeft.getY() - oldTopLeft.getY()        // deltaY         );         break;     }   }   public void attach(Hexagon toTranslate, Direction direction)   {     double horSize = size + hOffset;     /**        * To start with, we need to know toTranslate's position RELATIVE to ours        */       Point2D topLeft = getBoundPoint(BoundingCorner.TopLeft);     Point2D toTranslateTopLeft = toTranslate.getBoundPoint(BoundingCorner.TopLeft);       double deltaX = topLeft.getX() - toTranslateTopLeft.getX();       double deltaY = topLeft.getY() - toTranslateTopLeft.getY();       // that should be enough to line them up exactly... now offset it...     switch(direction)     {       case NorthEast:         deltaX += wOffset;         deltaY -= horSize;         break;       case East:         deltaX += width;         break;       case SouthEast:         deltaX += wOffset;         deltaY += horSize;         break;       case SouthWest:         deltaX -= wOffset;         deltaY += horSize;         break;       case West:         deltaX -= width;         break;       case NorthWest:         deltaX -= wOffset;         deltaY -= horSize;         break;     }     toTranslate.translate(deltaX, deltaY);   }   public static class CreateTile   {     public static void main(String[] args)     {       if(args.length != 2)       {         System.out.println("USAGE: java org.eoti.awt.geom.Hexagon$CreateTile size filename");         System.out.print("Output file can be: ");         for(String name : ImageIO.getWriterFormatNames())           System.out.print(name + ",");         System.out.println();         System.exit(0);       }       try{         int size = Integer.parseInt(args[0]);           Hexagon hex = new Hexagon(0, 0, size);           Rectangle2D newBounds = new Rectangle2D.Double(0, 0, hex.getWidth(), hex.getHeight());           hex.align(newBounds, Direction.NorthWest);           File file = GraphicsUtil.write(args[1], hex);           if(file == null)             System.out.println("Error creating file");           else             System.out.println("Hexagon tile created: " + file.getAbsolutePath());         }catch(Exception e){           System.out.format("Exception: %s", e.getMessage());           e.printStackTrace();         }     }   } } class GraphicsUtil {   protected Graphics g;   protected ImageObserver observer;   public GraphicsUtil(Graphics g, ImageObserver observer)   {     this.g = g;     this.observer = observer;   }   public enum Align   {     North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest, Center   }   public BufferedImage drawCodePoint(char codePoint, int width, int height)   {     return drawCodePoint(codePoint, width, height, g.getFont(), g.getColor());   }   public static BufferedImage drawCodePoint(char codePoint, int width, int height, Font font, Color color)   {     BufferedImage img = createImage(width, height);     Graphics2D g2 = img.createGraphics();     String text = "" + codePoint;     g2.setColor(color);     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);     GlyphVector gv = font.createGlyphVector(g2.getFontRenderContext(), text);     g2.drawGlyphVector(gv, 0f, (float)gv.getGlyphMetrics(0).getBounds2D().getHeight());     return img;   }   public static BufferedImage createImage(Dimension size)   {     return createImage(size.width, size.height);   }   public static BufferedImage createImage(int width, int height)   {     return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);   }   public void drawImage(BufferedImage img)   {     drawImage(g, img, observer);   }   public static void drawImage(Graphics g, BufferedImage img)   {     drawImage(g, img, (ImageObserver)null);   }   public static void drawImage(Graphics g, BufferedImage img, ImageObserver observer)   {     Graphics2D g2 = (Graphics2D)g;     g2.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), observer);   }   public void drawImage(BufferedImage img, Rectangle2D bounds)   {     drawImage(g, img, bounds, observer);   }   public static void drawImage(Graphics g, BufferedImage img, Rectangle2D bounds)   {     drawImage(g, img, bounds, null);   }   public static void drawImage(Graphics g, BufferedImage img, Rectangle2D bounds, ImageObserver observer)   {     Graphics2D g2 = (Graphics2D)g;     g2.drawImage(       img,            // what to draw       (int)bounds.getMinX(),    // dest left       (int)bounds.getMinY(),    // dest top       (int)bounds.getMaxX(),    // dest right       (int)bounds.getMaxY(),    // dest bottom       0,              // src left       0,              // src top       img.getWidth(),        // src right       img.getHeight(),      // src bottom       observer          // to notify of image updates     );   }   public static Rectangle2D contract(RectangularShape rect, double amount)   {     return contract(rect, amount, amount);   }   public static Rectangle2D contract(RectangularShape rect, double amountX, double amountY)   {     return new Rectangle2D.Double(       rect.getX() + amountX,       rect.getY() + amountY,       rect.getWidth() - (2*amountX),       rect.getHeight() - (2*amountY)     );   }   public static Rectangle2D expand(RectangularShape rect, double amount)   {     return expand(rect, amount, amount);   }   public static Rectangle2D expand(RectangularShape rect, double amountX, double amountY)   {     return new Rectangle2D.Double(       rect.getX() - amountX,       rect.getY() - amountY,       rect.getWidth() + (2*amountX),       rect.getHeight() + (2*amountY)     );   }   public static Point2D getPoint(RectangularShape bounds, Align align)   {     double x = 0.0;     double y = 0.0;     switch(align)     {       case North:         x = bounds.getCenterX();         y = bounds.getMinY();         break;       case NorthEast:         x = bounds.getMaxX();         y = bounds.getMinY();         break;       case East:         x = bounds.getMaxX();         y = bounds.getCenterY();         break;       case SouthEast:         x = bounds.getMaxX();         y = bounds.getMaxY();         break;       case South:         x = bounds.getCenterX();         y = bounds.getMaxY();         break;       case SouthWest:         x = bounds.getMinX();         y = bounds.getMaxY();         break;       case West:         x = bounds.getMinX();         y = bounds.getCenterY();         break;       case NorthWest:         x = bounds.getMinX();         y = bounds.getMinY();         break;       case Center:         x = bounds.getCenterX();         y = bounds.getCenterY();         break;     }     return new Point2D.Double(x,y);   }   public void drawString(String text, RectangularShape bounds, Align align)   {     drawString(g, text, bounds, align, 0.0);   }   public void drawString(String text, RectangularShape bounds, Align align, double angle)   {     drawString(g, text, bounds, align, angle);   }   public static void drawString(Graphics g, String text, RectangularShape bounds, Align align)   {     drawString(g, text, bounds, align, 0.0);   }   public static void drawString(Graphics g, String text, RectangularShape bounds, Align align, double angle)   {     Graphics2D g2 = (Graphics2D)g;     Font font = g2.getFont();     if(angle != 0)       g2.setFont(font.deriveFont(AffineTransform.getRotateInstance(Math.toRadians(angle))));     Rectangle2D sSize = g2.getFontMetrics().getStringBounds(text, g2);     Point2D pos = getPoint(bounds, align);     double x = pos.getX();     double y = pos.getY() + sSize.getHeight();     switch(align)     {       case North:       case South:       case Center:         x -= (sSize.getWidth() / 2);         break;       case NorthEast:       case East:       case SouthEast:         x -= (sSize.getWidth());         break;       case SouthWest:       case West:       case NorthWest:         break;     }     g2.drawString(text, (float)x, (float)y);     g2.setFont(font);   } /*   public static void drawGrid(Graphics g, Rectangle2D bounds, int cols, int rows)   {     Graphics2D g2 = (Graphics2D)g;     double minx = bounds.getMinX();     double miny = bounds.getMinY();     double maxx = bounds.getMaxX();     double maxy = bounds.getMaxY();     double width = bounds.getWidth();     double height = bounds.getHeight();     double xInterval = width / cols;     double yInterval = height / rows;     for(int col=1; col<=cols; col++)     {       for(int row=1; row<=rows; row++)       {         Point2D pos = new Point2D.Double(minx + (xInterval * col), miny + (yInterval * row));         g2.setColor(Color.black);         g2.drawLine(           (int)pos.getX(),           (int)miny,           (int)pos.getX(),           (int)maxy         );         g2.drawLine(           (int)minx,           (int)pos.getY(),           (int)maxx,           (int)pos.getY()         );         Point2D ctr = new Point2D.Double(           minx + (xInterval * col) - (xInterval/2),           miny + (yInterval * row) - (yInterval/2)         );         g2.setColor(Color.green);         g2.drawLine(           (int)ctr.getX(),           (int)miny,           (int)ctr.getX(),           (int)maxy         );         g2.drawLine(           (int)minx,           (int)ctr.getY(),           (int)maxx,           (int)ctr.getY()         );       }     }     g2.setColor(Color.black);     g2.drawRect((int)minx, (int)miny, (int)width, (int)height);   } */   public void drawImage(BufferedImage img, Align align)   {     drawImage(g, img, align, img.getWidth(), img.getHeight(), observer);   }   public void drawImage(BufferedImage img, Align align, double newWidth, double newHeight)   {     drawImage(g, img, align, newWidth, newHeight, observer);   }   public static void drawImage(Graphics g, BufferedImage img, Align align)   {     drawImage(g, img, align, img.getWidth(), img.getHeight(), null);   }   public static void drawImage(Graphics g, BufferedImage img, Align align, double newWidth, double newHeight)   {     drawImage(g, img, align, newWidth, newHeight, null);   }   public static void drawImage(Graphics g, BufferedImage img, Align align, double newWidth, double newHeight, ImageObserver observer)   {     // TBD   }   public void drawCentered(BufferedImage img, Point2D location)   {     drawCentered(g, img, location, img.getWidth(), img.getHeight(), observer);   }   public void drawCentered(BufferedImage img, Point2D location, double newWidth, double newHeight)   {     drawCentered(g, img, location, newWidth, newHeight, observer);   }   public static void drawCentered(Graphics g, BufferedImage img, Point2D location)   {     drawCentered(g, img, location, img.getWidth(), img.getHeight(), null);   }   public static void drawCentered(Graphics g, BufferedImage img, Point2D location, ImageObserver observer)   {     drawCentered(g, img, location, img.getWidth(), img.getHeight(), observer);   }   public static void drawCentered(Graphics g, BufferedImage img, Point2D location, double newWidth, double newHeight)   {     drawCentered(g, img, location, newWidth, newHeight, null);   }   public static void drawCentered(Graphics g, BufferedImage img, Point2D location, double newWidth, double newHeight, ImageObserver observer)   {     Graphics2D g2 = (Graphics2D)g;     g2.drawImage(       img,                  // what to draw       (int)(location.getX() - (newWidth/2)),  // dest left       (int)(location.getY() - (newHeight/2)),  // dest top       (int)(location.getX() + (newWidth/2)),  // dest right       (int)(location.getY() + (newHeight/2)),  // dest bottom       0,                    // src left       0,                    // src top       img.getWidth(),              // src right       img.getHeight(),            // src bottom       observer                // to notify of image updates     );   }   public static File write(String fileName, Shape shape)   throws IOException   {     Rectangle bounds = shape.getBounds();     BufferedImage img = createImage(bounds.width, bounds.height);     Graphics2D g2 = (Graphics2D)img.createGraphics();     //g2.setColor(WebColor.CornSilk.getColor());     g2.fill(shape);     g2.setColor(Color.black);     g2.draw(shape);     return write(fileName, img);   }   public static File write(String fileName, BufferedImage img)   throws IOException   {     File file = new File(fileName);     if(ImageIO.write(img, "PNG",file))       return file;     return null;   }   // add something like write(fileName, ArrayList<ArrayList<BufferedImage>>)   // or write(fileName, BufferedImage ... images)   // to create a tiled image from multiple source images }