AnticipationSpeed.java
package org.opentrafficsim.road.gtu.lane.perception.categories;
import java.util.function.Supplier;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.opentrafficsim.core.gtu.Gtu;
import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.Intermediate;
import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionAccumulator;
import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionCollector;
import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionFinalizer;
import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
import org.opentrafficsim.road.gtu.lane.perception.categories.AnticipationSpeed.SpeedSet;
/**
* Collector of leaders which derives an set of anticipation speeds from a lane. This includes all GTUs on the lane (current),
* all GTUs indicating left (left) and all GTUs indicating right (right).
* <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://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
*/
public class AnticipationSpeed implements PerceptionCollector<SpeedSet, LaneBasedGtu, SpeedSet>
{
/** Desired speed. */
private double desiredSpeed;
/** Look-ahead distance. */
private double x0;
/** Lane. */
private RelativeLane lane;
/**
* Constructor.
* @param desiredSpeed Speed; desired speed
* @param lookAhead Length; look-ahead distance
* @param lane RelativeLane; lane
*/
public AnticipationSpeed(final Speed desiredSpeed, final Length lookAhead, final RelativeLane lane)
{
this.desiredSpeed = desiredSpeed.si;
this.x0 = lookAhead.si;
this.lane = lane;
}
/** {@inheritDoc} */
@Override
public Supplier<SpeedSet> getIdentity()
{
return new Supplier<SpeedSet>()
{
@SuppressWarnings("synthetic-access")
@Override
public SpeedSet get()
{
SpeedSet identity = new SpeedSet();
identity.left = AnticipationSpeed.this.desiredSpeed;
identity.current = AnticipationSpeed.this.desiredSpeed;
identity.right = AnticipationSpeed.this.desiredSpeed;
return identity;
}
};
}
/** {@inheritDoc} */
@Override
public PerceptionAccumulator<LaneBasedGtu, SpeedSet> getAccumulator()
{
return new PerceptionAccumulator<LaneBasedGtu, SpeedSet>()
{
@SuppressWarnings("synthetic-access")
@Override
public Intermediate<SpeedSet> accumulate(final Intermediate<SpeedSet> intermediate, final LaneBasedGtu object,
final Length distance)
{
double v = anticipateSingle(object, distance);
if (AnticipationSpeed.this.lane.getNumLanes() < 2)
{
intermediate.getObject().current =
intermediate.getObject().current < v ? intermediate.getObject().current : v;
}
if (!AnticipationSpeed.this.lane.isCurrent())
{
if (AnticipationSpeed.this.lane.isRight())
{
if (object.getTurnIndicatorStatus().isLeft())
{
intermediate.getObject().left =
intermediate.getObject().left < v ? intermediate.getObject().left : v;
}
}
else
{
if (object.getTurnIndicatorStatus().isRight())
{
intermediate.getObject().right =
intermediate.getObject().right < v ? intermediate.getObject().right : v;
}
}
}
return intermediate;
}
};
}
/**
* Anticipate a single leader by possibly lowering the anticipation speed.
* @param gtu Gtu; GTU
* @param distance Length; distance to GTU
* @return possibly lowered anticipation speed
*/
final double anticipateSingle(final Gtu gtu, final Length distance)
{
Speed speed = gtu.getSpeed();
double v = speed == null ? 0.0 : speed.si;
if (v > this.desiredSpeed || distance.si > this.x0)
{
return this.desiredSpeed;
}
double f = distance.si / this.x0;
f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
return (1 - f) * v + f * this.desiredSpeed;
}
/** {@inheritDoc} */
@Override
public PerceptionFinalizer<SpeedSet, SpeedSet> getFinalizer()
{
return new PerceptionFinalizer<SpeedSet, SpeedSet>()
{
@Override
public SpeedSet collect(final SpeedSet intermediate)
{
return intermediate;
}
};
}
/**
* Class to contain info from 1 lane, regarding 3 lanes.
* <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://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
*/
public static class SpeedSet
{
/** Speed regarding the left lane. */
private double left = Double.POSITIVE_INFINITY;
/** Speed regarding the current lane. */
private double current = Double.POSITIVE_INFINITY;
/** Speed regarding the right lane. */
private double right = Double.POSITIVE_INFINITY;
/**
* Returns the speed regarding the left lane.
* @return Speed; speed regarding the left lane
*/
public final Speed getLeft()
{
return Speed.instantiateSI(this.left);
}
/**
* Returns the speed regarding the current lane.
* @return Speed; speed regarding the current lane
*/
public final Speed getCurrent()
{
return Speed.instantiateSI(this.current);
}
/**
* Returns the speed regarding the right lane.
* @return Speed; speed regarding the right lane
*/
public final Speed getRight()
{
return Speed.instantiateSI(this.right);
}
}
}