AbstractWrappableAnimation.java

  1. package org.opentrafficsim.simulationengine;

  2. import java.awt.Container;
  3. import java.awt.Dimension;
  4. import java.awt.Frame;
  5. import java.awt.Rectangle;
  6. import java.awt.geom.Rectangle2D;
  7. import java.io.Serializable;
  8. import java.rmi.RemoteException;
  9. import java.util.ArrayList;
  10. import java.util.List;

  11. import javax.naming.NamingException;
  12. import javax.swing.WindowConstants;
  13. import javax.vecmath.Point3d;

  14. import org.djunits.value.vdouble.scalar.Duration;
  15. import org.djunits.value.vdouble.scalar.Time;
  16. import org.opentrafficsim.base.modelproperties.Property;
  17. import org.opentrafficsim.base.modelproperties.PropertyException;
  18. import org.opentrafficsim.core.dsol.OTSModelInterface;
  19. import org.opentrafficsim.core.gtu.animation.DefaultSwitchableGTUColorer;
  20. import org.opentrafficsim.core.gtu.animation.GTUColorer;
  21. import org.opentrafficsim.core.network.Link;
  22. import org.opentrafficsim.core.network.NetworkException;
  23. import org.opentrafficsim.gui.OTSAnimationPanel;
  24. import org.opentrafficsim.gui.SimulatorFrame;

  25. import nl.tudelft.simulation.dsol.SimRuntimeException;
  26. import nl.tudelft.simulation.dsol.animation.Locatable;
  27. import nl.tudelft.simulation.language.d3.BoundingBox;
  28. import nl.tudelft.simulation.language.d3.DirectedPoint;

  29. /**
  30.  * <p>
  31.  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  32.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  33.  * <p>
  34.  * $LastChangedDate: 2016-12-11 14:07:37 +0100 (Sun, 11 Dec 2016) $, @version $Revision: 2838 $, by $Author: averbraeck $,
  35.  * initial version Jun 18, 2015 <br>
  36.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  37.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  38.  */
  39. public abstract class AbstractWrappableAnimation implements WrappableAnimation, Serializable
  40. {
  41.     /** */
  42.     private static final long serialVersionUID = 20150000L;

  43.     /** The properties exhibited by this simulation. */
  44.     @SuppressWarnings("checkstyle:visibilitymodifier")
  45.     protected List<Property<?>> properties = new ArrayList<>();

  46.     /** The properties after (possible) editing by the user. */
  47.     @SuppressWarnings("checkstyle:visibilitymodifier")
  48.     protected List<Property<?>> savedUserModifiedProperties;

  49.     /** Use EXIT_ON_CLOSE when true, DISPOSE_ON_CLOSE when false on closing of the window. */
  50.     @SuppressWarnings("checkstyle:visibilitymodifier")
  51.     protected boolean exitOnClose;

  52.     /** The tabbed panel so other tabs can be added by the classes that extend this class. */
  53.     @SuppressWarnings("checkstyle:visibilitymodifier")
  54.     protected OTSAnimationPanel panel;

  55.     /** Save the startTime for restarting the simulation. */
  56.     private Time savedStartTime;

  57.     /** Save the startTime for restarting the simulation. */
  58.     private Duration savedWarmupPeriod;

  59.     /** Save the runLength for restarting the simulation. */
  60.     private Duration savedRunLength;
  61.    
  62.     /** the model. */
  63.     private OTSModelInterface model;

  64.     /**
  65.      * Build the animator.
  66.      * @param startTime Time; the start time
  67.      * @param warmupPeriod Duration; the warm up period
  68.      * @param runLength Duration; the duration of the simulation / animation
  69.      * @param otsModel OTSModelInterface; the simulation model
  70.      * @return SimpleAnimator; a newly constructed animator
  71.      * @throws SimRuntimeException on ???
  72.      * @throws NamingException when context for the animation cannot be created
  73.      * @throws PropertyException when one of the user modified properties has the empty string as key
  74.      */
  75.     @SuppressWarnings("checkstyle:designforextension")
  76.     protected SimpleAnimator buildSimpleAnimator(final Time startTime, final Duration warmupPeriod, final Duration runLength,
  77.             final OTSModelInterface otsModel) throws SimRuntimeException, NamingException, PropertyException
  78.     {
  79.         return new SimpleAnimator(startTime, warmupPeriod, runLength, otsModel);
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     @SuppressWarnings("checkstyle:designforextension")
  84.     public SimpleAnimator buildAnimator(final Time startTime, final Duration warmupPeriod, final Duration runLength,
  85.             final List<Property<?>> userModifiedProperties, final Rectangle rect, final boolean eoc)
  86.             throws SimRuntimeException, NamingException, OTSSimulationException, PropertyException
  87.     {
  88.         this.savedUserModifiedProperties = userModifiedProperties;
  89.         this.exitOnClose = eoc;

  90.         this.savedStartTime = startTime;
  91.         this.savedWarmupPeriod = warmupPeriod;
  92.         this.savedRunLength = runLength;

  93.         GTUColorer colorer = new DefaultSwitchableGTUColorer();
  94.         this.model = makeModel(colorer);

  95.         if (null == this.model)
  96.         {
  97.             return null; // Happens when the user cancels the file open dialog in the OpenStreetMap demo.
  98.         }

  99.         final SimpleAnimator simulator = buildSimpleAnimator(startTime, warmupPeriod, runLength, this.model);
  100.         try
  101.         {
  102.             this.panel = new OTSAnimationPanel(makeAnimationRectangle(), new Dimension(1024, 768), simulator, this, colorer);
  103.         }
  104.         catch (RemoteException exception)
  105.         {
  106.             throw new SimRuntimeException(exception);
  107.         }

  108.         addAnimationToggles();
  109.         addTabs(simulator);

  110.         SimulatorFrame frame = new SimulatorFrame(shortName(), this.panel);
  111.         if (rect != null)
  112.         {
  113.             frame.setBounds(rect);
  114.         }
  115.         else
  116.         {
  117.             frame.setExtendedState(Frame.MAXIMIZED_BOTH);
  118.         }

  119.         frame.setDefaultCloseOperation(this.exitOnClose ? WindowConstants.EXIT_ON_CLOSE : WindowConstants.DISPOSE_ON_CLOSE);

  120.         return simulator;
  121.     }

  122.     /**
  123.      * Make additional tabs in the main simulation window.
  124.      * @param simulator SimpleSimulatorInterface; the simulator
  125.      * @throws OTSSimulationException in case the chart, axes or legend cannot be generated
  126.      * @throws PropertyException when one of the user modified properties has the empty string as key
  127.      */
  128.     protected void addTabs(final SimpleSimulatorInterface simulator) throws OTSSimulationException, PropertyException
  129.     {
  130.         // Override this method to add custom tabs
  131.     }

  132.     /**
  133.      * Placeholder method to place animation buttons or to show/hide classes on the animation.
  134.      */
  135.     @SuppressWarnings("checkstyle:designforextension")
  136.     protected void addAnimationToggles()
  137.     {
  138.         // overridable placeholder to place animation buttons or to show/hide classes on the animation.
  139.     }

  140.     /**
  141.      * Add a button for toggling an animatable class on or off.
  142.      * @param name the name of the button
  143.      * @param locatableClass the class for which the button holds (e.g., GTU.class)
  144.      * @param iconPath the path to the 24x24 icon to display
  145.      * @param toolTipText the tool tip text to show when hovering over the button
  146.      * @param initiallyVisible whether the class is initially shown or not
  147.      */
  148.     public final void addToggleAnimationButton(final String name, final Class<? extends Locatable> locatableClass,
  149.             final String iconPath, final String toolTipText, final boolean initiallyVisible)
  150.     {
  151.         this.panel.addToggleAnimationButton(name, locatableClass, iconPath, toolTipText, initiallyVisible);
  152.     }

  153.     /**
  154.      * Add a button for toggling an animatable class on or off.
  155.      * @param name the name of the button
  156.      * @param locatableClass the class for which the button holds (e.g., GTU.class)
  157.      * @param toolTipText the tool tip text to show when hovering over the button
  158.      * @param initiallyVisible whether the class is initially shown or not
  159.      */
  160.     public final void addToggleAnimationButton(final String name, final Class<? extends Locatable> locatableClass,
  161.             final String toolTipText, final boolean initiallyVisible)
  162.     {
  163.         this.panel.addToggleAnimationButton(name, locatableClass, toolTipText, initiallyVisible);
  164.     }

  165.     /**
  166.      * Set a class to be shown in the animation to true.
  167.      * @param locatableClass the class for which the animation has to be shown.
  168.      */
  169.     public final void showAnimationClass(final Class<? extends Locatable> locatableClass)
  170.     {
  171.         this.panel.getAnimationPanel().showClass(locatableClass);
  172.     }

  173.     /**
  174.      * Set a class to be hidden in the animation to true.
  175.      * @param locatableClass the class for which the animation has to be hidden.
  176.      */
  177.     public final void hideAnimationClass(final Class<? extends Locatable> locatableClass)
  178.     {
  179.         this.panel.getAnimationPanel().hideClass(locatableClass);
  180.     }

  181.     /**
  182.      * Toggle a class to be displayed in the animation to its reverse value.
  183.      * @param locatableClass the class for which a visible animation has to be turned off or vice versa.
  184.      */
  185.     public final void toggleAnimationClass(final Class<? extends Locatable> locatableClass)
  186.     {
  187.         this.panel.getAnimationPanel().toggleClass(locatableClass);
  188.     }

  189.     /**
  190.      * @param colorer the GTU colorer to use.
  191.      * @return the demo model. Don't forget to keep a local copy.
  192.      * @throws OTSSimulationException in case the construction of the model fails
  193.      */
  194.     protected abstract OTSModelInterface makeModel(GTUColorer colorer) throws OTSSimulationException;

  195.     /**
  196.      * Return the initial 'home' extent for the animation. The 'Home' button returns to this extent. Override this method when a
  197.      * smaller or larger part of the infra should be shown. In the default setting, all currently visible objects are shown.
  198.      * @return the initial and 'home' rectangle for the animation.
  199.      */
  200.     @SuppressWarnings("checkstyle:designforextension")
  201.     protected Rectangle2D makeAnimationRectangle()
  202.     {
  203.         double minX = Double.MAX_VALUE;
  204.         double maxX = -Double.MAX_VALUE;
  205.         double minY = Double.MAX_VALUE;
  206.         double maxY = -Double.MAX_VALUE;
  207.         Point3d p3dL = new Point3d();
  208.         Point3d p3dU = new Point3d();
  209.         try
  210.         {
  211.             for (Link link : this.model.getNetwork().getLinkMap().values())
  212.             {
  213.                 DirectedPoint l = link.getLocation();
  214.                 BoundingBox b = new BoundingBox(link.getBounds());
  215.                 b.getLower(p3dL);
  216.                 b.getUpper(p3dU);
  217.                 minX = Math.min(minX, l.x + Math.min(p3dL.x, p3dU.x));
  218.                 minY = Math.min(minY, l.y + Math.min(p3dL.y, p3dU.y));
  219.                 maxX = Math.max(maxX, l.x + Math.max(p3dL.x, p3dU.x));
  220.                 maxY = Math.max(maxY, l.y + Math.max(p3dL.y, p3dU.y));
  221.             }
  222.         }
  223.         catch (Exception e)
  224.         {
  225.             // ignore
  226.         }
  227.        
  228.         minX = minX - 0.05 * Math.abs(minX);
  229.         minY = minY - 0.05 * Math.abs(minY);
  230.         maxX = maxX + 0.05 * Math.abs(maxX);
  231.         maxY = maxY + 0.05 * Math.abs(maxY);
  232.        
  233.         return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
  234.     }

  235.     /** {@inheritDoc} */
  236.     @Override
  237.     public final ArrayList<Property<?>> getProperties()
  238.     {
  239.         return new ArrayList<Property<?>>(this.properties);
  240.     }

  241.     /** {@inheritDoc} */
  242.     @Override
  243.     public final SimpleSimulatorInterface rebuildSimulator(final Rectangle rect)
  244.             throws SimRuntimeException, NetworkException, NamingException, OTSSimulationException, PropertyException
  245.     {
  246.         return buildAnimator(this.savedStartTime, this.savedWarmupPeriod, this.savedRunLength, this.savedUserModifiedProperties,
  247.                 rect, this.exitOnClose);
  248.     }

  249.     /** {@inheritDoc} */
  250.     @Override
  251.     public final List<Property<?>> getUserModifiedProperties()
  252.     {
  253.         return this.savedUserModifiedProperties;
  254.     }

  255.     /** {@inheritDoc} */
  256.     @Override
  257.     @SuppressWarnings("checkstyle:designforextension")
  258.     public void stopTimersThreads()
  259.     {
  260.         if (this.panel != null && this.panel.getStatusBar() != null)
  261.         {
  262.             this.panel.getStatusBar().cancelTimer();
  263.         }
  264.         this.panel = null;
  265.     }

  266.     /**
  267.      * @return panel
  268.      */
  269.     public final OTSAnimationPanel getPanel()
  270.     {
  271.         return this.panel;
  272.     }

  273.     /**
  274.      * Add a tab to the simulation window. This method can not be called from constructModel because the TabbedPane has not yet
  275.      * been constructed at that time; recommended: override addTabs and call this method from there.
  276.      * @param index int; index of the new tab; use <code>getTabCount()</code> to obtain the valid range
  277.      * @param caption String; caption of the new tab
  278.      * @param container Container; content of the new tab
  279.      */
  280.     public final void addTab(final int index, final String caption, final Container container)
  281.     {
  282.         this.panel.getTabbedPane().addTab(index, caption, container);
  283.     }

  284.     /**
  285.      * Report the current number of tabs in the simulation window. This method can not be called from constructModel because the
  286.      * TabbedPane has not yet been constructed at that time; recommended: override addTabs and call this method from there.
  287.      * @return int; the number of tabs in the simulation window
  288.      */
  289.     public final int getTabCount()
  290.     {
  291.         return this.panel.getTabbedPane().getTabCount();
  292.     }

  293. }