1 package org.opentrafficsim.trafficcontrol.trafcod;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Graphics;
6 import java.awt.Graphics2D;
7 import java.awt.event.MouseEvent;
8 import java.awt.event.MouseListener;
9 import java.awt.event.MouseMotionListener;
10 import java.awt.geom.Point2D;
11 import java.awt.image.BufferedImage;
12 import java.rmi.RemoteException;
13 import java.util.LinkedHashSet;
14 import java.util.Set;
15
16 import javax.swing.JPanel;
17 import javax.swing.ToolTipManager;
18
19 import org.djutils.event.Event;
20 import org.djutils.event.EventListener;
21 import org.djutils.event.LocalEventProducer;
22 import org.opentrafficsim.road.network.lane.object.detector.TrafficLightDetector;
23 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
24
25
26
27
28
29
30
31
32
33 public class TrafCodDisplay extends JPanel implements MouseMotionListener, MouseListener
34 {
35
36 private static final long serialVersionUID = 20161115L;
37
38
39 private final BufferedImage image;
40
41
42 private Set<TrafCODObject> trafCODObjects = new LinkedHashSet<>();
43
44
45 private final int defaultInitialDelay = ToolTipManager.sharedInstance().getInitialDelay();
46
47
48
49
50
51
52
53 public TrafCodDisplay(final BufferedImage image)
54 {
55 this.image = image;
56 super.setPreferredSize(new Dimension(this.image.getWidth(), this.image.getHeight()));
57 addMouseMotionListener(this);
58 }
59
60
61
62
63
64
65 public DetectorImage getDetectorImage(final String id)
66 {
67 for (TrafCODObject tco : this.trafCODObjects)
68 {
69 if (tco instanceof DetectorImage && ((DetectorImage) tco).getId().equals(id))
70 {
71 return (DetectorImage) tco;
72 }
73 }
74 return null;
75 }
76
77 @Override
78 protected void paintComponent(final Graphics g)
79 {
80 super.paintComponent(g);
81 g.drawImage(this.image, 0, 0, null);
82 for (TrafCODObject tco : this.trafCODObjects)
83 {
84 tco.draw((Graphics2D) g);
85 }
86 }
87
88
89
90
91
92 void addTrafCODObject(final TrafCODObject trafCODObject)
93 {
94 this.trafCODObjects.add(trafCODObject);
95 }
96
97 @Override
98 public void mouseDragged(final MouseEvent e)
99 {
100 mouseMoved(e);
101 }
102
103 @Override
104 public void mouseMoved(final MouseEvent e)
105 {
106 String toolTipText = null;
107 for (TrafCODObject tco : this.trafCODObjects)
108 {
109 toolTipText = tco.toolTipHit(e.getX(), e.getY());
110 if (null != toolTipText)
111 {
112 break;
113 }
114 }
115
116 setToolTipText(toolTipText);
117 }
118
119 @Override
120 public void mouseClicked(final MouseEvent e)
121 {
122
123 }
124
125 @Override
126 public void mousePressed(final MouseEvent e)
127 {
128
129 }
130
131 @Override
132 public void mouseReleased(final MouseEvent e)
133 {
134
135 }
136
137 @Override
138 public void mouseEntered(final MouseEvent e)
139 {
140 ToolTipManager.sharedInstance().setInitialDelay(0);
141 }
142
143 @Override
144 public void mouseExited(final MouseEvent e)
145 {
146 ToolTipManager.sharedInstance().setInitialDelay(this.defaultInitialDelay);
147 }
148
149 }
150
151
152
153
154
155 interface TrafCODObject
156 {
157
158
159
160
161 void draw(Graphics2D g2);
162
163
164
165
166
167
168
169
170 String toolTipHit(int testX, int testY);
171
172 }
173
174
175
176
177 class DetectorImage implements TrafCODObject, EventListener
178 {
179
180 private static final long serialVersionUID = 20200313L;
181
182
183 private final TrafCodDisplay display;
184
185
186 private final int x;
187
188
189 private final int y;
190
191
192 private final String description;
193
194
195 private final String id;
196
197
198 private Color fillColor = Color.WHITE;
199
200
201 private static final int BOX_SIZE = 13;
202
203
204 private static final int X_OFFSET = 5;
205
206
207 private static final int Y_OFFSET = 5;
208
209
210
211
212
213
214
215
216 DetectorImage(final TrafCodDisplay display, final Point2D center, final String id, final String description)
217 {
218 this.display = display;
219 this.x = (int) center.getX();
220 this.y = (int) center.getY();
221 this.id = id;
222 this.description = description;
223 display.addTrafCODObject(this);
224 }
225
226 @Override
227 public void draw(final Graphics2D g2)
228 {
229 g2.setColor(this.fillColor);
230 g2.fillRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
231 g2.setColor(Color.BLACK);
232 g2.drawRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
233 }
234
235 @Override
236 public void notify(final Event event) throws RemoteException
237 {
238 if (event.getType().equals(TrafficLightDetector.TRAFFIC_LIGHT_DETECTOR_TRIGGER_ENTRY_EVENT))
239 {
240 this.fillColor = Color.BLUE;
241 }
242 else if (event.getType().equals(TrafficLightDetector.TRAFFIC_LIGHT_DETECTOR_TRIGGER_EXIT_EVENT))
243 {
244 this.fillColor = Color.WHITE;
245 }
246 this.display.repaint();
247 }
248
249 @Override
250 public String toolTipHit(final int testX, final int testY)
251 {
252 if (testX < X_OFFSET + this.x - BOX_SIZE / 2 || testX >= X_OFFSET + this.x + BOX_SIZE / 2
253 || testY < Y_OFFSET - BOX_SIZE / 2 + this.y || testY >= Y_OFFSET + this.y + BOX_SIZE / 2)
254 {
255 return null;
256 }
257 return this.description;
258 }
259
260
261
262
263
264 public String getId()
265 {
266 return this.id;
267 }
268
269 }
270
271
272
273
274 class TrafficLightImage extends LocalEventProducer implements TrafCODObject
275 {
276
277 private static final long serialVersionUID = 20200313L;
278
279
280 private final TrafCodDisplay display;
281
282
283 private final int x;
284
285
286 private final int y;
287
288
289 private final String description;
290
291
292 private TrafficLightColor color = TrafficLightColor.BLACK;
293
294
295
296
297
298
299
300 TrafficLightImage(final TrafCodDisplay display, final Point2D center, final String description)
301 {
302 this.display = display;
303 this.x = (int) center.getX();
304 this.y = (int) center.getY();
305 this.description = description;
306 display.addTrafCODObject(this);
307 }
308
309 @Override
310 public String toolTipHit(final int testX, final int testY)
311 {
312 if (testX < this.x - DISC_SIZE / 2 || testX >= this.x + DISC_SIZE / 2 || testY < this.y - DISC_SIZE / 2
313 || testY >= this.y + DISC_SIZE / 2)
314 {
315 return null;
316 }
317 return this.description;
318 }
319
320
321
322
323
324 public void setTrafficLightColor(final TrafficLightColor trafficLightColor)
325 {
326 this.color = trafficLightColor;
327 this.display.repaint();
328 }
329
330
331 private static final int DISC_SIZE = 11;
332
333 @Override
334 public void draw(final Graphics2D g2)
335 {
336 Color lightColor;
337 switch (this.color)
338 {
339 case BLACK:
340 lightColor = Color.BLACK;
341 break;
342
343 case GREEN:
344 lightColor = Color.green;
345 break;
346
347 case YELLOW:
348 lightColor = Color.YELLOW;
349 break;
350
351 case RED:
352 lightColor = Color.RED;
353 break;
354
355 default:
356 System.err.println("Unhandled TrafficLightColor: " + this.color);
357 return;
358 }
359 g2.setColor(lightColor);
360 g2.fillOval(this.x - DISC_SIZE / 2, this.y - DISC_SIZE / 2, DISC_SIZE, DISC_SIZE);
361
362 }
363
364 }