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.EventType;
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 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 @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(MouseEvent e)
111 {
112 mouseMoved(e);
113 }
114
115
116 @Override
117 public void mouseMoved(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(MouseEvent e)
135 {
136
137 }
138
139
140 @Override
141 public void mousePressed(MouseEvent e)
142 {
143
144 }
145
146
147 @Override
148 public void mouseReleased(MouseEvent e)
149 {
150
151 }
152
153
154 @Override
155 public void mouseEntered(MouseEvent e)
156 {
157 ToolTipManager.sharedInstance().setInitialDelay(0);
158 }
159
160
161 @Override
162 public void mouseExited(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 final TrafCODDisplay display;
199
200
201 private final int x;
202
203
204 private final int y;
205
206
207 private final String description;
208
209
210 private final String id;
211
212
213 private Color fillColor = Color.WHITE;
214
215
216 private static final int BOX_SIZE = 13;
217
218
219 private static final int xOffset = 5;
220
221
222 private static final int yOffset = 5;
223
224
225
226
227
228
229
230
231 public DetectorImage(final TrafCODDisplay display, Point2D center, String id, String description)
232 {
233 this.display = display;
234 this.x = (int) center.getX();
235 this.y = (int) center.getY();
236 this.id = id;
237 this.description = description;
238 display.addTrafCODObject(this);
239 }
240
241
242 @Override
243 public void draw(Graphics2D g2)
244 {
245 g2.setColor(this.fillColor);
246 g2.fillRect(xOffset + this.x - BOX_SIZE / 2, yOffset + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
247 g2.setColor(Color.BLACK);
248 g2.drawRect(xOffset + this.x - BOX_SIZE / 2, yOffset + this.y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
249 }
250
251
252 @Override
253 public void notify(EventInterface event) throws RemoteException
254 {
255 if (event.getType().equals(NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_ENTRY_EVENT))
256 {
257 this.fillColor = Color.BLUE;
258 }
259 else if (event.getType().equals(NonDirectionalOccupancySensor.NON_DIRECTIONAL_OCCUPANCY_SENSOR_TRIGGER_EXIT_EVENT))
260 {
261 this.fillColor = Color.WHITE;
262 }
263 this.display.repaint();
264 }
265
266
267 @Override
268 public String toolTipHit(final int testX, final int testY)
269 {
270 if (testX < xOffset + this.x - BOX_SIZE / 2 || testX >= xOffset + this.x + BOX_SIZE / 2
271 || testY < yOffset - BOX_SIZE / 2 + this.y || testY >= yOffset + this.y + BOX_SIZE / 2)
272 {
273 return null;
274 }
275 return this.description;
276 }
277
278
279
280
281
282 public String getId()
283 {
284 return this.id;
285 }
286
287 }
288
289
290
291
292
293 class TrafficLightImage implements TrafficLight, TrafCODObject
294 {
295
296 private final TrafCODDisplay display;
297
298
299 private final int x;
300
301
302 private final int y;
303
304
305 private final String description;
306
307
308 private TrafficLightColor color = TrafficLightColor.BLACK;
309
310
311
312
313
314
315
316 public TrafficLightImage(final TrafCODDisplay display, final Point2D center, final String description)
317 {
318 this.display = display;
319 this.x = (int) center.getX();
320 this.y = (int) center.getY();
321 this.description = description;
322 display.addTrafCODObject(this);
323 }
324
325
326 @Override
327 public String toolTipHit(int testX, int testY)
328 {
329 if (testX < this.x - DISC_SIZE / 2 || testX >= this.x + DISC_SIZE / 2 || testY < this.y - DISC_SIZE / 2
330 || testY >= this.y + DISC_SIZE / 2)
331 {
332 return null;
333 }
334 return this.description;
335 }
336
337
338 @Override
339 public DirectedPoint getLocation()
340 {
341 return null;
342 }
343
344
345 @Override
346 public Bounds getBounds()
347 {
348 return null;
349 }
350
351
352 @Override
353 public Lane getLane()
354 {
355 return null;
356 }
357
358
359 @Override
360 public LongitudinalDirectionality getDirection()
361 {
362 return LongitudinalDirectionality.DIR_NONE;
363 }
364
365
366 @Override
367 public Length getLongitudinalPosition()
368 {
369 return null;
370 }
371
372
373 @Override
374 public OTSLine3D getGeometry()
375 {
376 return null;
377 }
378
379
380 @Override
381 public Length getHeight()
382 {
383 return null;
384 }
385
386
387 @Override
388 public String getId()
389 {
390 return null;
391 }
392
393
394 @Override
395 public String getFullId()
396 {
397 return null;
398 }
399
400 @Override
401 public Serializable getSourceId() throws RemoteException
402 {
403 return null;
404 }
405
406
407 @Override
408 public boolean addListener(EventListenerInterface listener, EventType eventType, ReferenceType referenceType)
409 throws RemoteException
410 {
411 return false;
412 }
413
414
415 @Override
416 public boolean addListener(EventListenerInterface listener, EventType eventType, int position) throws RemoteException
417 {
418 return false;
419 }
420
421
422 @Override
423 public boolean addListener(EventListenerInterface listener, EventType eventType, int position, ReferenceType referenceType)
424 throws RemoteException
425 {
426 return false;
427 }
428
429
430
431 @Override
432 public boolean addListener(EventListenerInterface listener, EventType eventType) throws RemoteException
433 {
434 return false;
435 }
436
437
438 @Override
439 public boolean hasListeners() throws RemoteException
440 {
441 return false;
442 }
443
444
445 @Override
446 public int numberOfListeners(EventType eventType) throws RemoteException
447 {
448 return 0;
449 }
450
451
452 @Override
453 public Set<EventType> getEventTypesWithListeners() throws RemoteException
454 {
455 return null;
456 }
457
458
459 @Override
460 public boolean removeListener(EventListenerInterface listener, EventType eventType) throws RemoteException
461 {
462 return false;
463 }
464
465
466 @Override
467 public TrafficLightColor getTrafficLightColor()
468 {
469 return null;
470 }
471
472
473 @Override
474 public void setTrafficLightColor(TrafficLightColor trafficLightColor)
475 {
476 this.color = trafficLightColor;
477 this.display.repaint();
478 }
479
480
481 private static final int DISC_SIZE = 11;
482
483
484 @Override
485 public void draw(Graphics2D g2)
486 {
487 Color lightColor;
488 switch (this.color)
489 {
490 case BLACK:
491 lightColor = Color.BLACK;
492 break;
493
494 case GREEN:
495 lightColor = Color.green;
496 break;
497
498 case YELLOW:
499 lightColor = Color.YELLOW;
500 break;
501
502 case RED:
503 lightColor = Color.RED;
504 break;
505
506 default:
507 System.err.println("Unhandled TrafficLightColor: " + this.color);
508 return;
509 }
510 g2.setColor(lightColor);
511 g2.fillOval(this.x - DISC_SIZE / 2, this.y - DISC_SIZE / 2, DISC_SIZE, DISC_SIZE);
512
513 }
514
515 }