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