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
78 @Override
79 protected void paintComponent(final Graphics g)
80 {
81 super.paintComponent(g);
82 g.drawImage(this.image, 0, 0, null);
83 for (TrafCODObject tco : this.trafCODObjects)
84 {
85 tco.draw((Graphics2D) g);
86 }
87 }
88
89
90
91
92
93 void addTrafCODObject(final TrafCODObject trafCODObject)
94 {
95 this.trafCODObjects.add(trafCODObject);
96 }
97
98
99 @Override
100 public void mouseDragged(final MouseEvent e)
101 {
102 mouseMoved(e);
103 }
104
105
106 @Override
107 public void mouseMoved(final MouseEvent e)
108 {
109 String toolTipText = null;
110 for (TrafCODObject tco : this.trafCODObjects)
111 {
112 toolTipText = tco.toolTipHit(e.getX(), e.getY());
113 if (null != toolTipText)
114 {
115 break;
116 }
117 }
118
119 setToolTipText(toolTipText);
120 }
121
122
123 @Override
124 public void mouseClicked(final MouseEvent e)
125 {
126
127 }
128
129
130 @Override
131 public void mousePressed(final MouseEvent e)
132 {
133
134 }
135
136
137 @Override
138 public void mouseReleased(final MouseEvent e)
139 {
140
141 }
142
143
144 @Override
145 public void mouseEntered(final MouseEvent e)
146 {
147 ToolTipManager.sharedInstance().setInitialDelay(0);
148 }
149
150
151 @Override
152 public void mouseExited(final MouseEvent e)
153 {
154 ToolTipManager.sharedInstance().setInitialDelay(this.defaultInitialDelay);
155 }
156
157 }
158
159
160
161
162
163 interface TrafCODObject
164 {
165
166
167
168
169 void draw(Graphics2D g2);
170
171
172
173
174
175
176
177
178 String toolTipHit(int testX, int testY);
179
180 }
181
182
183
184
185 class DetectorImage implements TrafCODObject, EventListener
186 {
187
188 private static final long serialVersionUID = 20200313L;
189
190
191 private final TrafCodDisplay display;
192
193
194 private final int x;
195
196
197 private final int y;
198
199
200 private final String description;
201
202
203 private final String id;
204
205
206 private Color fillColor = Color.WHITE;
207
208
209 private static final int BOX_SIZE = 13;
210
211
212 private static final int X_OFFSET = 5;
213
214
215 private static final int Y_OFFSET = 5;
216
217
218
219
220
221
222
223
224 DetectorImage(final TrafCodDisplay display, final Point2D center, final String id, final String description)
225 {
226 this.display = display;
227 this.x = (int) center.getX();
228 this.y = (int) center.getY();
229 this.id = id;
230 this.description = description;
231 display.addTrafCODObject(this);
232 }
233
234
235 @Override
236 public void draw(final Graphics2D g2)
237 {
238 g2.setColor(this.fillColor);
239 g2.fillRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
240 g2.setColor(Color.BLACK);
241 g2.drawRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
242 }
243
244
245 @Override
246 public void notify(final Event event) throws RemoteException
247 {
248 if (event.getType().equals(TrafficLightDetector.TRAFFIC_LIGHT_DETECTOR_TRIGGER_ENTRY_EVENT))
249 {
250 this.fillColor = Color.BLUE;
251 }
252 else if (event.getType().equals(TrafficLightDetector.TRAFFIC_LIGHT_DETECTOR_TRIGGER_EXIT_EVENT))
253 {
254 this.fillColor = Color.WHITE;
255 }
256 this.display.repaint();
257 }
258
259
260 @Override
261 public String toolTipHit(final int testX, final int testY)
262 {
263 if (testX < X_OFFSET + this.x - BOX_SIZE / 2 || testX >= X_OFFSET + this.x + BOX_SIZE / 2
264 || testY < Y_OFFSET - BOX_SIZE / 2 + this.y || testY >= Y_OFFSET + this.y + BOX_SIZE / 2)
265 {
266 return null;
267 }
268 return this.description;
269 }
270
271
272
273
274
275 public String getId()
276 {
277 return this.id;
278 }
279
280 }
281
282
283
284
285 class TrafficLightImage extends LocalEventProducer implements TrafCODObject
286 {
287
288 private static final long serialVersionUID = 20200313L;
289
290
291 private final TrafCodDisplay display;
292
293
294 private final int x;
295
296
297 private final int y;
298
299
300 private final String description;
301
302
303 private TrafficLightColor color = TrafficLightColor.BLACK;
304
305
306
307
308
309
310
311 TrafficLightImage(final TrafCodDisplay display, final Point2D center, final String description)
312 {
313 this.display = display;
314 this.x = (int) center.getX();
315 this.y = (int) center.getY();
316 this.description = description;
317 display.addTrafCODObject(this);
318 }
319
320
321 @Override
322 public String toolTipHit(final int testX, final int testY)
323 {
324 if (testX < this.x - DISC_SIZE / 2 || testX >= this.x + DISC_SIZE / 2 || testY < this.y - DISC_SIZE / 2
325 || testY >= this.y + DISC_SIZE / 2)
326 {
327 return null;
328 }
329 return this.description;
330 }
331
332
333
334
335
336 public void setTrafficLightColor(final TrafficLightColor trafficLightColor)
337 {
338 this.color = trafficLightColor;
339 this.display.repaint();
340 }
341
342
343 private static final int DISC_SIZE = 11;
344
345
346 @Override
347 public void draw(final Graphics2D g2)
348 {
349 Color lightColor;
350 switch (this.color)
351 {
352 case BLACK:
353 lightColor = Color.BLACK;
354 break;
355
356 case GREEN:
357 lightColor = Color.green;
358 break;
359
360 case YELLOW:
361 lightColor = Color.YELLOW;
362 break;
363
364 case RED:
365 lightColor = Color.RED;
366 break;
367
368 default:
369 System.err.println("Unhandled TrafficLightColor: " + this.color);
370 return;
371 }
372 g2.setColor(lightColor);
373 g2.fillOval(this.x - DISC_SIZE / 2, this.y - DISC_SIZE / 2, DISC_SIZE, DISC_SIZE);
374
375 }
376
377 }