View Javadoc
1   package org.opentrafficsim.draw.factory;
2   
3   import java.awt.Color;
4   import java.rmi.RemoteException;
5   import java.util.HashMap;
6   import java.util.Map;
7   
8   import javax.naming.NamingException;
9   
10  import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
11  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
12  import org.opentrafficsim.core.geometry.OTSGeometryException;
13  import org.opentrafficsim.core.gtu.GTU;
14  import org.opentrafficsim.core.gtu.GTUType;
15  import org.opentrafficsim.core.gtu.GtuGenerator;
16  import org.opentrafficsim.core.network.LateralDirectionality;
17  import org.opentrafficsim.core.network.Link;
18  import org.opentrafficsim.core.network.Network;
19  import org.opentrafficsim.core.network.Node;
20  import org.opentrafficsim.core.network.OTSNetwork;
21  import org.opentrafficsim.core.object.ObjectInterface;
22  import org.opentrafficsim.draw.core.OTSDrawingException;
23  import org.opentrafficsim.draw.gtu.DefaultCarAnimation;
24  import org.opentrafficsim.draw.network.LinkAnimation;
25  import org.opentrafficsim.draw.network.NodeAnimation;
26  import org.opentrafficsim.draw.road.BusStopAnimation;
27  import org.opentrafficsim.draw.road.ConflictAnimation;
28  import org.opentrafficsim.draw.road.LaneAnimation;
29  import org.opentrafficsim.draw.road.SensorAnimation;
30  import org.opentrafficsim.draw.road.ShoulderAnimation;
31  import org.opentrafficsim.draw.road.SpeedSignAnimation;
32  import org.opentrafficsim.draw.road.StripeAnimation;
33  import org.opentrafficsim.draw.road.StripeAnimation.TYPE;
34  import org.opentrafficsim.draw.road.TrafficLightAnimation;
35  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
36  import org.opentrafficsim.road.network.lane.CrossSectionElement;
37  import org.opentrafficsim.road.network.lane.CrossSectionLink;
38  import org.opentrafficsim.road.network.lane.Lane;
39  import org.opentrafficsim.road.network.lane.Shoulder;
40  import org.opentrafficsim.road.network.lane.Stripe;
41  import org.opentrafficsim.road.network.lane.conflict.Conflict;
42  import org.opentrafficsim.road.network.lane.object.BusStop;
43  import org.opentrafficsim.road.network.lane.object.SpeedSign;
44  import org.opentrafficsim.road.network.lane.object.sensor.SingleSensor;
45  import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
46  
47  import nl.tudelft.simulation.dsol.SimRuntimeException;
48  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
49  import nl.tudelft.simulation.dsol.logger.SimLogger;
50  import nl.tudelft.simulation.event.EventInterface;
51  import nl.tudelft.simulation.event.EventListenerInterface;
52  
53  /**
54   * DefaultAnimationFactory.java. <br>
55   * <br>
56   * Copyright (c) 2003-2019 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
57   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
58   * source code and binary code of this software is proprietary information of Delft University of Technology.
59   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
60   */
61  public class DefaultAnimationFactory implements EventListenerInterface
62  {
63      /** the simulator. */
64      private final OTSSimulatorInterface simulator;
65  
66      /** GTU colorer. */
67      private final GTUColorer gtuColorer;
68  
69      /** rendered gtus. */
70      private Map<LaneBasedGTU, Renderable2D<LaneBasedGTU>> animatedGTUs = new HashMap<>();
71  
72      /** rendered static objects. */
73      private Map<ObjectInterface, Renderable2D<?>> animatedObjects = new HashMap<>();
74  
75      /**
76       * Creates animations for nodes, links and lanes. The class will subscribe to the network and listen to changes, so the
77       * adding and removing of GTUs and Objects is animated correctly.
78       * @param network OTSNetwork; the network
79       * @param simulator OTSSimulatorInterface; the simulator
80       * @param gtuColorer GTUColorer; GTU colorer
81       * @param animateNetwork boolean; whether to animate the current network objects
82       * @throws OTSDrawingException on drawing error
83       */
84      protected DefaultAnimationFactory(final OTSNetwork network, final OTSSimulatorInterface simulator,
85              final GTUColorer gtuColorer, final boolean animateNetwork) throws OTSDrawingException
86      {
87          this.simulator = simulator;
88          this.gtuColorer = gtuColorer;
89  
90          // subscribe to adding and removing events
91          network.addListener(this, Network.ANIMATION_GTU_ADD_EVENT);
92          network.addListener(this, Network.ANIMATION_GTU_REMOVE_EVENT);
93          network.addListener(this, Network.ANIMATION_OBJECT_ADD_EVENT);
94          network.addListener(this, Network.ANIMATION_OBJECT_REMOVE_EVENT);
95          network.addListener(this, Network.ANIMATION_GENERATOR_ADD_EVENT);
96          network.addListener(this, Network.ANIMATION_GENERATOR_REMOVE_EVENT);
97  
98          // model the current infrastructure
99          try
100         {
101             if (animateNetwork)
102             {
103                 for (Node node : network.getNodeMap().values())
104                 {
105                     new NodeAnimation(node, simulator);
106                 }
107                 for (Link link : network.getLinkMap().values())
108                 {
109                     new LinkAnimation(link, simulator, 0.5f);
110                     if (link instanceof CrossSectionLink)
111                     {
112                         for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
113                         {
114                             if (element instanceof Lane)
115                             {
116                                 new LaneAnimation((Lane) element, simulator, Color.GRAY.brighter(), false);
117                             }
118                             else if (element instanceof Shoulder)
119                             {
120                                 new ShoulderAnimation((Shoulder) element, simulator, Color.DARK_GRAY);
121                             }
122                             else if (element instanceof Stripe)
123                             {
124                                 Stripe stripe = (Stripe) element;
125                                 TYPE type;
126                                 if (stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR), LateralDirectionality.LEFT))
127                                 {
128                                     type = stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR),
129                                             LateralDirectionality.RIGHT) ? TYPE.DASHED : TYPE.LEFTONLY;
130                                 }
131                                 else
132                                 {
133                                     type = stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR),
134                                             LateralDirectionality.RIGHT) ? TYPE.RIGHTONLY : TYPE.SOLID;
135                                 }
136                                 new StripeAnimation((Stripe) element, simulator, type);
137                             }
138                         }
139                     }
140                 }
141 
142                 for (TrafficLight tl : network.getObjectMap(TrafficLight.class).values())
143                 {
144                     new TrafficLightAnimation(tl, simulator);
145                 }
146 
147             }
148 
149             for (GTU gtu : network.getGTUs())
150             {
151                 Renderable2D<LaneBasedGTU> gtuAnimation =
152                         new DefaultCarAnimation((LaneBasedGTU) gtu, simulator, this.gtuColorer);
153                 this.animatedGTUs.put((LaneBasedGTU) gtu, gtuAnimation);
154             }
155 
156             for (ObjectInterface object : network.getObjectMap().values())
157             {
158                 animateStaticObject(object);
159             }
160         }
161         catch (RemoteException | NamingException | OTSGeometryException exception)
162         {
163             throw new OTSDrawingException("Exception while creating network animation.", exception);
164         }
165     }
166 
167     /**
168      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is not read from XML. The class will
169      * subscribe to the network and listen to changes, so the adding and removing of GTUs and Objects is animated correctly.
170      * @param network OTSNetwork; the network
171      * @param simulator OTSSimulatorInterface; the simulator
172      * @param gtuColorer GTUColorer; GTU colorer
173      * @throws OTSDrawingException on drawing error
174      */
175     public static void animateNetwork(final OTSNetwork network, final OTSSimulatorInterface simulator,
176             final GTUColorer gtuColorer) throws OTSDrawingException
177     {
178         new DefaultAnimationFactory(network, simulator, gtuColorer, true);
179     }
180 
181     /**
182      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is read from XML. The class will
183      * subscribe to the network and listen to changes, so the adding and removing of GTUs and Objects is animated correctly.
184      * @param network OTSNetwork; the network
185      * @param simulator OTSSimulatorInterface; the simulator
186      * @param gtuColorer GTUColorer; GTU colorer
187      * @throws OTSDrawingException on drawing error
188      */
189     public static void animateXmlNetwork(final OTSNetwork network, final OTSSimulatorInterface simulator,
190             final GTUColorer gtuColorer) throws OTSDrawingException
191     {
192         new DefaultAnimationFactory(network, simulator, gtuColorer, false);
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public void notify(final EventInterface event) throws RemoteException
198     {
199         try
200         {
201             if (event.getType().equals(Network.ANIMATION_GTU_ADD_EVENT))
202             {
203                 // schedule the addition of the GTU to prevent it from not having an operational plan
204                 LaneBasedGTU gtu = (LaneBasedGTU) event.getContent();
205                 this.simulator.scheduleEventNow(this, this, "animateGTU", new Object[] { gtu });
206             }
207             else if (event.getType().equals(Network.ANIMATION_GTU_REMOVE_EVENT))
208             {
209                 LaneBasedGTU gtu = (LaneBasedGTU) event.getContent();
210                 if (this.animatedGTUs.containsKey(gtu))
211                 {
212                     this.animatedGTUs.get(gtu).destroy();
213                     this.animatedGTUs.remove(gtu);
214                 }
215             }
216             else if (event.getType().equals(Network.ANIMATION_OBJECT_ADD_EVENT))
217             {
218                 ObjectInterface object = (ObjectInterface) event.getContent();
219                 animateStaticObject(object);
220             }
221             else if (event.getType().equals(Network.ANIMATION_OBJECT_REMOVE_EVENT))
222             {
223                 ObjectInterface object = (ObjectInterface) event.getContent();
224                 if (this.animatedObjects.containsKey(object))
225                 {
226                     this.animatedObjects.get(object).destroy();
227                     this.animatedObjects.remove(object);
228                 }
229             }
230             else if (event.getType().equals(Network.ANIMATION_GENERATOR_ADD_EVENT))
231             {
232                 GtuGenerator gtuGenerator = (GtuGenerator) event.getContent();
233                 animateGTUGenerator(gtuGenerator);
234             }
235             else if (event.getType().equals(Network.ANIMATION_GENERATOR_REMOVE_EVENT))
236             {
237                 // TODO: change the way generators are animated
238             }
239         }
240         catch (NamingException | SimRuntimeException exception)
241         {
242             SimLogger.always().error(exception, "Exception while updating network animation.");
243         }
244     }
245 
246     /**
247      * Draw the GTU (scheduled method).
248      * @param gtu LaneBasedGTU; the GTU to draw
249      */
250     protected void animateGTU(final LaneBasedGTU gtu)
251     {
252         try
253         {
254             Renderable2D<LaneBasedGTU> gtuAnimation = new DefaultCarAnimation(gtu, this.simulator, this.gtuColorer);
255             this.animatedGTUs.put(gtu, gtuAnimation);
256         }
257         catch (RemoteException | NamingException exception)
258         {
259             SimLogger.always().error(exception, "Exception while drawing GTU.");
260         }
261     }
262 
263     /**
264      * Draw the static object.
265      * @param object ObjectInterface; the object to draw
266      */
267     protected void animateStaticObject(final ObjectInterface object)
268     {
269         try
270         {
271             if (object instanceof SingleSensor)
272             {
273                 SingleSensor sensor = (SingleSensor) object;
274                 Renderable2D<SingleSensor> objectAnimation =
275                         new SensorAnimation(sensor, sensor.getLongitudinalPosition(), this.simulator, Color.GREEN);
276                 this.animatedObjects.put(object, objectAnimation);
277             }
278             else if (object instanceof Conflict)
279             {
280                 Conflict conflict = (Conflict) object;
281                 Renderable2D<Conflict> objectAnimation = new ConflictAnimation(conflict, this.simulator);
282                 this.animatedObjects.put(object, objectAnimation);
283             }
284             else if (object instanceof SpeedSign)
285             {
286                 SpeedSign speedSign = (SpeedSign) object;
287                 Renderable2D<SpeedSign> objectAnimation = new SpeedSignAnimation(speedSign, this.simulator);
288                 this.animatedObjects.put(object, objectAnimation);
289             }
290             else if (object instanceof BusStop)
291             {
292                 BusStop busStop = (BusStop) object;
293                 Renderable2D<BusStop> objectAnimation = new BusStopAnimation(busStop, this.simulator);
294                 this.animatedObjects.put(object, objectAnimation);
295             }
296         }
297         catch (RemoteException | NamingException exception)
298         {
299             SimLogger.always().error(exception, "Exception while drawing Object of class ObjectInterface.");
300         }
301     }
302 
303     /**
304      * Draw the GTUGenerator.
305      * @param gtuGenerator GtuGenerator; the GTUGenerator to draw
306      */
307     protected void animateGTUGenerator(final GtuGenerator gtuGenerator)
308     {
309         // TODO: default animation of GTU generator
310     }
311 
312 }