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.io.Serializable;
13 import java.rmi.RemoteException;
14 import java.util.LinkedHashSet;
15 import java.util.Set;
16
17 import javax.swing.JPanel;
18 import javax.swing.ToolTipManager;
19
20 import org.djunits.value.vdouble.scalar.Length;
21 import org.djutils.event.EventInterface;
22 import org.djutils.event.EventListenerInterface;
23 import org.djutils.event.EventTypeInterface;
24 import org.djutils.event.ref.ReferenceType;
25 import org.opentrafficsim.core.geometry.Bounds;
26 import org.opentrafficsim.core.geometry.DirectedPoint;
27 import org.opentrafficsim.core.geometry.OTSLine3D;
28 import org.opentrafficsim.core.network.LongitudinalDirectionality;
29 import org.opentrafficsim.road.network.lane.Lane;
30 import org.opentrafficsim.road.network.lane.object.sensor.NonDirectionalOccupancySensor;
31 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
32 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
33
34
35
36
37
38
39
40
41
42
43 public class TrafCODDisplay extends JPanel implements MouseMotionListener, MouseListener
44 {
45
46 private static final long serialVersionUID = 20161115L;
47
48
49 private final BufferedImage image;
50
51
52 private Set<TrafCODObject> trafCODObjects = new LinkedHashSet<>();
53
54
55 private final int defaultInitialDelay = ToolTipManager.sharedInstance().getInitialDelay();
56
57
58
59
60
61
62
63 public TrafCODDisplay(final BufferedImage image)
64 {
65 this.image = image;
66 super.setPreferredSize(new Dimension(this.image.getWidth(), this.image.getHeight()));
67 addMouseMotionListener(this);
68 }
69
70
71
72
73
74
75 public DetectorImage getDetectorImage(final String id)
76 {
77 for (TrafCODObject tco : this.trafCODObjects)
78 {
79 if (tco instanceof DetectorImage && ((DetectorImage) tco).getId().equals(id))
80 {
81 return (DetectorImage) tco;
82 }
83 }
84 return null;
85 }
86
87
88 @Override
89 protected void paintComponent(final Graphics g)
90 {
91 super.paintComponent(g);
92 g.drawImage(this.image, 0, 0, null);
93 for (TrafCODObject tco : this.trafCODObjects)
94 {
95 tco.draw((Graphics2D) g);
96 }
97 }
98
99
100
101
102
103 void addTrafCODObject(final TrafCODObject trafCODObject)
104 {
105 this.trafCODObjects.add(trafCODObject);
106 }
107
108
109 @Override
110 public void mouseDragged(final MouseEvent e)
111 {
112 mouseMoved(e);
113 }
114
115
116 @Override
117 public void mouseMoved(final MouseEvent e)
118 {
119 String toolTipText = null;
120 for (TrafCODObject tco : this.trafCODObjects)
121 {
122 toolTipText = tco.toolTipHit(e.getX(), e.getY());
123 if (null != toolTipText)
124 {
125 break;
126 }
127 }
128
129 setToolTipText(toolTipText);
130 }
131
132
133 @Override
134 public void mouseClicked(final MouseEvent e)
135 {
136
137 }
138
139
140 @Override
141 public void mousePressed(final MouseEvent e)
142 {
143
144 }
145
146
147 @Override
148 public void mouseReleased(final MouseEvent e)
149 {
150
151 }
152
153
154 @Override
155 public void mouseEntered(final MouseEvent e)
156 {
157 ToolTipManager.sharedInstance().setInitialDelay(0);
158 }
159
160
161 @Override
162 public void mouseExited(final MouseEvent e)
163 {
164 ToolTipManager.sharedInstance().setInitialDelay(this.defaultInitialDelay);
165 }
166
167 }
168
169
170
171
172
173 interface TrafCODObject
174 {
175
176
177
178
179 void draw(Graphics2D g2);
180
181
182
183
184
185
186
187
188 String toolTipHit(int testX, int testY);
189
190 }
191
192
193
194
195 class DetectorImage implements TrafCODObject, EventListenerInterface
196 {
197
198 private static final long serialVersionUID = 20200313L;
199
200
201 private final TrafCODDisplay display;
202
203
204 private final int x;
205
206
207 private final int y;
208
209
210 private final String description;
211
212
213 private final String id;
214
215
216 private Color fillColor = Color.WHITE;
217
218
219 private static final int BOX_SIZE = 13;
220
221
222 private static final int X_OFFSET = 5;
223
224
225 private static final int Y_OFFSET = 5;
226
227
228
229
230
231
232
233
234 DetectorImage(final TrafCODDisplay display, final Point2D center, final String id, final String description)
235 {
236 this.display = display;
237 this.x = (int) center.getX();
238 this.y = (int) center.getY();
239 this.id = id;
240 this.description = description;
241 display.addTrafCODObject(this);
242 }
243
244
245 @Override
246 public void draw(final Graphics2D g2)
247 {
248 g2.setColor(this.fillColor);
249 g2.fillRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
250 g2.setColor(Color.BLACK);
251 g2.drawRect(X_OFFSET + this.x - BOX_SIZE / 2, Y_OFFSET + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
252 }
253
254
255 @Override
256 public void notify(final EventInterface event) throws RemoteException
257 {
258 if (event.getType().equals(NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_ENTRY_EVENT))
259 {
260 this.fillColor = Color.BLUE;
261 }
262 else if (event.getType().equals(NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_EXIT_EVENT))
263 {
264 this.fillColor = Color.WHITE;
265 }
266 this.display.repaint();
267 }
268
269
270 @Override
271 public String toolTipHit(final int testX, final int testY)
272 {
273 if (testX < X_OFFSET + this.x - BOX_SIZE / 2 || testX >= X_OFFSET + this.x + BOX_SIZE / 2
274 || testY < Y_OFFSET - BOX_SIZE / 2 + this.y || testY >= Y_OFFSET + this.y + BOX_SIZE / 2)
275 {
276 return null;
277 }
278 return this.description;
279 }
280
281
282
283
284
285 public String getId()
286 {
287 return this.id;
288 }
289
290 }
291
292
293
294
295
296 class TrafficLightImage implements TrafficLight, TrafCODObject
297 {
298
299 private static final long serialVersionUID = 20200313L;
300
301
302 private final TrafCODDisplay display;
303
304
305 private final int x;
306
307
308 private final int y;
309
310
311 private final String description;
312
313
314 private TrafficLightColor color = TrafficLightColor.BLACK;
315
316
317
318
319
320
321
322 TrafficLightImage(final TrafCODDisplay display, final Point2D center, final String description)
323 {
324 this.display = display;
325 this.x = (int) center.getX();
326 this.y = (int) center.getY();
327 this.description = description;
328 display.addTrafCODObject(this);
329 }
330
331
332 @Override
333 public String toolTipHit(final int testX, final int testY)
334 {
335 if (testX < this.x - DISC_SIZE / 2 || testX >= this.x + DISC_SIZE / 2 || testY < this.y - DISC_SIZE / 2
336 || testY >= this.y + DISC_SIZE / 2)
337 {
338 return null;
339 }
340 return this.description;
341 }
342
343
344 @Override
345 public DirectedPoint getLocation()
346 {
347 return null;
348 }
349
350
351 @Override
352 public Bounds getBounds()
353 {
354 return null;
355 }
356
357
358 @Override
359 public Lane getLane()
360 {
361 return null;
362 }
363
364
365 @Override
366 public LongitudinalDirectionality getDirection()
367 {
368 return LongitudinalDirectionality.DIR_NONE;
369 }
370
371
372 @Override
373 public Length getLongitudinalPosition()
374 {
375 return null;
376 }
377
378
379 @Override
380 public OTSLine3D getGeometry()
381 {
382 return null;
383 }
384
385
386 @Override
387 public Length getHeight()
388 {
389 return null;
390 }
391
392
393 @Override
394 public String getId()
395 {
396 return null;
397 }
398
399
400 @Override
401 public String getFullId()
402 {
403 return null;
404 }
405
406 @Override
407 public Serializable getSourceId() throws RemoteException
408 {
409 return null;
410 }
411
412
413 @Override
414 public boolean addListener(final EventListenerInterface listener, final EventTypeInterface eventType,
415 final ReferenceType referenceType) throws RemoteException
416 {
417 return false;
418 }
419
420
421 @Override
422 public boolean addListener(final EventListenerInterface listener, final EventTypeInterface eventType, final int position)
423 throws RemoteException
424 {
425 return false;
426 }
427
428
429 @Override
430 public boolean addListener(final EventListenerInterface listener, final EventTypeInterface eventType, final int position,
431 final ReferenceType referenceType) throws RemoteException
432 {
433 return false;
434 }
435
436
437
438 @Override
439 public boolean addListener(final EventListenerInterface listener, final EventTypeInterface eventType) throws RemoteException
440 {
441 return false;
442 }
443
444
445 @Override
446 public boolean hasListeners() throws RemoteException
447 {
448 return false;
449 }
450
451
452 @Override
453 public int numberOfListeners(final EventTypeInterface eventType) throws RemoteException
454 {
455 return 0;
456 }
457
458
459 @Override
460 public Set<EventTypeInterface> getEventTypesWithListeners() throws RemoteException
461 {
462 return null;
463 }
464
465
466 @Override
467 public boolean removeListener(final EventListenerInterface listener, final EventTypeInterface eventType)
468 throws RemoteException
469 {
470 return false;
471 }
472
473
474 @Override
475 public TrafficLightColor getTrafficLightColor()
476 {
477 return null;
478 }
479
480
481 @Override
482 public void setTrafficLightColor(final TrafficLightColor trafficLightColor)
483 {
484 this.color = trafficLightColor;
485 this.display.repaint();
486 }
487
488
489 private static final int DISC_SIZE = 11;
490
491
492 @Override
493 public void draw(final Graphics2D g2)
494 {
495 Color lightColor;
496 switch (this.color)
497 {
498 case BLACK:
499 lightColor = Color.BLACK;
500 break;
501
502 case GREEN:
503 lightColor = Color.green;
504 break;
505
506 case YELLOW:
507 lightColor = Color.YELLOW;
508 break;
509
510 case RED:
511 lightColor = Color.RED;
512 break;
513
514 default:
515 System.err.println("Unhandled TrafficLightColor: " + this.color);
516 return;
517 }
518 g2.setColor(lightColor);
519 g2.fillOval(this.x - DISC_SIZE / 2, this.y - DISC_SIZE / 2, DISC_SIZE, DISC_SIZE);
520
521 }
522
523 }