View Javadoc

    1   /*
    2    * @(#) GridPanel.java Oct 29, 2003
    3    *
    4    * Copyright (c) 2002-2005 Delft University of Technology Jaffalaan 5, 2628 BX
    5    * Delft, the Netherlands. All rights reserved.
    6    *
    7    * This software is proprietary information of Delft University of Technology
    8    * The code is published under the Lesser General Public License
    9    */
    10  package nl.tudelft.simulation.dsol.gui.animation2D;
    11
    12  import java.awt.Color;
    13  import java.awt.Dimension;
    14  import java.awt.Graphics;
    15  import java.awt.geom.Point2D;
    16  import java.awt.geom.Rectangle2D;
    17  import java.awt.geom.RectangularShape;
    18  import java.text.NumberFormat;
    19
    20  import javax.swing.JPanel;
    21
    22  import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
    23
    24  /***
    25   * The GridPanel introduces the gridPanel <br>
    26   * (c) copyright 2002-2005 <a href="http://www.simulation.tudelft.nl">Delft
    27   * University of Technology </a>, the Netherlands. <br>
    28   * See for project information <a
    29   * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
    30   * License of use: <a href="http://www.gnu.org/copyleft/lesser.html">Lesser
    31   * General Public License (LGPL) </a>, no warranty.
    32   *
    33   * @version $Revision$ $Date$
    34   * @author <a href="mailto:nlang@fbk.eur.nl">Niels Lang </a>, <a
    35   *         href="http://www.tbm.tudelft.nl/webstaf/peterja">Peter Jacobs </a>
    36   */
    37  public class GridPanel extends JPanel
    38  {
    39  	/*** the UP directions for moving/zooming */
    40  	public static final int UP = 1;
    41
    42  	/*** the DOWN directions for moving/zooming */
    43  	public static final int DOWN = 2;
    44
    45  	/*** the LEFT directions for moving/zooming */
    46  	public static final int LEFT = 3;
    47
    48  	/*** the RIGHT directions for moving/zooming */
    49  	public static final int RIGHT = 4;
    50
    51  	/*** the ZOOM_IN directions for moving/zooming */
    52  	public static final int IN = 5;
    53
    54  	/*** the ZOOM_OUT directions for moving/zooming */
    55  	public static final int OUT = 6;
    56
    57  	/*** gridColor */
    58  	protected static final Color GRIDCOLOR = Color.BLACK;
    59
    60  	/*** the extent of this panel */
    61  	protected Rectangle2D extent = null;
    62
    63  	/*** the extent of this panel */
    64  	protected Rectangle2D homeExtent = null;
    65
    66  	/*** show the grid */
    67  	protected boolean showGrid = true;
    68
    69  	/*** the gridSize in world Units */
    70  	protected double gridSize = 100.0;
    71
    72  	/*** the formatter to use */
    73  	protected NumberFormat formatter = NumberFormat.getInstance();
    74
    75  	/*** the last computed Dimension */
    76  	protected Dimension lastDimension = null;
    77
    78  	/***
    79  	 * constructs a new GridPanel
    80  	 *
    81  	 * @param extent the extent to show.
    82  	 */
    83  	public GridPanel(final Rectangle2D extent)
    84  	{
    85  		this(extent, new Dimension(600, 600));
    86  	}
    87
    88
    89  	/***
    90  	 * constructs a new GridPanel
    91  	 *
    92  	 * @param extent the initial extent
    93  	 * @param size the size of the panel in pixels.
    94  	 */
    95  	public GridPanel(final Rectangle2D extent, final Dimension size)
    96  	{
    97  		super(true);
    98  		this.extent = extent;
    99  		this.homeExtent = (Rectangle2D) extent.clone();
    100 		this.setBackground(Color.WHITE);
    101 		this.setPreferredSize(size);
    102 		this.lastDimension = this.getSize();
    103 	}
    104
    105 	/***
    106 	 * returns the extent of this panel
    107 	 *
    108 	 * @return Rectangle2D
    109 	 */
    110 	public Rectangle2D getExtent()
    111 	{
    112 		return this.extent;
    113 	}
    114
    115 	/***
    116 	 * @see javax.swing.JComponent #paintComponent(java.awt.Graphics)
    117 	 */
    118 	public synchronized void paintComponent(final Graphics g)
    119 	{
    120 		super.paintComponent(g);
    121 		if (!this.getSize().equals(this.lastDimension))
    122 		{
    123 			this.lastDimension = this.getSize();
    124 			this.extent = Renderable2DInterface.Util.computeVisibleExtent(
    125 					this.extent, this.getSize());
    126 		}
    127 		if (this.showGrid)
    128 		{
    129 			this.drawGrid(g);
    130 		}
    131 	}
    132
    133 	/***
    134 	 * show the grid?
    135 	 *
    136 	 * @param bool true/false
    137 	 */
    138 	public synchronized void showGrid(final boolean bool)
    139 	{
    140 		this.showGrid = bool;
    141 		this.repaint();
    142 	}
    143
    144 	/***
    145 	 * pans the panel in a specified direction
    146 	 *
    147 	 * @param direction the direction
    148 	 * @param percentage the percentage
    149 	 */
    150 	public synchronized void pan(final int direction, final double percentage)
    151 	{
    152 		if (percentage <= 0 || percentage > 1.0)
    153 		{
    154 			throw new IllegalArgumentException("percentage<=0 || >1.0");
    155 		}
    156 		switch (direction)
    157 		{
    158 			case LEFT :
    159 				this.extent.setRect(this.extent.getMinX() - percentage
    160 						* this.extent.getWidth(), this.extent.getMinY(),
    161 						this.extent.getWidth(), this.extent.getHeight());
    162 				break;
    163 			case RIGHT :
    164 				this.extent.setRect(this.extent.getMinX() + percentage
    165 						* this.extent.getWidth(), this.extent.getMinY(),
    166 						this.extent.getWidth(), this.extent.getHeight());
    167 				break;
    168 			case UP :
    169 				this.extent.setRect(this.extent.getMinX(), this.extent
    170 						.getMinY()
    171 						+ percentage * this.extent.getHeight(), this.extent
    172 						.getWidth(), this.extent.getHeight());
    173 				break;
    174 			case DOWN :
    175 				this.extent.setRect(this.extent.getMinX(), this.extent
    176 						.getMinY()
    177 						- percentage * this.extent.getHeight(), this.extent
    178 						.getWidth(), this.extent.getHeight());
    179 				break;
    180 			default :
    181 				throw new IllegalArgumentException("direction unkonw");
    182 		}
    183 		this.repaint();
    184 	}
    185
    186 	/***
    187 	 * resets the panel to its original extent
    188 	 */
    189 	public synchronized void home()
    190 	{
    191 		this.extent = Renderable2DInterface.Util.computeVisibleExtent(
    192 				this.homeExtent, this.getSize());
    193 		this.repaint();
    194 	}
    195
    196 	/***
    197 	 * @return Returns the showGrid.
    198 	 */
    199 	public boolean isShowGrid()
    200 	{
    201 		return this.showGrid;
    202 	}
    203
    204 	/***
    205 	 * @param showGrid The showGrid to set.
    206 	 */
    207 	public void setShowGrid(final boolean showGrid)
    208 	{
    209 		this.showGrid = showGrid;
    210 	}
    211
    212 	/***
    213 	 * zooms in/out
    214 	 *
    215 	 * @param direction the zoom direction
    216 	 * @param factor The Factor
    217 	 */
    218 	public synchronized void zoom(final int direction, final double factor)
    219 	{
    220 		double newScale = Renderable2DInterface.Util.getScale(this.extent, this
    221 				.getSize());
    222 		switch (direction)
    223 		{
    224 			case IN :
    225 				newScale = newScale * factor;
    226 				break;
    227 			case OUT :
    228 				newScale = newScale / factor;
    229 				break;
    230 			default :
    231 				throw new IllegalArgumentException("zoom direction unknown");
    232 		}
    233 		this.extent.setRect(this.extent.getCenterX() - 0.5 * newScale
    234 				* this.getWidth(), this.extent.getCenterY() - 0.5 * newScale
    235 				* this.getHeight(), newScale * this.getWidth(), newScale
    236 				* this.getHeight());
    237 		this.repaint();
    238 	}
    239
    240 	// ------------------------ PRIVATE METHODS ---------------------------/
    241 	/***
    242 	 * Added to make sure the recursive render-call calls THIS render method
    243 	 * instead of a potential super-class defined 'paintComponent' render
    244 	 * method.
    245 	 *
    246 	 * @param g the graphics object
    247 	 */
    248 	protected synchronized void drawGrid(final Graphics g)
    249 	{
    250 		// we prepare the graphics object for the grid
    251 		g.setFont(g.getFont().deriveFont(11.0f));
    252 		g.setColor(GRIDCOLOR);
    253 		double scale = Renderable2DInterface.Util.getScale(this.extent, this
    254 				.getSize());
    255
    256 		int gridSizePixels = (int) Math.round(this.gridSize / scale);
    257 		if (gridSizePixels < 40)
    258 		{
    259 			this.gridSize = 10 * this.gridSize;
    260 			int maximumNumberOfDigits = (int) Math.max(0, 1 + Math.ceil(Math
    261 					.log(1 / this.gridSize)
    262 					/ Math.log(10)));
    263 			this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
    264 			this.drawGrid(g);
    265 			return;
    266 		}
    267 		if (gridSizePixels > 10 * 40)
    268 		{
    269 			int maximumNumberOfDigits = (int) Math.max(0, 2 + Math.ceil(Math
    270 					.log(1 / this.gridSize)
    271 					/ Math.log(10)));
    272 			this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
    273 			this.gridSize = this.gridSize / 10;
    274 			this.drawGrid(g);
    275 			return;
    276 		}
    277 		// Let's draw the vertical lines
    278 		double mod = this.extent.getMinX() % this.gridSize;
    279 		int x = (int) -Math.round(mod / scale);
    280 		while (x < this.getWidth())
    281 		{
    282 			Point2D point = Renderable2DInterface.Util.getWorldCoordinates(
    283 					new Point2D.Double(x, 0), this.extent, this.getSize());
    284 			if (point != null)
    285 			{
    286 				String label = this.formatter.format(Math.round(point.getX()
    287 						/ this.gridSize)
    288 						* this.gridSize);
    289 				double labelWidth = this.getFontMetrics(this.getFont())
    290 						.getStringBounds(label, g).getWidth();
    291 				if (x > labelWidth + 4)
    292 				{
    293 					g.drawLine(x, 15, x, this.getHeight());
    294 					g.drawString(label, (int) Math.round(x - 0.5 * labelWidth),
    295 							11);
    296 				}
    297 			}
    298 			x = x + gridSizePixels;
    299 		}
    300 		// Let's draw the horizontal lines
    301 		mod = Math.abs(this.extent.getMinY()) % this.gridSize;
    302 		int y = (int) Math.round(this.getSize().getHeight() - (mod / scale));
    303 		while (y > 15)
    304 		{
    305 			Point2D point = Renderable2DInterface.Util.getWorldCoordinates(
    306 					new Point2D.Double(0, y), this.extent, this.getSize());
    307 			if (point != null)
    308 			{
    309 				String label = this.formatter.format(Math.round(point.getY()
    310 						/ this.gridSize)
    311 						* this.gridSize);
    312 				RectangularShape labelBounds = this.getFontMetrics(
    313 						this.getFont()).getStringBounds(label, g);
    314 				g.drawLine((int) Math.round(labelBounds.getWidth() + 4), y,
    315 						this.getWidth(), y);
    316 				g.drawString(label, 2, (int) Math.round(y
    317 						+ labelBounds.getHeight() * 0.3));
    318 			}
    319 			y = y - gridSizePixels;
    320 		}
    321 	}
    322 }