1 package org.opentrafficsim.editor.extensions.map;
2
3 import java.awt.Color;
4 import java.awt.Graphics;
5 import java.awt.geom.Point2D;
6 import java.awt.geom.RectangularShape;
7 import java.rmi.RemoteException;
8 import java.util.List;
9
10 import javax.naming.NamingException;
11
12 import org.djutils.draw.bounds.Bounds2d;
13 import org.djutils.draw.point.Point2d;
14 import org.djutils.event.EventProducer;
15 import org.djutils.event.EventType;
16 import org.djutils.metadata.MetaData;
17
18 import nl.tudelft.simulation.dsol.animation.Locatable;
19 import nl.tudelft.simulation.dsol.swing.animation.d2.VisualizationPanel;
20 import nl.tudelft.simulation.naming.context.ContextInterface;
21
22
23
24
25
26
27
28
29
30 public class MapVisualizationPanel extends VisualizationPanel
31 {
32
33
34 private static final long serialVersionUID = 20260212L;
35
36
37 public static final EventType EXTENT_CHANGED = new EventType(new MetaData("EXTENT_CHANGED", "EXTENT_CHANGED"));
38
39
40
41
42
43
44
45
46
47 public MapVisualizationPanel(final Bounds2d homeExtent, final EventProducer producer, final ContextInterface context)
48 throws RemoteException, NamingException
49 {
50 super(homeExtent, producer, context);
51 }
52
53 @Override
54 public void setBackground(final Color bg)
55 {
56 int threshold = 64;
57 int alternative = 96;
58 if (bg.getRed() <= threshold && bg.getGreen() <= threshold && bg.getBlue() <= threshold)
59 {
60 setGridColor(new Color(alternative, alternative, alternative));
61 }
62 else
63 {
64 setGridColor(Color.BLACK);
65 }
66 super.setBackground(bg);
67 }
68
69
70
71 @Override
72 protected synchronized void drawGrid(final Graphics g)
73 {
74
75 g.setFont(g.getFont().deriveFont(11.0f));
76 g.setColor(this.getGridColor());
77 double scaleX = this.getRenderableScale().getXScale(this.getExtent(), this.getSize());
78 double scaleY = this.getRenderableScale().getYScale(this.getExtent(), this.getSize());
79
80 int count = 0;
81 double gridSizePixelsX = this.gridSizeX / scaleX;
82 while (gridSizePixelsX < 40)
83 {
84 this.gridSizeX = 10 * this.gridSizeX;
85 int maximumNumberOfDigits = (int) Math.max(0, 1 + Math.ceil(Math.log(1 / this.gridSizeX) / Math.log(10)));
86 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
87 gridSizePixelsX = (int) Math.round(this.gridSizeX / scaleX);
88 if (count++ > 10)
89 {
90 break;
91 }
92 }
93
94 count = 0;
95 while (gridSizePixelsX > 10 * 40)
96 {
97 int maximumNumberOfDigits = (int) Math.max(0, 2 + Math.ceil(Math.log(1 / this.gridSizeX) / Math.log(10)));
98 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
99 this.gridSizeX = this.gridSizeX / 10;
100 gridSizePixelsX = (int) Math.round(this.gridSizeX / scaleX);
101 if (count++ > 10)
102 {
103 break;
104 }
105 }
106
107 double gridSizePixelsY = this.gridSizeY / scaleY;
108 while (gridSizePixelsY < 40)
109 {
110 this.gridSizeY = 10 * this.gridSizeY;
111 int maximumNumberOfDigits = (int) Math.max(0, 1 + Math.ceil(Math.log(1 / this.gridSizeY) / Math.log(10)));
112 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
113 gridSizePixelsY = (int) Math.round(this.gridSizeY / scaleY);
114 if (count++ > 10)
115 {
116 break;
117 }
118 }
119
120 count = 0;
121 while (gridSizePixelsY > 10 * 40)
122 {
123 int maximumNumberOfDigits = (int) Math.max(0, 2 + Math.ceil(Math.log(1 / this.gridSizeY) / Math.log(10)));
124 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
125 this.gridSizeY = this.gridSizeY / 10;
126 gridSizePixelsY = (int) Math.round(this.gridSizeY / scaleY);
127 if (count++ > 10)
128 {
129 break;
130 }
131 }
132
133
134 double mod = this.getExtent().getMinX() % this.gridSizeX;
135 double x = -mod / scaleX;
136 while (x < this.getWidth())
137 {
138 Point2d point =
139 this.getRenderableScale().getWorldCoordinates(new Point2D.Double(x, 0), this.getExtent(), this.getSize());
140 if (point != null)
141 {
142 String label = this.formatter.format(Math.round(point.getX() / this.gridSizeX) * this.gridSizeX);
143 double labelWidth = this.getFontMetrics(this.getFont()).getStringBounds(label, g).getWidth();
144 if (x > labelWidth + 4)
145 {
146 int xInt = (int) Math.round(x);
147 g.drawLine(xInt, 15, xInt, this.getHeight());
148 g.drawString(label, (int) Math.round(x - 0.5 * labelWidth), 11);
149 }
150 }
151 x = x + gridSizePixelsX;
152 }
153
154
155 mod = this.getExtent().getMinY() % this.gridSizeY;
156 double y = this.getSize().getHeight() + (mod / scaleY);
157 while (y > 15)
158 {
159 Point2d point =
160 this.getRenderableScale().getWorldCoordinates(new Point2D.Double(0, y), this.getExtent(), this.getSize());
161 if (point != null)
162 {
163 String label = this.formatter.format(Math.round(point.getY() / this.gridSizeY) * this.gridSizeY);
164 RectangularShape labelBounds = this.getFontMetrics(this.getFont()).getStringBounds(label, g);
165 int yInt = (int) Math.round(y);
166 g.drawLine((int) Math.round(labelBounds.getWidth() + 4), yInt, this.getWidth(), yInt);
167 g.drawString(label, 2, (int) Math.round(y + labelBounds.getHeight() * 0.3));
168 }
169 y = y - gridSizePixelsY;
170 }
171 }
172
173
174
175
176
177
178
179 public double pxScale()
180 {
181 double x = getRenderableScale().getXScale(getExtent(), getSize());
182 double y = x / getRenderableScale().getYScaleRatio();
183 return Math.min(x, y);
184 }
185
186
187
188 @Override
189 public void setExtent(final Bounds2d extent)
190 {
191 super.setExtent(extent);
192 fireEvent(EXTENT_CHANGED);
193 }
194
195
196
197 @Override
198 public void pan(final Point2D mouseClickedPoint, final Point2D mouseReleasedPoint)
199 {
200 super.pan(mouseClickedPoint, mouseReleasedPoint);
201 }
202
203 @Override
204 public List<Locatable> getSelectedObjects(final Point2D mousePoint)
205 {
206 return super.getSelectedObjects(mousePoint);
207 }
208
209 @Override
210 public Object getSelectedObject(final List<Locatable> targets)
211 {
212 return super.getSelectedObject(targets);
213 }
214
215 }