ExtendedDataType.java
package org.opentrafficsim.kpi.sampling.data;
import org.djunits.unit.AbsoluteLinearUnit;
import org.djunits.unit.Unit;
import org.djunits.value.vdouble.scalar.base.DoubleScalar;
import org.djunits.value.vdouble.scalar.base.DoubleScalarAbs;
import org.djunits.value.vdouble.scalar.base.DoubleScalarRel;
import org.djunits.value.vdouble.scalar.base.DoubleScalarRelWithAbs;
import org.djunits.value.vfloat.scalar.base.FloatScalar;
import org.djunits.value.vfloat.scalar.base.FloatScalarAbs;
import org.djunits.value.vfloat.scalar.base.FloatScalarRel;
import org.djunits.value.vfloat.scalar.base.FloatScalarRelWithAbs;
import org.djutils.exceptions.Throw;
import org.opentrafficsim.kpi.interfaces.GtuData;
import org.opentrafficsim.kpi.sampling.DataType;
/**
* Type class to define different types of data by which trajectories can be extended beyond the basic t, x, v, a. Extend this
* class to define a new data type. Extended data types are defined with 3 generic types. {@code <T>} is the type of a single
* scalar value, {@code <O>} is the output type of the whole trajectory, e.g. {@code List<Double>} or {@code FloatLengthVector},
* and {@code <S>} is the storage type by which the data is gathered, e.g. {@code List<Double>} or {@code float[]}.
* <p>
* Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <T> type of value
* @param <O> output type
* @param <S> storage type
* @param <G> GTU data type
*/
public abstract class ExtendedDataType<T, O, S, G extends GtuData> extends DataType<T, G>
{
/**
* Constructor.
* @param id id
* @param description description
* @param type type class
*/
public ExtendedDataType(final String id, final String description, final Class<T> type)
{
super(id, description, type);
}
/**
* Returns the current value of the GTU.
* @param gtu GTU
* @return current value of the GTU
*/
@Override
public abstract T getValue(G gtu);
/**
* Returns an updated list/array/vector of the storage type, including a new value at given index.
* @param storage storage
* @param index index to store next value
* @param value value to add
* @return updated list/array/vector of the storage type, including a new value at given index
*/
public abstract S setValue(S storage, int index, T value);
/**
* Returns a specific output value. This is used to store extended data types as generic file, i.e. text file.
* @param output output
* @param index index of value to return
* @return the i'th output value o
*/
public abstract T getOutputValue(O output, int index);
/**
* Returns a specific storage value. This is used to bypass conversion to the output type when trajectories are cut.
* @param storage storage
* @param index index of value to return
* @return the i'th output value
*/
public abstract T getStorageValue(S storage, int index);
/**
* Returns an initial storage object.
* @return initial storage object
*/
public abstract S initializeStorage();
/**
* Convert storage type to output type.
* @param storage stored data
* @param size size of trajectory
* @return converted output
*/
public abstract O convert(S storage, int size);
/**
* Parses a stored string representation to original type.
* @param string stored string representation
* @return value in original type
*/
public abstract T parseValue(String string);
/**
* Interpolate value between two measured values. The default implementation takes a linear interpolation over time for
* {@link DoubleScalar}, {@link FloatScalar}, {@link Double} and {@link Float}, or the closest value in time otherwise.
* @param value0 first value
* @param value1 second value
* @param f interpolation fraction
* @param <AU> unit of value, if values are {@code DoubleScalar}
* @param <RU> the corresponding relative unit
* @param <R> the relative double type
* @param <RA> the relative double type belonging to the absolute type
* @param <A> the absolute double type
* @param <FR> the relative float type
* @param <FRA> the relative float type belonging to the absolute type
* @param <FA> the absolute float type
* @return interpolated value
*/
@SuppressWarnings({"unchecked", "checkstyle:designforextension"})
public <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, R extends DoubleScalarRel<RU, R>,
RA extends DoubleScalarRelWithAbs<AU, A, RU, RA>, A extends DoubleScalarAbs<AU, A, RU, RA>,
FR extends FloatScalarRel<RU, FR>, FRA extends FloatScalarRelWithAbs<AU, FA, RU, FRA>,
FA extends FloatScalarAbs<AU, FA, RU, FRA>> T interpolate(final T value0, final T value1, final double f)
{
Throw.whenNull(value0, "Values to interpolate may not be null.");
Throw.whenNull(value1, "Values to interpolate may not be null.");
if (value0 instanceof DoubleScalarRel<?, ?>)
{
return (T) DoubleScalarRel.interpolate((R) value0, (R) value1, f);
}
if (value0 instanceof DoubleScalarAbs<?, ?, ?, ?>)
{
return (T) DoubleScalarAbs.interpolate((A) value0, (A) value1, f);
}
if (value0 instanceof FloatScalarRel<?, ?>)
{
return (T) FloatScalarRel.interpolate((FR) value0, (FR) value1, (float) f);
}
if (value0 instanceof FloatScalarAbs<?, ?, ?, ?>)
{
return (T) FloatScalarAbs.interpolate((FA) value0, (FA) value1, (float) f);
}
if (value0 instanceof Double)
{
return (T) (Double) ((Double) value0 * (1.0 - f) + (Double) value1 * f);
}
if (value0 instanceof Float)
{
return (T) (Float) (float) ((Float) value0 * (1.0 - f) + (Float) value1 * f);
}
if (f < 0.5)
{
return value0;
}
return value1;
}
@Override
public String toString()
{
return "ExtendedDataType [id=" + getId() + ", description=" + getDescription() + "]";
}
}