DefaultAnimationFactory.java

  1. package org.opentrafficsim.draw.factory;

  2. import java.awt.Color;
  3. import java.rmi.RemoteException;
  4. import java.util.Collections;
  5. import java.util.LinkedHashMap;
  6. import java.util.Map;

  7. import javax.naming.NamingException;

  8. import org.djutils.event.EventInterface;
  9. import org.djutils.event.EventListenerInterface;
  10. import org.djutils.logger.CategoryLogger;
  11. import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
  12. import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
  13. import org.opentrafficsim.core.geometry.OTSGeometryException;
  14. import org.opentrafficsim.core.gtu.GTU;
  15. import org.opentrafficsim.core.gtu.GTUType;
  16. import org.opentrafficsim.core.gtu.GtuGenerator;
  17. import org.opentrafficsim.core.network.LateralDirectionality;
  18. import org.opentrafficsim.core.network.Link;
  19. import org.opentrafficsim.core.network.Network;
  20. import org.opentrafficsim.core.network.Node;
  21. import org.opentrafficsim.core.network.OTSNetwork;
  22. import org.opentrafficsim.core.object.ObjectInterface;
  23. import org.opentrafficsim.draw.core.OTSDrawingException;
  24. import org.opentrafficsim.draw.gtu.DefaultCarAnimation;
  25. import org.opentrafficsim.draw.network.LinkAnimation;
  26. import org.opentrafficsim.draw.network.NodeAnimation;
  27. import org.opentrafficsim.draw.road.BusStopAnimation;
  28. import org.opentrafficsim.draw.road.ConflictAnimation;
  29. import org.opentrafficsim.draw.road.LaneAnimation;
  30. import org.opentrafficsim.draw.road.SensorAnimation;
  31. import org.opentrafficsim.draw.road.ShoulderAnimation;
  32. import org.opentrafficsim.draw.road.SpeedSignAnimation;
  33. import org.opentrafficsim.draw.road.StripeAnimation;
  34. import org.opentrafficsim.draw.road.StripeAnimation.TYPE;
  35. import org.opentrafficsim.draw.road.TrafficLightAnimation;
  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.DestinationSensor;
  46. import org.opentrafficsim.road.network.lane.object.sensor.SingleSensor;
  47. import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
  48. import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;

  49. import nl.tudelft.simulation.dsol.SimRuntimeException;
  50. import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;

  51. /**
  52.  * DefaultAnimationFactory.java. <br>
  53.  * <br>
  54.  * Copyright (c) 2003-2020 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
  55.  * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
  56.  * source code and binary code of this software is proprietary information of Delft University of Technology.
  57.  * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
  58.  */
  59. public class DefaultAnimationFactory implements EventListenerInterface
  60. {
  61.     /** the simulator. */
  62.     private final OTSSimulatorInterface simulator;

  63.     /** GTU colorer. */
  64.     private final GTUColorer gtuColorer;

  65.     /** rendered gtus. */
  66.     private Map<LaneBasedGTU, Renderable2D<LaneBasedGTU>> animatedGTUs = Collections.synchronizedMap(new LinkedHashMap<>());

  67.     /** rendered static objects. */
  68.     public Map<ObjectInterface, Renderable2D<?>> animatedObjects = Collections.synchronizedMap(new LinkedHashMap<>());

  69.     /**
  70.      * Creates animations for nodes, links and lanes. The class will subscribe to the network and listen to changes, so the
  71.      * adding and removing of GTUs and Objects is animated correctly.
  72.      * @param network OTSNetwork; the network
  73.      * @param gtuColorer GTUColorer; GTU colorer
  74.      * @param animateNetwork boolean; whether to animate the current network objects
  75.      * @throws OTSDrawingException on drawing error
  76.      */
  77.     protected DefaultAnimationFactory(final OTSNetwork network, final GTUColorer gtuColorer,
  78.             final boolean animateNetwork) throws OTSDrawingException
  79.     {
  80.         this.simulator = network.getSimulator();
  81.         this.gtuColorer = gtuColorer;

  82.         // subscribe to adding and removing events
  83.         network.addListener(this, Network.ANIMATION_GTU_ADD_EVENT);
  84.         network.addListener(this, Network.ANIMATION_GTU_REMOVE_EVENT);
  85.         network.addListener(this, Network.ANIMATION_OBJECT_ADD_EVENT);
  86.         network.addListener(this, Network.ANIMATION_OBJECT_REMOVE_EVENT);
  87.         network.addListener(this, Network.ANIMATION_GENERATOR_ADD_EVENT);
  88.         network.addListener(this, Network.ANIMATION_GENERATOR_REMOVE_EVENT);

  89.         // model the current infrastructure
  90.         try
  91.         {
  92.             if (animateNetwork)
  93.             {
  94.                 for (Node node : network.getNodeMap().values())
  95.                 {
  96.                     new NodeAnimation(node, simulator);
  97.                 }
  98.                 for (Link link : network.getLinkMap().values())
  99.                 {
  100.                     new LinkAnimation(link, simulator, 0.5f);
  101.                     if (link instanceof CrossSectionLink)
  102.                     {
  103.                         for (CrossSectionElement element : ((CrossSectionLink) link).getCrossSectionElementList())
  104.                         {
  105.                             if (element instanceof Lane)
  106.                             {
  107.                                 new LaneAnimation((Lane) element, simulator, Color.GRAY.brighter());
  108.                             }
  109.                             else if (element instanceof Shoulder)
  110.                             {
  111.                                 new ShoulderAnimation((Shoulder) element, simulator, Color.DARK_GRAY);
  112.                             }
  113.                             else if (element instanceof Stripe)
  114.                             {
  115.                                 Stripe stripe = (Stripe) element;
  116.                                 TYPE type;
  117.                                 if (stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR), LateralDirectionality.LEFT))
  118.                                 {
  119.                                     type = stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR),
  120.                                             LateralDirectionality.RIGHT) ? TYPE.DASHED : TYPE.LEFTONLY;
  121.                                 }
  122.                                 else
  123.                                 {
  124.                                     type = stripe.isPermeable(network.getGtuType(GTUType.DEFAULTS.CAR),
  125.                                             LateralDirectionality.RIGHT) ? TYPE.RIGHTONLY : TYPE.SOLID;
  126.                                 }
  127.                                 new StripeAnimation((Stripe) element, simulator, type);
  128.                             }
  129.                         }
  130.                     }
  131.                 }

  132.                 for (TrafficLight tl : network.getObjectMap(TrafficLight.class).values())
  133.                 {
  134.                     new TrafficLightAnimation(tl, simulator);
  135.                 }

  136.             }

  137.             for (GTU gtu : network.getGTUs())
  138.             {
  139.                 Renderable2D<LaneBasedGTU> gtuAnimation =
  140.                         new DefaultCarAnimation((LaneBasedGTU) gtu, simulator, this.gtuColorer);
  141.                 this.animatedGTUs.put((LaneBasedGTU) gtu, gtuAnimation);
  142.             }

  143.             for (ObjectInterface object : network.getObjectMap().values())
  144.             {
  145.                 animateStaticObject(object);
  146.             }
  147.         }
  148.         catch (RemoteException | NamingException | OTSGeometryException exception)
  149.         {
  150.             throw new OTSDrawingException("Exception while creating network animation.", exception);
  151.         }

  152.     }

  153.     /**
  154.      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is not read from XML. The class will
  155.      * subscribe to the network and listen to changes, so the adding and removing of GTUs and Objects is animated correctly.
  156.      * @param network OTSNetwork; the network
  157.      * @param simulator OTSSimulatorInterface; the simulator
  158.      * @param gtuColorer GTUColorer; GTU colorer
  159.      * @return the DefaultAnimationFactory
  160.      * @throws OTSDrawingException on drawing error
  161.      */
  162.     public static DefaultAnimationFactory animateNetwork(final OTSNetwork network, final OTSSimulatorInterface simulator,
  163.             final GTUColorer gtuColorer) throws OTSDrawingException
  164.     {
  165.         return new DefaultAnimationFactory(network, gtuColorer, true);
  166.     }

  167.     /**
  168.      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is 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 gtuColorer GTUColorer; GTU colorer
  172.      * @return the DefaultAnimationFactory
  173.      * @throws OTSDrawingException on drawing error
  174.      */
  175.     public static DefaultAnimationFactory animateXmlNetwork(final OTSNetwork network, final GTUColorer gtuColorer) throws OTSDrawingException
  176.     {
  177.         return new DefaultAnimationFactory(network, gtuColorer, false);
  178.     }

  179.     /** {@inheritDoc} */
  180.     @Override
  181.     public void notify(final EventInterface event) throws RemoteException
  182.     {
  183.         try
  184.         {
  185.             if (event.getType().equals(Network.ANIMATION_GTU_ADD_EVENT))
  186.             {
  187.                 // schedule the addition of the GTU to prevent it from not having an operational plan
  188.                 LaneBasedGTU gtu = (LaneBasedGTU) event.getContent();
  189.                 this.simulator.scheduleEventNow(this, this, "animateGTU", new Object[] {gtu});
  190.             }
  191.             else if (event.getType().equals(Network.ANIMATION_GTU_REMOVE_EVENT))
  192.             {
  193.                 LaneBasedGTU gtu = (LaneBasedGTU) event.getContent();
  194.                 if (this.animatedGTUs.containsKey(gtu))
  195.                 {
  196.                     this.animatedGTUs.get(gtu).destroy();
  197.                     this.animatedGTUs.remove(gtu);
  198.                 }
  199.             }
  200.             else if (event.getType().equals(Network.ANIMATION_OBJECT_ADD_EVENT))
  201.             {
  202.                 ObjectInterface object = (ObjectInterface) event.getContent();
  203.                 animateStaticObject(object);
  204.             }
  205.             else if (event.getType().equals(Network.ANIMATION_OBJECT_REMOVE_EVENT))
  206.             {
  207.                 ObjectInterface object = (ObjectInterface) event.getContent();
  208.                 if (this.animatedObjects.containsKey(object))
  209.                 {
  210.                     this.animatedObjects.get(object).destroy();
  211.                     this.animatedObjects.remove(object);
  212.                 }
  213.             }
  214.             else if (event.getType().equals(Network.ANIMATION_GENERATOR_ADD_EVENT))
  215.             {
  216.                 GtuGenerator gtuGenerator = (GtuGenerator) event.getContent();
  217.                 animateGTUGenerator(gtuGenerator);
  218.             }
  219.             else if (event.getType().equals(Network.ANIMATION_GENERATOR_REMOVE_EVENT))
  220.             {
  221.                 // TODO: change the way generators are animated
  222.             }
  223.         }
  224.         catch (NamingException | SimRuntimeException exception)
  225.         {
  226.             CategoryLogger.always().error(exception, "Exception while updating network animation.");
  227.         }
  228.     }

  229.     /**
  230.      * Draw the GTU (scheduled method).
  231.      * @param gtu LaneBasedGTU; the GTU to draw
  232.      */
  233.     protected void animateGTU(final LaneBasedGTU gtu)
  234.     {
  235.         try
  236.         {
  237.             Renderable2D<LaneBasedGTU> gtuAnimation = new DefaultCarAnimation(gtu, this.simulator, this.gtuColorer);
  238.             this.animatedGTUs.put(gtu, gtuAnimation);
  239.         }
  240.         catch (RemoteException | NamingException exception)
  241.         {
  242.             gtu.getSimulator().getLogger().always().error(exception, "Exception while drawing GTU.");
  243.         }
  244.     }

  245.     /**
  246.      * Draw the static object.
  247.      * @param object ObjectInterface; the object to draw
  248.      */
  249.     protected void animateStaticObject(final ObjectInterface object)
  250.     {
  251.         try
  252.         {
  253.             if (object instanceof SinkSensor)
  254.             {
  255.                 SinkSensor sensor = (SinkSensor) object;
  256.                 // Renderable2D<SinkSensor> objectAnimation = new SinkAnimation(sensor, this.simulator);
  257.                 Renderable2D<SingleSensor> objectAnimation =
  258.                         new SensorAnimation(sensor, sensor.getLongitudinalPosition(), this.simulator, Color.YELLOW);
  259.                 this.animatedObjects.put(object, objectAnimation);
  260.             }
  261.             else if (object instanceof DestinationSensor)
  262.             {
  263.                 DestinationSensor sensor = (DestinationSensor) object;
  264.                 // Renderable2D<DestinationSensor> objectAnimation = new DestinationAnimation(sensor, this.simulator);
  265.                 Renderable2D<SingleSensor> objectAnimation =
  266.                         new SensorAnimation(sensor, sensor.getLongitudinalPosition(), this.simulator, Color.ORANGE);
  267.                 this.animatedObjects.put(object, objectAnimation);
  268.             }
  269.             else if (object instanceof SingleSensor)
  270.             {
  271.                 SingleSensor sensor = (SingleSensor) object;
  272.                 Renderable2D<SingleSensor> objectAnimation =
  273.                         new SensorAnimation(sensor, sensor.getLongitudinalPosition(), this.simulator, Color.GREEN);
  274.                 this.animatedObjects.put(object, objectAnimation);
  275.             }
  276.             else if (object instanceof Conflict)
  277.             {
  278.                 Conflict conflict = (Conflict) object;
  279.                 Renderable2D<Conflict> objectAnimation = new ConflictAnimation(conflict, this.simulator);
  280.                 this.animatedObjects.put(object, objectAnimation);
  281.             }
  282.             else if (object instanceof SpeedSign)
  283.             {
  284.                 SpeedSign speedSign = (SpeedSign) object;
  285.                 Renderable2D<SpeedSign> objectAnimation = new SpeedSignAnimation(speedSign, this.simulator);
  286.                 this.animatedObjects.put(object, objectAnimation);
  287.             }
  288.             else if (object instanceof BusStop)
  289.             {
  290.                 BusStop busStop = (BusStop) object;
  291.                 Renderable2D<BusStop> objectAnimation = new BusStopAnimation(busStop, this.simulator);
  292.                 this.animatedObjects.put(object, objectAnimation);
  293.             }
  294.         }
  295.         catch (RemoteException | NamingException exception)
  296.         {
  297.             CategoryLogger.always().error(exception, "Exception while drawing Object of class ObjectInterface.");
  298.         }
  299.     }

  300.     /**
  301.      * Draw the GTUGenerator.
  302.      * @param gtuGenerator GtuGenerator; the GTUGenerator to draw
  303.      */
  304.     protected void animateGTUGenerator(final GtuGenerator gtuGenerator)
  305.     {
  306.         // TODO: default animation of GTU generator
  307.     }

  308. }