AbstractSpaceTimePlot.java

  1. package org.opentrafficsim.draw.graphs;

  2. import org.djunits.value.vdouble.scalar.Duration;
  3. import org.djunits.value.vdouble.scalar.Length;
  4. import org.djunits.value.vdouble.scalar.Time;
  5. import org.jfree.chart.JFreeChart;
  6. import org.jfree.chart.event.AxisChangeEvent;
  7. import org.jfree.chart.event.AxisChangeListener;
  8. import org.jfree.chart.plot.XYPlot;

  9. /**
  10.  * Plots with space-time. This class adds some zoom control, where a user can manually select a zoom range, or the plot
  11.  * automatically zooms over the entire space range, and either the entire or some most recent fixed period in time.
  12.  * <p>
  13.  * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  14.  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  15.  * </p>
  16.  * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
  17.  * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
  18.  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
  19.  */
  20. public abstract class AbstractSpaceTimePlot extends AbstractBoundedPlot
  21. {

  22.     /** Initial end time of plot. */
  23.     private final Time initialEnd;

  24.     /** Whether to update the axes. */
  25.     private boolean autoBoundAxes = true;

  26.     /** Whether to disable auto bounds on the axes on any change on the axes. */
  27.     private boolean virtualAutoBounds = false;

  28.     /** Fixed domain range. */
  29.     private Double fixedDomainRange = null;

  30.     /**
  31.      * Constructor.
  32.      * @param caption String; caption
  33.      * @param updateInterval Duration; regular update interval (simulation time)
  34.      * @param scheduler PlotScheduler; scheduler.
  35.      * @param delay Duration; amount of time that chart runs behind simulation to prevent gaps in the charted data
  36.      * @param initialEnd Time; initial end time of plots, will be expanded if simulation time exceeds it
  37.      */
  38.     public AbstractSpaceTimePlot(final String caption, final Duration updateInterval, final PlotScheduler scheduler,
  39.             final Duration delay, final Time initialEnd)
  40.     {
  41.         super(scheduler, caption, updateInterval, delay);
  42.         this.initialEnd = initialEnd;
  43.     }

  44.     /** {@inheritDoc} */
  45.     @Override
  46.     protected void setChart(final JFreeChart chart)
  47.     {
  48.         super.setChart(chart);
  49.         XYPlot xyPlot = chart.getXYPlot();
  50.         setLowerRangeBound(0.0);
  51.         setUpperRangeBound(getEndLocation().si);
  52.         setLowerDomainBound(0.0);
  53.         setUpperDomainBound(this.initialEnd.si);
  54.         setAutoBounds(xyPlot);
  55.         // axis listeners to enable/disable auto zoom
  56.         xyPlot.getDomainAxis().addChangeListener(new AxisChangeListener()
  57.         {
  58.             /** {@inheritDoc} */
  59.             @SuppressWarnings("synthetic-access")
  60.             @Override
  61.             public void axisChanged(final AxisChangeEvent event)
  62.             {
  63.                 if (!AbstractSpaceTimePlot.this.virtualAutoBounds)
  64.                 {
  65.                     // the axis was changed, but not by a command from this class, auto bounds should be disabled
  66.                     AbstractSpaceTimePlot.this.autoBoundAxes = false;
  67.                 }
  68.             }
  69.         });
  70.     }

  71.     /** {@inheritDoc} */
  72.     @Override
  73.     protected void update()
  74.     {
  75.         if (getUpdateTime() != null && this.initialEnd != null)
  76.         {
  77.             setUpperDomainBound(Math.max(getUpdateTime().si, this.initialEnd.si));
  78.         }
  79.         if (this.autoBoundAxes && getChart() != null) // null during construction
  80.         {
  81.             setAutoBounds(getChart().getXYPlot());
  82.         }
  83.         super.update();
  84.     }

  85.     /**
  86.      * Update the fixed-ness of the domain range.
  87.      * @param fixed boolean; if true; the domain range will not update when new data becomes available; if false; the domain
  88.      *            range will update to show newly available data
  89.      */
  90.     public void updateFixedDomainRange(final boolean fixed)
  91.     {
  92.         this.fixedDomainRange = fixed ? getChart().getXYPlot().getDomainAxis().getRange().getLength() : null;
  93.         notifyPlotChange();
  94.     }

  95.     /**
  96.      * Sets the auto bounds without deactivating auto bounds through the axis change listener. This is used to initialize the
  97.      * plot, and to update the plot when time is increased.
  98.      * @param plot XYPlot; plot with default zoom-all bounds set
  99.      */
  100.     private void setAutoBounds(final XYPlot plot)
  101.     {
  102.         // disables the axis change listener from registering a user input that is actually an update of bounds as the time
  103.         // increases
  104.         this.virtualAutoBounds = true;
  105.         if (this.fixedDomainRange != null && getUpdateTime().si > 0.0)
  106.         {
  107.             plot.getDomainAxis().setRange(Math.max(getUpdateTime().si - this.fixedDomainRange, 0.0), getUpdateTime().si);
  108.         }
  109.         else
  110.         {
  111.             super.setAutoBoundDomain(plot); // super to skip setting autoBoundAxes = true
  112.         }
  113.         super.setAutoBoundRange(plot); // super to skip setting autoBoundAxes = true
  114.         this.virtualAutoBounds = false;
  115.     }

  116.     /** {@inheritDoc} This implementation overrides to enable it's own form of auto bounds. */
  117.     @Override
  118.     public final void setAutoBoundDomain(final XYPlot plot)
  119.     {
  120.         super.setAutoBoundDomain(plot);
  121.         this.autoBoundAxes = true;
  122.     }

  123.     /** {@inheritDoc} This implementation overrides to enable it's own form of auto bounds. */
  124.     @Override
  125.     public final void setAutoBoundRange(final XYPlot plot)
  126.     {
  127.         super.setAutoBoundRange(plot);
  128.         this.autoBoundAxes = true;
  129.     }

  130.     /**
  131.      * Returns the total path length.
  132.      * @return Length; total path length
  133.      */
  134.     protected abstract Length getEndLocation();

  135. }