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 }