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