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