package org.opentrafficsim.graphs;
import java.util.ArrayList;
import java.util.List;
import org.djunits.unit.LengthUnit;
import org.djunits.unit.TimeUnit;
import org.djunits.value.StorageType;
import org.djunits.value.ValueException;
import org.djunits.value.vdouble.scalar.DoubleScalarInterface;
import org.djunits.value.vdouble.vector.MutablePositionVector;
import org.djunits.value.vdouble.vector.MutableTimeVector;
import org.opentrafficsim.road.network.lane.Lane;
import org.opentrafficsim.simulationengine.OTSSimulationException;
/**
* Speed contour plot.
*
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* $LastChangedDate: 2015-09-03 13:38:01 +0200 (Thu, 03 Sep 2015) $, @version $Revision: 1378 $, by $Author: averbraeck $,
* initial version Jul 29, 2014
* @author Peter Knoppers
*/
public class SpeedContourPlot extends ContourPlot
{
/** */
private static final long serialVersionUID = 20140729L;
/**
* Create a new SpeedContourPlot.
* @param caption String; text to show above the SpeedContourPlot
* @param path List<Lane>; the series of Lanes that will provide the data for this TrajectoryPlot
* @throws OTSSimulationException in case of problems initializing the graph
*/
public SpeedContourPlot(final String caption, final List path) throws OTSSimulationException
{
super(caption, new Axis(INITIALLOWERTIMEBOUND, INITIALUPPERTIMEBOUND, STANDARDTIMEGRANULARITIES,
STANDARDTIMEGRANULARITIES[STANDARDINITIALTIMEGRANULARITYINDEX], "", "Time", "%.0fs"), path, 0d, 40d, 150d,
"speed %.1f km/h", "%.1f km/h", 20d);
}
/** {@inheritDoc} */
@Override
public final GraphType getGraphType()
{
return GraphType.SPEED_CONTOUR;
}
/** Storage for the total time spent in each cell. */
private ArrayList cumulativeTimes;
/** Storage for the total length traveled in each cell. */
private ArrayList cumulativeLengths;
/** {@inheritDoc} */
@Override
public final Comparable getSeriesKey(final int series)
{
return "speed";
}
/** {@inheritDoc} */
@Override
public final void extendXRange(final DoubleScalarInterface newUpperLimit)
{
if (null == this.cumulativeTimes)
{
this.cumulativeTimes = new ArrayList();
this.cumulativeLengths = new ArrayList();
}
int highestBinNeeded =
(int) Math.floor(this.getXAxis().getRelativeBin(newUpperLimit) * this.getXAxis().getCurrentGranularity()
/ this.getXAxis().getGranularities()[0]);
while (highestBinNeeded >= this.cumulativeTimes.size())
{
try
{
this.cumulativeTimes.add(new MutableTimeVector(new double[this.getYAxis().getBinCount()], TimeUnit.SECOND,
StorageType.DENSE));
this.cumulativeLengths.add(new MutablePositionVector(new double[this.getYAxis().getBinCount()],
LengthUnit.METER, StorageType.DENSE));
}
catch (ValueException exception)
{
exception.printStackTrace();
}
}
}
/** {@inheritDoc} */
@Override
public final void incrementBinData(final int timeBin, final int distanceBin, final double duration,
final double distanceCovered, final double acceleration)
{
if (timeBin < 0 || distanceBin < 0 || 0 == duration || distanceBin >= this.getYAxis().getBinCount())
{
return;
}
MutableTimeVector timeValues = this.cumulativeTimes.get(timeBin);
MutablePositionVector lengthValues = this.cumulativeLengths.get(timeBin);
try
{
timeValues.setSI(distanceBin, timeValues.getSI(distanceBin) + duration);
lengthValues.setSI(distanceBin, lengthValues.getSI(distanceBin) + distanceCovered);
}
catch (ValueException exception)
{
System.err.println("Error in incrementData:");
exception.printStackTrace();
}
}
/** {@inheritDoc} */
@Override
public final double computeZValue(final int firstTimeBin, final int endTimeBin, final int firstDistanceBin,
final int endDistanceBin)
{
double cumulativeTimeInSI = 0;
double cumulativeLengthInSI = 0;
if (firstTimeBin >= this.cumulativeTimes.size())
{
return Double.NaN;
}
try
{
for (int timeBinIndex = firstTimeBin; timeBinIndex < endTimeBin; timeBinIndex++)
{
if (timeBinIndex >= this.cumulativeTimes.size())
{
break;
}
MutableTimeVector timeValues = this.cumulativeTimes.get(timeBinIndex);
MutablePositionVector lengthValues = this.cumulativeLengths.get(timeBinIndex);
for (int distanceBinIndex = firstDistanceBin; distanceBinIndex < endDistanceBin; distanceBinIndex++)
{
cumulativeTimeInSI += timeValues.getSI(distanceBinIndex);
cumulativeLengthInSI += lengthValues.getSI(distanceBinIndex);
}
}
}
catch (ValueException exception)
{
System.err.println(String.format("Error in getZValue(timeBinRange=[%d-%d], distanceBinRange=[%d-%d]", firstTimeBin,
endTimeBin, firstDistanceBin, endDistanceBin));
exception.printStackTrace();
}
if (0 == cumulativeTimeInSI)
{
return Double.NaN;
}
return 3600d / 1000 * cumulativeLengthInSI / cumulativeTimeInSI;
}
/** {@inheritDoc} */
@Override
public final String toString()
{
return "SpeedContourPlot [cumulativeTimes.size=" + this.cumulativeTimes.size() + ", cumulativeLengths.size="
+ this.cumulativeLengths.size() + "]";
}
}