1
2
3
4
5
6
7
8
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
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
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
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
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 }