View Javadoc

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