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 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
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
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
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
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 }