View Javadoc
1   package org.opentrafficsim.draw.graphs;
2   
3   import org.djunits.value.vdouble.scalar.Duration;
4   import org.djunits.value.vdouble.scalar.Length;
5   import org.djunits.value.vdouble.scalar.Time;
6   import org.jfree.chart.JFreeChart;
7   import org.jfree.chart.event.AxisChangeEvent;
8   import org.jfree.chart.event.AxisChangeListener;
9   import org.jfree.chart.plot.XYPlot;
10  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
11  
12  /**
13   * Plots with space-time. This class adds some zoom control, where a user can manually select a zoom range, or the plot
14   * automatically zooms over the entire space range, and either the entire or some most recent fixed period in time.
15   * <p>
16   * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
17   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
18   * <p>
19   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 okt. 2018 <br>
20   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
21   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
22   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
23   */
24  public abstract class AbstractSpaceTimePlot extends AbstractBoundedPlot
25  {
26  
27      /** Initial end time of plot. */
28      private final Time initialEnd;
29  
30      /** Whether to update the axes. */
31      private boolean autoBoundAxes = true;
32  
33      /** Whether to disable auto bounds on the axes on any change on the axes. */
34      private boolean virtualAutoBounds = false;
35  
36      /** Fixed domain range. */
37      private Double fixedDomainRange = null;
38  
39      /**
40       * Constructor.
41       * @param caption String; caption
42       * @param updateInterval Duration; regular update interval (simulation time)
43       * @param simulator OTSSimulatorInterface; simulator
44       * @param delay Duration; amount of time that chart runs behind simulation to prevent gaps in the charted data
45       * @param initialEnd Time; initial end time of plots, will be expanded if simulation time exceeds it
46       */
47      public AbstractSpaceTimePlot(final String caption, final Duration updateInterval, final OTSSimulatorInterface simulator,
48              final Duration delay, final Time initialEnd)
49      {
50          super(simulator, caption, updateInterval, delay);
51          this.initialEnd = initialEnd;
52      }
53  
54      /** {@inheritDoc} */
55      @Override
56      protected void setChart(final JFreeChart chart)
57      {
58          super.setChart(chart);
59          XYPlot xyPlot = chart.getXYPlot();
60          setLowerRangeBound(0.0);
61          setUpperRangeBound(getEndLocation().si);
62          setLowerDomainBound(0.0);
63          setUpperDomainBound(this.initialEnd.si);
64          setAutoBounds(xyPlot);
65          // axis listeners to enable/disable auto zoom
66          xyPlot.getDomainAxis().addChangeListener(new AxisChangeListener()
67          {
68              /** {@inheritDoc} */
69              @SuppressWarnings("synthetic-access")
70              @Override
71              public void axisChanged(final AxisChangeEvent event)
72              {
73                  if (!AbstractSpaceTimePlot.this.virtualAutoBounds)
74                  {
75                      // the axis was changed, but not by a command from this class, auto bounds should be disabled
76                      AbstractSpaceTimePlot.this.autoBoundAxes = false;
77                  }
78              }
79          });
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      protected void update()
85      {
86          if (getUpdateTime() != null && this.initialEnd != null)
87          {
88              setUpperDomainBound(Math.max(getUpdateTime().si, this.initialEnd.si));
89          }
90          if (this.autoBoundAxes && getChart() != null) // null during construction
91          {
92              setAutoBounds(getChart().getXYPlot());
93          }
94          super.update();
95      }
96  
97      /**
98       * Update the fixed-ness of the domain range.
99       * @param fixed boolean; if true; the domain range will not update when new data becomes available; if false; the domain
100      *            range will update to show newly available data
101      */
102     public void updateFixedDomainRange(final boolean fixed)
103     {
104         this.fixedDomainRange = fixed ? getChart().getXYPlot().getDomainAxis().getRange().getLength() : null;
105         notifyPlotChange();
106     }
107 
108     /**
109      * Sets the auto bounds without deactivating auto bounds through the axis change listener. This is used to initialize the
110      * plot, and to update the plot when time is increased.
111      * @param plot XYPlot; plot with default zoom-all bounds set
112      */
113     private void setAutoBounds(final XYPlot plot)
114     {
115         // disables the axis change listener from registering a user input that is actually an update of bounds as the time
116         // increases
117         this.virtualAutoBounds = true;
118         if (this.fixedDomainRange != null && getUpdateTime().si > 0.0)
119         {
120             plot.getDomainAxis().setRange(Math.max(getUpdateTime().si - this.fixedDomainRange, 0.0), getUpdateTime().si);
121         }
122         else
123         {
124             super.setAutoBoundDomain(plot); // super to skip setting autoBoundAxes = true
125         }
126         super.setAutoBoundRange(plot); // super to skip setting autoBoundAxes = true
127         this.virtualAutoBounds = false;
128     }
129 
130     /** {@inheritDoc} This implementation overrides to enable it's own form of auto bounds. */
131     @Override
132     public final void setAutoBoundDomain(final XYPlot plot)
133     {
134         super.setAutoBoundDomain(plot);
135         this.autoBoundAxes = true;
136     }
137 
138     /** {@inheritDoc} This implementation overrides to enable it's own form of auto bounds. */
139     @Override
140     public final void setAutoBoundRange(final XYPlot plot)
141     {
142         super.setAutoBoundRange(plot);
143         this.autoBoundAxes = true;
144     }
145 
146     /**
147      * Returns the total path length.
148      * @return Length; total path length
149      */
150     protected abstract Length getEndLocation();
151 
152 }