DefaultAnimationFactory.java

  1. package org.opentrafficsim.animation;

  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.Event;
  9. import org.djutils.event.EventListener;
  10. import org.djutils.logger.CategoryLogger;
  11. import org.opentrafficsim.animation.data.AnimationBusStopData;
  12. import org.opentrafficsim.animation.data.AnimationConflictData;
  13. import org.opentrafficsim.animation.data.AnimationCrossSectionElementData;
  14. import org.opentrafficsim.animation.data.AnimationGtuData;
  15. import org.opentrafficsim.animation.data.AnimationGtuGeneratorPositionData;
  16. import org.opentrafficsim.animation.data.AnimationLaneData;
  17. import org.opentrafficsim.animation.data.AnimationLaneDetectorData;
  18. import org.opentrafficsim.animation.data.AnimationLinkData;
  19. import org.opentrafficsim.animation.data.AnimationNodeData;
  20. import org.opentrafficsim.animation.data.AnimationPriorityData;
  21. import org.opentrafficsim.animation.data.AnimationShoulderData;
  22. import org.opentrafficsim.animation.data.AnimationSpeedSignData;
  23. import org.opentrafficsim.animation.data.AnimationStripeData;
  24. import org.opentrafficsim.animation.data.AnimationTrafficLightData;
  25. import org.opentrafficsim.animation.data.AnimationTrafficLightDetectorData;
  26. import org.opentrafficsim.animation.gtu.colorer.GtuColorer;
  27. import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
  28. import org.opentrafficsim.core.gtu.Gtu;
  29. import org.opentrafficsim.core.gtu.GtuGenerator.GtuGeneratorPosition;
  30. import org.opentrafficsim.core.network.Link;
  31. import org.opentrafficsim.core.network.Network;
  32. import org.opentrafficsim.core.network.Node;
  33. import org.opentrafficsim.core.object.LocatedObject;
  34. import org.opentrafficsim.core.object.NonLocatedObject;
  35. import org.opentrafficsim.draw.OtsDrawingException;
  36. import org.opentrafficsim.draw.gtu.DefaultCarAnimation;
  37. import org.opentrafficsim.draw.gtu.DefaultCarAnimation.GtuData;
  38. import org.opentrafficsim.draw.network.LinkAnimation;
  39. import org.opentrafficsim.draw.network.NodeAnimation;
  40. import org.opentrafficsim.draw.road.BusStopAnimation;
  41. import org.opentrafficsim.draw.road.BusStopAnimation.BusStopData;
  42. import org.opentrafficsim.draw.road.ConflictAnimation;
  43. import org.opentrafficsim.draw.road.ConflictAnimation.ConflictData;
  44. import org.opentrafficsim.draw.road.CrossSectionElementAnimation;
  45. import org.opentrafficsim.draw.road.GtuGeneratorPositionAnimation;
  46. import org.opentrafficsim.draw.road.GtuGeneratorPositionAnimation.GtuGeneratorPositionData;
  47. import org.opentrafficsim.draw.road.LaneAnimation;
  48. import org.opentrafficsim.draw.road.LaneDetectorAnimation;
  49. import org.opentrafficsim.draw.road.LaneDetectorAnimation.LaneDetectorData;
  50. import org.opentrafficsim.draw.road.PriorityAnimation;
  51. import org.opentrafficsim.draw.road.SpeedSignAnimation;
  52. import org.opentrafficsim.draw.road.SpeedSignAnimation.SpeedSignData;
  53. import org.opentrafficsim.draw.road.StripeAnimation;
  54. import org.opentrafficsim.draw.road.TrafficLightAnimation;
  55. import org.opentrafficsim.draw.road.TrafficLightAnimation.TrafficLightData;
  56. import org.opentrafficsim.draw.road.TrafficLightDetectorAnimation;
  57. import org.opentrafficsim.draw.road.TrafficLightDetectorAnimation.TrafficLightDetectorData;
  58. import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator;
  59. import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
  60. import org.opentrafficsim.road.network.lane.CrossSectionElement;
  61. import org.opentrafficsim.road.network.lane.CrossSectionLink;
  62. import org.opentrafficsim.road.network.lane.Lane;
  63. import org.opentrafficsim.road.network.lane.Shoulder;
  64. import org.opentrafficsim.road.network.lane.Stripe;
  65. import org.opentrafficsim.road.network.lane.conflict.Conflict;
  66. import org.opentrafficsim.road.network.lane.object.BusStop;
  67. import org.opentrafficsim.road.network.lane.object.SpeedSign;
  68. import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
  69. import org.opentrafficsim.road.network.lane.object.detector.SinkDetector;
  70. import org.opentrafficsim.road.network.lane.object.detector.TrafficLightDetector;
  71. import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;

  72. import nl.tudelft.simulation.dsol.SimRuntimeException;
  73. import nl.tudelft.simulation.dsol.animation.Locatable;
  74. import nl.tudelft.simulation.dsol.animation.d2.Renderable2d;
  75. import nl.tudelft.simulation.naming.context.Contextualized;

  76. /**
  77.  * DefaultAnimationFactory.
  78.  * <p>
  79.  * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  80.  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  81.  * </p>
  82.  * @author <a href="https://github.com/averbraeck" target="_blank">Alexander Verbraeck</a>
  83.  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
  84.  */
  85. public class DefaultAnimationFactory implements EventListener
  86. {
  87.     /** */
  88.     private static final long serialVersionUID = 20230129L;

  89.     /** The network. */
  90.     private final Network network;

  91.     /** The simulator. */
  92.     private final OtsSimulatorInterface simulator;

  93.     /** GTU colorer. */
  94.     private final GtuColorer gtuColorer;

  95.     /** Rendered gtus. */
  96.     private Map<LaneBasedGtu, Renderable2d<GtuData>> animatedGTUs = Collections.synchronizedMap(new LinkedHashMap<>());

  97.     /** Rendered located objects. */
  98.     private Map<Locatable, Renderable2d<?>> animatedLocatedObjects = Collections.synchronizedMap(new LinkedHashMap<>());

  99.     /** Rendered non-located objects. */
  100.     private Map<NonLocatedObject, Renderable2d<?>> animatedNonLocatedObjects =
  101.             Collections.synchronizedMap(new LinkedHashMap<>());

  102.     /**
  103.      * Creates animations for nodes, links and lanes. The class will subscribe to the network and listen to changes, so the
  104.      * adding and removing of GTUs and Objects is animated correctly.
  105.      * @param network Network; the network
  106.      * @param gtuColorer GtuColorer; GTU colorer
  107.      * @param animateNetwork boolean; whether to animate the current network objects
  108.      * @throws OtsDrawingException on drawing error
  109.      */
  110.     protected DefaultAnimationFactory(final Network network, final GtuColorer gtuColorer, final boolean animateNetwork)
  111.             throws OtsDrawingException
  112.     {
  113.         this.network = network;
  114.         this.simulator = network.getSimulator();
  115.         this.gtuColorer = gtuColorer;

  116.         // subscribe to adding and removing events
  117.         network.addListener(this, Network.GTU_ADD_EVENT);
  118.         network.addListener(this, Network.GTU_REMOVE_EVENT);
  119.         network.addListener(this, Network.OBJECT_ADD_EVENT);
  120.         network.addListener(this, Network.OBJECT_REMOVE_EVENT);
  121.         network.addListener(this, Network.NONLOCATED_OBJECT_ADD_EVENT);
  122.         network.addListener(this, Network.NONLOCATED_OBJECT_REMOVE_EVENT);

  123.         // model the current infrastructure
  124.         try
  125.         {
  126.             if (animateNetwork)
  127.             {
  128.                 for (Node node : network.getNodeMap().values())
  129.                 {
  130.                     new NodeAnimation(new AnimationNodeData(node), this.simulator);
  131.                 }
  132.                 for (Link link : network.getLinkMap().values())
  133.                 {
  134.                     new LinkAnimation(new AnimationLinkData(link), this.simulator, 0.5f);
  135.                     if (link instanceof CrossSectionLink cLink)
  136.                     {
  137.                         for (CrossSectionElement element : cLink.getCrossSectionElementList())
  138.                         {
  139.                             if (element instanceof Shoulder shoulder)
  140.                             {
  141.                                 new CrossSectionElementAnimation<>(new AnimationShoulderData(shoulder), this.simulator,
  142.                                         Color.DARK_GRAY);
  143.                             }
  144.                             else if (element instanceof Lane lane)
  145.                             {
  146.                                 new LaneAnimation(new AnimationLaneData(lane), this.simulator, Color.GRAY.brighter());
  147.                             }
  148.                             else if (element instanceof Stripe stripe)
  149.                             {
  150.                                 new StripeAnimation(new AnimationStripeData(stripe), this.simulator);
  151.                             }
  152.                             else
  153.                             {
  154.                                 new CrossSectionElementAnimation<>(new AnimationCrossSectionElementData<>(element),
  155.                                         this.simulator, Color.DARK_GRAY);
  156.                             }
  157.                         }
  158.                         if (!cLink.getPriority().isNone())
  159.                         {
  160.                             new PriorityAnimation(new AnimationPriorityData(cLink), this.simulator);
  161.                         }
  162.                     }
  163.                 }
  164.             }

  165.             for (Gtu gtu : network.getGTUs())
  166.             {
  167.                 GtuData gtuData = new AnimationGtuData(this.gtuColorer, (LaneBasedGtu) gtu);
  168.                 Renderable2d<GtuData> gtuAnimation = new DefaultCarAnimation(gtuData, this.simulator);
  169.                 this.animatedGTUs.put((LaneBasedGtu) gtu, gtuAnimation);
  170.             }

  171.             for (LocatedObject object : network.getObjectMap().values())
  172.             {
  173.                 animateLocatedObject(object);
  174.             }

  175.             for (NonLocatedObject object : network.getNonLocatedObjectMap().values())
  176.             {
  177.                 animateNonLocatedObject(object);
  178.             }
  179.         }
  180.         catch (RemoteException | NamingException exception)
  181.         {
  182.             throw new OtsDrawingException("Exception while creating network animation.", exception);
  183.         }

  184.     }

  185.     /**
  186.      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is not read from XML. The class will
  187.      * subscribe to the network and listen to changes, so the adding and removing of GTUs and Objects is animated correctly.
  188.      * @param network Network; the network
  189.      * @param contextualized Contextualized; context provider
  190.      * @param gtuColorer GtuColorer; GTU colorer
  191.      * @return the DefaultAnimationFactory
  192.      * @throws OtsDrawingException on drawing error
  193.      */
  194.     public static DefaultAnimationFactory animateNetwork(final Network network, final Contextualized contextualized,
  195.             final GtuColorer gtuColorer) throws OtsDrawingException
  196.     {
  197.         return new DefaultAnimationFactory(network, gtuColorer, true);
  198.     }

  199.     /**
  200.      * Creates animations for nodes, links, lanes and GTUs. This can be used if the network is read from XML. The class will
  201.      * subscribe to the network and listen to changes, so the adding and removing of GTUs and Objects is animated correctly.
  202.      * @param network Network; the network
  203.      * @param gtuColorer GtuColorer; GTU colorer
  204.      * @return the DefaultAnimationFactory
  205.      * @throws OtsDrawingException on drawing error
  206.      */
  207.     public static DefaultAnimationFactory animateXmlNetwork(final Network network, final GtuColorer gtuColorer)
  208.             throws OtsDrawingException
  209.     {
  210.         return new DefaultAnimationFactory(network, gtuColorer, false);
  211.     }

  212.     /** {@inheritDoc} */
  213.     @Override
  214.     public void notify(final Event event) throws RemoteException
  215.     {
  216.         try
  217.         {
  218.             if (event.getType().equals(Network.GTU_ADD_EVENT))
  219.             {
  220.                 // schedule the addition of the GTU to prevent it from not having an operational plan
  221.                 LaneBasedGtu gtu = (LaneBasedGtu) this.network.getGTU((String) event.getContent());
  222.                 this.simulator.scheduleEventNow(this, "animateGTU", new Object[] {gtu});
  223.             }
  224.             else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
  225.             {
  226.                 LaneBasedGtu gtu = (LaneBasedGtu) this.network.getGTU((String) event.getContent());
  227.                 if (this.animatedGTUs.containsKey(gtu))
  228.                 {
  229.                     this.animatedGTUs.get(gtu).destroy(gtu.getSimulator());
  230.                     this.animatedGTUs.remove(gtu);
  231.                 }
  232.             }
  233.             else if (event.getType().equals(Network.OBJECT_ADD_EVENT))
  234.             {
  235.                 LocatedObject object = this.network.getObjectMap().get((String) event.getContent());
  236.                 animateLocatedObject(object);
  237.             }
  238.             else if (event.getType().equals(Network.OBJECT_REMOVE_EVENT))
  239.             {
  240.                 LocatedObject object = this.network.getObjectMap().get((String) event.getContent());
  241.                 // TODO: this.animatedObjects.get(object).destroy(object.getSimulator());
  242.                 // XXX: this is now a memory leak; we don't expect static animation objects to be removed during the run
  243.                 this.animatedLocatedObjects.remove(object);
  244.             }
  245.             else if (event.getType().equals(Network.NONLOCATED_OBJECT_ADD_EVENT))
  246.             {
  247.                 NonLocatedObject object = this.network.getNonLocatedObjectMap().get((String) event.getContent());
  248.                 animateNonLocatedObject(object);
  249.             }
  250.             else if (event.getType().equals(Network.NONLOCATED_OBJECT_REMOVE_EVENT))
  251.             {
  252.                 NonLocatedObject object = this.network.getNonLocatedObjectMap().get((String) event.getContent());
  253.                 // TODO: this.animatedObjects.get(object).destroy(object.getSimulator());
  254.                 // XXX: this is now a memory leak; we don't expect static animation objects to be removed during the run
  255.                 this.animatedNonLocatedObjects.remove(object);
  256.             }
  257.         }
  258.         catch (SimRuntimeException exception)
  259.         {
  260.             CategoryLogger.always().error(exception, "Exception while updating network animation.");
  261.         }
  262.     }

  263.     /**
  264.      * Draw the GTU (scheduled method).
  265.      * @param gtu LaneBasedGtu; the GTU to draw
  266.      */
  267.     protected void animateGTU(final LaneBasedGtu gtu)
  268.     {
  269.         try
  270.         {
  271.             GtuData gtuData = new AnimationGtuData(this.gtuColorer, gtu);
  272.             Renderable2d<GtuData> gtuAnimation = new DefaultCarAnimation(gtuData, this.simulator);
  273.             this.animatedGTUs.put(gtu, gtuAnimation);
  274.         }
  275.         catch (RemoteException | NamingException exception)
  276.         {
  277.             gtu.getSimulator().getLogger().always().error(exception, "Exception while drawing GTU.");
  278.         }
  279.     }

  280.     /**
  281.      * Draw the static object.
  282.      * @param object ObjectInterface; the object to draw
  283.      */
  284.     protected void animateLocatedObject(final LocatedObject object)
  285.     {
  286.         try
  287.         {
  288.             if (object instanceof SinkDetector)
  289.             {
  290.                 SinkDetector detector = (SinkDetector) object;
  291.                 // Renderable2d<SinkSensor> objectAnimation = new SinkAnimation(detector, this.simulator);
  292.                 Renderable2d<LaneDetectorData> objectAnimation = LaneDetectorAnimation
  293.                         .ofGenericType(new AnimationLaneDetectorData(detector), this.simulator, Color.ORANGE);
  294.                 this.animatedLocatedObjects.put(object, objectAnimation);
  295.             }
  296.             else if (object instanceof TrafficLightDetector)
  297.             {
  298.                 TrafficLightDetector trafficLigthDetector = (TrafficLightDetector) object;
  299.                 Renderable2d<TrafficLightDetectorData> objectAnimation = new TrafficLightDetectorAnimation(
  300.                         new AnimationTrafficLightDetectorData(trafficLigthDetector), this.simulator);
  301.                 this.animatedLocatedObjects.put(object, objectAnimation);
  302.             }
  303.             else if (object instanceof TrafficLightDetector.StartEndDetector)
  304.             {
  305.                 // we do not draw these, as we draw the TrafficLightDetector
  306.                 return;
  307.             }
  308.             else if (object instanceof LaneDetector)
  309.             {
  310.                 LaneDetector detector = (LaneDetector) object;
  311.                 Renderable2d<LaneDetectorData> objectAnimation = LaneDetectorAnimation
  312.                         .ofGenericType(new AnimationLaneDetectorData(detector), this.simulator, Color.BLACK);
  313.                 this.animatedLocatedObjects.put(object, objectAnimation);
  314.             }
  315.             else if (object instanceof Conflict)
  316.             {
  317.                 Conflict conflict = (Conflict) object;
  318.                 Renderable2d<ConflictData> objectAnimation =
  319.                         new ConflictAnimation(new AnimationConflictData(conflict), this.simulator);
  320.                 this.animatedLocatedObjects.put(object, objectAnimation);
  321.             }
  322.             else if (object instanceof TrafficLight)
  323.             {
  324.                 TrafficLight trafficLight = (TrafficLight) object;
  325.                 Renderable2d<TrafficLightData> objectAnimation =
  326.                         new TrafficLightAnimation(new AnimationTrafficLightData(trafficLight), this.simulator);
  327.                 this.animatedLocatedObjects.put(object, objectAnimation);
  328.             }
  329.             else if (object instanceof SpeedSign)
  330.             {
  331.                 SpeedSign speedSign = (SpeedSign) object;
  332.                 Renderable2d<SpeedSignData> objectAnimation =
  333.                         new SpeedSignAnimation(new AnimationSpeedSignData(speedSign), this.simulator);
  334.                 this.animatedLocatedObjects.put(object, objectAnimation);
  335.             }
  336.             else if (object instanceof BusStop)
  337.             {
  338.                 BusStop busStop = (BusStop) object;
  339.                 Renderable2d<BusStopData> objectAnimation =
  340.                         new BusStopAnimation(new AnimationBusStopData(busStop), this.simulator);
  341.                 this.animatedLocatedObjects.put(object, objectAnimation);
  342.             }
  343.         }
  344.         catch (RemoteException | NamingException exception)
  345.         {
  346.             CategoryLogger.always().error(exception, "Exception while drawing Object of class LocatedObject.");
  347.         }
  348.     }

  349.     /**
  350.      * Draw non-located objects.
  351.      * @param object NonLocatedObject; the object to draw.
  352.      */
  353.     protected void animateNonLocatedObject(final NonLocatedObject object)
  354.     {
  355.         try
  356.         {
  357.             if (object instanceof LaneBasedGtuGenerator)
  358.             {
  359.                 LaneBasedGtuGenerator generator = (LaneBasedGtuGenerator) object;
  360.                 for (GtuGeneratorPosition position : generator.getPositions())
  361.                 {
  362.                     Renderable2d<GtuGeneratorPositionData> objectAnimation =
  363.                             new GtuGeneratorPositionAnimation(new AnimationGtuGeneratorPositionData(position), this.simulator);
  364.                     this.animatedLocatedObjects.put(position, objectAnimation);
  365.                 }
  366.             }
  367.         }
  368.         catch (RemoteException | NamingException exception)
  369.         {
  370.             CategoryLogger.always().error(exception, "Exception while drawing Object of class NonLocatedObject.");
  371.         }
  372.     }

  373. }