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