ConflictUtil.java
package org.opentrafficsim.road.gtu.lane.tactical.util;
import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.ATLEASTONE;
import static org.opentrafficsim.core.gtu.behavioralcharacteristics.AbstractParameterType.Check.POSITIVE;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import org.djunits.unit.AccelerationUnit;
import org.djunits.unit.LengthUnit;
import org.djunits.unit.TimeUnit;
import org.djunits.value.vdouble.scalar.Acceleration;
import org.djunits.value.vdouble.scalar.Duration;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.djunits.value.vdouble.scalar.Time;
import org.opentrafficsim.core.gtu.GTUException;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDouble;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDuration;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeLength;
import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
import org.opentrafficsim.road.gtu.lane.perception.headway.AbstractHeadwayGTU;
import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayConflict;
import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayStopLine;
import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
import nl.tudelft.simulation.language.Throw;
/**
* This class implements default behavior for intersection conflicts for use in tactical planners.
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 3, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
public final class ConflictUtil
{
/** Minimum time gap between events. */
public static final ParameterTypeDuration MIN_GAP = new ParameterTypeDuration("minGap", "Minimum gap for conflicts.",
new Duration(1.0, TimeUnit.SECOND), POSITIVE);
/** Multiplication factor on time for conservative assessment. */
public static final ParameterTypeDouble TIME_FACTOR = new ParameterTypeDouble("timeFactor",
"Safety factor on estimated time.", 1.25, ATLEASTONE);
/** Area before stop line where one is considered arrived at the intersection. */
public static final ParameterTypeLength STOP_AREA = new ParameterTypeLength("stopArea",
"Area before stop line where one is considered arrived at the intersection.", new Length(4, LengthUnit.METER),
POSITIVE);
/**
* Do not instantiate.
*/
private ConflictUtil()
{
//
}
/**
* Approach conflicts by applying appropriate acceleration (or deceleration). The model may yield for a vehicle even while
* having priority. Such a 'yield plan' is remembered in <tt>YieldPlans</tt>. By forwarding the same <tt>YieldPlans</tt> for
* a GTU consistency of such plans is provided. If any conflict is not accepted to pass, stopping before a more upstream
* conflict is applied if there not sufficient stopping length in between conflicts.
* @param behavioralCharacteristics behavioral characteristics
* @param conflicts set of conflicts to approach
* @param leaders leading vehicles
* @param carFollowingModel car-following model
* @param vehicleLength length of vehicle
* @param speed current speed
* @param speedLimitInfo speed limit info
* @param conflictPlans set of plans for conflict
* @return acceleration appropriate for approaching the conflicts
* @throws GTUException in case of an unsupported conflict rule
* @throws ParameterException if a parameter is not defined or out of bounds
*/
@SuppressWarnings("checkstyle:parameternumber")
public static Acceleration approachConflicts(final BehavioralCharacteristics behavioralCharacteristics,
final SortedSet<HeadwayConflict> conflicts, final SortedSet<AbstractHeadwayGTU> leaders,
final CarFollowingModel carFollowingModel, final Length vehicleLength, final Speed speed,
final SpeedLimitInfo speedLimitInfo, final ConflictPlans conflictPlans) throws GTUException, ParameterException
{
Length stopLength = behavioralCharacteristics.getParameter(ParameterTypes.S0).plus(vehicleLength);
List<Length> prevStarts = new ArrayList<>();
List<Length> prevEnds = new ArrayList<>();
Acceleration a = new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
conflictPlans.cleanYieldPlans();
for (HeadwayConflict conflict : conflicts)
{
// adjust acceleration for situations where stopping might not be required
if (conflict.isCrossing())
{
// avoid collision if crossing is occupied
a =
Acceleration.min(a, avoidCrossingCollision(behavioralCharacteristics, conflict, carFollowingModel,
speed, speedLimitInfo));
}
else
{
// follow leading GTUs on merge or split
a =
Acceleration.min(a, followConflictingLeaderOnMergeOrSplit(conflict, behavioralCharacteristics,
carFollowingModel, speed, speedLimitInfo));
}
// determine if we need to stop
boolean stop;
switch (conflict.getConflictRule())
{
case PRIORITY:
{
stop =
stopForPriorityConflict(conflict, leaders, speed, stopLength, vehicleLength,
behavioralCharacteristics, conflictPlans);
break;
}
case GIVE_WAY:
{
stop =
stopForGiveWayConflict(conflict, leaders, speed, stopLength, vehicleLength,
behavioralCharacteristics, speedLimitInfo, carFollowingModel);
break;
}
case STOP:
{
stop =
stopForStopConflict(conflict, leaders, speed, stopLength, vehicleLength, behavioralCharacteristics,
speedLimitInfo, carFollowingModel);
break;
}
case ALL_STOP:
{
stop = stopForAllStopConflict(conflict, conflictPlans);
break;
}
default:
{
throw new GTUException("Unsupported conflict rule encountered while approaching conflicts.");
}
}
// stop if required, account for upstream conflicts to keep clear
prevStarts.add(conflict.getDistance());
if (stop)
{
// stop for first conflict looking upstream of this blocked conflict that allows sufficient space
int j = 0; // most upstream conflict if not in between conflicts
for (int i = prevEnds.size() - 1; i >= 0; i--) // downstream to upstream
{
// note, at this point prevStarts contains one more conflict than prevEnds
if (prevStarts.get(i + 1).minus(prevEnds.get(i)).gt(stopLength))
{
j = i + 1;
break;
}
}
// stop for j'th conflict, further conflicts may be ignored
return Acceleration.min(a, CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed,
speedLimitInfo, prevStarts.get(j)));
}
prevEnds.add(conflict.getDistance().plus(conflict.getLength()));
}
return a;
}
/**
* Determines acceleration for following conflicting vehicles <i>on</i> a merge or split conflict.
* @param conflict merge or split conflict
* @param behavioralCharacteristics behavioral characteristics
* @param carFollowingModel car-following model
* @param speed current speed
* @param speedLimitInfo speed limit info
* @return acceleration for following conflicting vehicles <i>on</i> a merge or split conflict
* @throws ParameterException if a parameter is not given or out of bounds
*/
private static Acceleration followConflictingLeaderOnMergeOrSplit(final HeadwayConflict conflict,
final BehavioralCharacteristics behavioralCharacteristics, final CarFollowingModel carFollowingModel,
final Speed speed, final SpeedLimitInfo speedLimitInfo) throws ParameterException
{
// ignore if no conflicting GTU's
if (conflict.getDownstreamConflictingGTUs().isEmpty())
{
return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
}
// get the most upstream GTU to consider
AbstractHeadwayGTU c = conflict.getDownstreamConflictingGTUs().first();
if (c.isAhead())
{
// conflict GTU completely downstream of conflict (i.e. regular car-following, ignore here)
return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
}
// conflict GTU (partially) on the conflict
// TODO plus? confused about rear overlap for two other things... tailway?
// {@formatter:off}
// ______________________________________________
// ___ virtual headway | ___ |
// |___|(-----------------------)|___|(vehicle from south, on lane from south)
// _____________________________|_______|________
// / /
// / /
// {@formatter:on}
Length virtualHeadway = conflict.getDistance().plus(c.getOverlapRear());
// follow leader
SortedMap<Length, Speed> leaders = new TreeMap<>();
leaders.put(virtualHeadway, c.getSpeed());
Acceleration a = carFollowingModel.followingAcceleration(behavioralCharacteristics, speed, speedLimitInfo, leaders);
// if conflicting GTU is partially upstream of the conflict and at (near) stand-still, stop for the conflict rather than
// following the tail of the conflicting GTU
if (conflict.isMerge() && virtualHeadway.lt(conflict.getDistance()))
{
// {@formatter:off}
/*
* ______________________________________________
* ___ stop for conflict | |
* |___|(--------------------)| ___ |
* _____________________________|__/ /_|________
* / /__/ /
* / /
*/
// {@formatter:on}
Acceleration aStop =
CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed, speedLimitInfo, conflict
.getDistance());
a = Acceleration.max(a, aStop); // max, which ever allows the largest acceleration
}
return a;
}
/**
* Determines an acceleration required to avoid a collision with GTUs <i>on</i> a crossing conflict.
* @param behavioralCharacteristics behavioral characteristics
* @param conflict conflict
* @param carFollowingModel car-following model
* @param speed current speed
* @param speedLimitInfo speed limit info
* @return acceleration required to avoid a collision
* @throws ParameterException if parameter is not defined
*/
private static Acceleration avoidCrossingCollision(final BehavioralCharacteristics behavioralCharacteristics,
final HeadwayConflict conflict, final CarFollowingModel carFollowingModel, final Speed speed,
final SpeedLimitInfo speedLimitInfo) throws ParameterException
{
if (!conflict.getDownstreamConflictingGTUs().isEmpty())
{
AbstractHeadwayGTU conflictingGTU = conflict.getDownstreamConflictingGTUs().first();
if (conflictingGTU.isParallel())
{
Length distance =
conflictingGTU.getOverlapRear().abs().plus(conflictingGTU.getOverlap()).plus(
conflictingGTU.getOverlapFront().abs());
AnticipationInfo ttcC =
AnticipationInfo.anticipateMovement(distance, conflictingGTU.getSpeed(), Acceleration.ZERO);
AnticipationInfo tteO =
AnticipationInfo.anticipateMovementFreeAcceleration(conflict.getDistance(), speed,
behavioralCharacteristics, carFollowingModel, speedLimitInfo, new Duration(.5, TimeUnit.SI));
// enter before cleared
if (tteO.getDuration().lt(ttcC.getDuration()))
{
if (!conflictingGTU.getSpeed().eq(Speed.ZERO))
{
// solve parabolic speed profile s = v*t + .5*a*t*t, a =
double acc =
2 * (conflict.getDistance().si - speed.si * ttcC.getDuration().si)
/ (ttcC.getDuration().si * ttcC.getDuration().si);
// time till zero speed > time to avoid conflict?
if (speed.si / -acc > ttcC.getDuration().si)
{
return new Acceleration(acc, AccelerationUnit.SI);
}
}
// conflicting vehicle on conflict at stand-still, or will reach zero speed ourselves
return CarFollowingUtil.stop(carFollowingModel, behavioralCharacteristics, speed, speedLimitInfo,
conflict.getDistance());
}
}
}
return new Acceleration(Double.POSITIVE_INFINITY, AccelerationUnit.SI);
}
/**
* Approach a priority conflict. Stopping is applied to give way to conflicting traffic in case congestion is present on the
* own lane.
* @param conflict conflict to approach
* @param leaders leading vehicles in own lane
* @param speed current speed
* @param stopLength length required to stop
* @param vehicleLength vehicle length
* @param behavioralCharacteristics behavioral characteristics
* @param yieldPlans set of plans for yielding with priority
* @return whether to stop for this conflict
* @throws ParameterException if parameter B is not defined
*/
private static boolean stopForPriorityConflict(final HeadwayConflict conflict,
final SortedSet<AbstractHeadwayGTU> leaders, final Speed speed, final Length stopLength, final Length vehicleLength,
final BehavioralCharacteristics behavioralCharacteristics, final ConflictPlans yieldPlans) throws ParameterException
{
if (leaders.isEmpty() || conflict.getUpstreamConflictingGTUs().isEmpty()
|| conflict.getUpstreamConflictingGTUs().first().getSpeed().eq(Speed.ZERO))
{
// no leader, and no (stand-still) conflicting vehicle
return false;
}
// time till enter; will enter the conflict
// AnticipationInfo tteO = AnticipationInfo.anticipateMovement(conflict.getDistance(), speed, Acceleration.ZERO);
// time till clear; will clear the conflict
Length distance = conflict.getDistance().plus(vehicleLength);
if (conflict.isCrossing())
{
// merge is cleared at start, crossing at end
distance = distance.plus(conflict.getLength());
}
AnticipationInfo ttcC = AnticipationInfo.anticipateMovement(distance, speed, Acceleration.ZERO);
// time till passible; downstream vehicle will leave sufficient room (stopLength) after the conflict
distance = distance.minus(leaders.first().getDistance()).minus(vehicleLength).plus(stopLength);
AnticipationInfo ttpD = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
// MOTUS uses tteO instead of ttcC, but especially for long conflicts this is not appropriate
if (ttpD.getDuration().ge(ttcC.getDuration())) // might block conflict
{
// TODO respond to indicator / expected turn, will the conflict vehicle go over the conflict? Consider further
// conflicting vehicles if not.
// at a merge, the vehicle that was yielded for may become the leader, do not yield (but follow)
if (yieldPlans.isYieldPlan(conflict, leaders.first()))
{
return false;
}
// In MOTUS these rules are different. Drivers tagged themselves as conflict blocked, which others used. In OTS
// this information is (rightfully) not available. This tagging is simplified to 'speed = 0'.
if (!yieldPlans.isYieldPlan(conflict, conflict.getUpstreamConflictingGTUs().first())
&& conflict.getUpstreamConflictingGTUs().first().getSpeed().equals(Speed.ZERO))
{
Acceleration b = behavioralCharacteristics.getParameter(ParameterTypes.B);
Acceleration bReq =
new Acceleration(.5 * speed.si * speed.si / conflict.getDistance().si, AccelerationUnit.SI);
if (bReq.gt(b))
{
// cannot stop safely, do not initiate plan
return false;
}
}
// initiate or keep plan to yield
yieldPlans.setYieldPlan(conflict, conflict.getUpstreamConflictingGTUs().first());
return true;
}
// if the yield was a plan, it is abandoned as the conflict will not be blocked
return false;
}
/**
* Approach a give-way conflict.
* @param conflict conflict
* @param leaders leaders
* @param speed current speed
* @param stopLength length required when stopped
* @param vehicleLength vehicle length
* @param behavioralCharacteristics behavioral characteristics
* @param speedLimitInfo speed limit info
* @param carFollowingModel car-following model
* @return whether to stop for this conflict
* @throws ParameterException if a parameter is not defined
*/
@SuppressWarnings("checkstyle:parameternumber")
private static boolean stopForGiveWayConflict(final HeadwayConflict conflict,
final SortedSet<AbstractHeadwayGTU> leaders, final Speed speed, final Length stopLength, final Length vehicleLength,
final BehavioralCharacteristics behavioralCharacteristics, final SpeedLimitInfo speedLimitInfo,
final CarFollowingModel carFollowingModel) throws ParameterException
{
// TODO disregard conflicting vehicles with a route not over the conflict, if known through e.d. indicator
// Get data independent of conflicting vehicle
// parameters
Acceleration b = behavioralCharacteristics.getParameter(ParameterTypes.B).multiplyBy(-1.0);
double f = behavioralCharacteristics.getParameter(TIME_FACTOR);
Duration gap = behavioralCharacteristics.getParameter(MIN_GAP);
// time till conflict is cleared
Length distance = conflict.getDistance().plus(vehicleLength);
if (conflict.isCrossing())
{
// merge is cleared at start, crossing at end
distance = distance.plus(conflict.getLength());
}
AnticipationInfo ttcO =
AnticipationInfo.anticipateMovementFreeAcceleration(distance, speed, behavioralCharacteristics,
carFollowingModel, speedLimitInfo, new Duration(.5, TimeUnit.SI));
// time till downstream vehicle will make the conflict passible, under constant speed or safe deceleration
AnticipationInfo ttpDz = null;
AnticipationInfo ttpDs = null;
if (conflict.isCrossing())
{
if (!leaders.isEmpty())
{
distance =
conflict.getDistance().minus(leaders.first().getDistance()).plus(conflict.getLength()).plus(stopLength);
ttpDz = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
ttpDs = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), b);
}
else
{
// no leader so conflict is passible within a duration of 0
ttpDz = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
ttpDs = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
}
}
// Get list of conflicting vehicles' information
ArrayList<Length> confDistance = new ArrayList<>();
ArrayList<Speed> confSpeed = new ArrayList<>();
ArrayList<Acceleration> confAcceleration = new ArrayList<>();
if (!conflict.getUpstreamConflictingGTUs().isEmpty())
{
for (AbstractHeadwayGTU conflictingVehicle : conflict.getUpstreamConflictingGTUs())
{
confDistance.add(conflictingVehicle.getDistance());
confSpeed.add(conflictingVehicle.getSpeed());
confAcceleration.add(conflictingVehicle.getAcceleration());
}
}
else
{
// none within visibility, assume a conflicting vehicle just outside of visibility driving at speed limit
confDistance.add(conflict.getConflictingVisibility());
confSpeed.add(conflict.getConflictingSpeedLimit());
confAcceleration.add(Acceleration.ZERO);
}
// Loop over conflicting vehicles
for (int i = 0; i < confDistance.size(); i++)
{
// time till conflict vehicle will enter, under current acceleration and safe deceleration
AnticipationInfo tteCc =
AnticipationInfo.anticipateMovement(confDistance.get(i), confSpeed.get(i), confAcceleration.get(i));
AnticipationInfo tteCs = AnticipationInfo.anticipateMovement(confDistance.get(i), confSpeed.get(i), b);
// check gap
if (conflict.isMerge())
{
// Merge, will be each others followers, add time to overcome speed difference
double vConflicting = confSpeed.get(i).si + b.si * ttcO.getDuration().si;
double vSelf = ttcO.getEndSpeed().si;
double speedDiff = vConflicting - vSelf;
speedDiff = speedDiff > 0 ? speedDiff : 0;
Duration additionalTime = new Duration(speedDiff / -b.si, TimeUnit.SI);
// 1) will clear the conflict before the conflict vehicle will enter
// 2) conflict vehicle has sufficient time to adjust speed
if (ttcO.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
|| ttcO.getDuration().plus(additionalTime).multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
{
return true;
}
}
else if (conflict.isCrossing())
{
// Crossing, stop if order of events is not ok
// 1) downstream vehicle must supply sufficient space before conflict vehicle will enter
// 2) must clear the conflict before the conflict vehicle will enter
// 3) if leader decelerates with b, conflict vehicle should be able to safely delay entering conflict
if (ttpDz.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
|| ttcO.getDuration().multiplyBy(f).plus(gap).gt(tteCc.getDuration())
|| ttpDs.getDuration().multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
{
return true;
}
}
else
{
throw new RuntimeException("Conflict is of unknown type " + conflict.getConflictType()
+ ", which is not merge nor crossing.");
}
}
// No conflict vehicle triggered stopping
return false;
}
/**
* Approach a stop conflict. Currently this is equal to approaching a give-way conflict.
* @param conflict conflict
* @param leaders leaders
* @param speed current speed
* @param stopLength length required when stopped
* @param vehicleLength vehicle length
* @param behavioralCharacteristics behavioral characteristics
* @param speedLimitInfo speed limit info
* @param carFollowingModel car-following model
* @return whether to stop for this conflict
* @throws ParameterException if a parameter is not defined
*/
@SuppressWarnings("checkstyle:parameternumber")
private static boolean stopForStopConflict(final HeadwayConflict conflict, final SortedSet<AbstractHeadwayGTU> leaders,
final Speed speed, final Length stopLength, final Length vehicleLength,
final BehavioralCharacteristics behavioralCharacteristics, final SpeedLimitInfo speedLimitInfo,
final CarFollowingModel carFollowingModel) throws ParameterException
{
return stopForGiveWayConflict(conflict, leaders, speed, stopLength, vehicleLength, behavioralCharacteristics,
speedLimitInfo, carFollowingModel);
}
/**
* Approach an all-stop conflict.
* @param conflict conflict to approach
* @param conflictPlans set of plans for conflict
* @return whether to stop for this conflict
*/
private static boolean stopForAllStopConflict(final HeadwayConflict conflict, final ConflictPlans conflictPlans)
{
// TODO all-stop behavior
if (conflictPlans.isStopPhaseRun(conflict.getStopLine()))
{
return false;
}
return false;
}
/**
* Holds the tactical plans of a driver considering conflicts. These are remembered for consistency. Set of yield plans in
* case of having priority. Such plans are remembered to get consistency. For instance, if the decision is made to yield as
* current deceleration suggests it's safe to do so, but the trajectory for stopping in front of the conflict results in
* deceleration slightly above what is considered safe deceleration, the plan should not be abandoned. Decelerations above
* what is considered safe deceleration may result due to numerical overshoot or other factor coming into play in
* car-following models. Many other examples exist where a driver sticks to a certain plan.
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 7, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
public static final class ConflictPlans implements Serializable
{
/** */
private static final long serialVersionUID = 20160811L;
/** Set of current plans. */
private final Map<String, String> yieldPlans = new HashMap<>();
/** Set of conflicts that are still actively considered for a yield plan. */
private final Set<String> activeYieldPlans = new HashSet<>();
/** Phases of navigating an all-stop intersection per intersection. */
private final HashMap<String, StopPhase> stopPhases = new HashMap<>();
/** Estimated arrival times of vehicles at all-stop intersection. */
private final HashMap<String, Time> arrivalTimes = new HashMap<>();
/**
* Returns whether a plan exists for yielding at the conflict for the given conflict GTU.
* @param conflict conflict
* @param gtu conflicting GTU
* @return whether a plan exists for yielding at the conflict for the given conflict GTU
*/
boolean isYieldPlan(final HeadwayConflict conflict, final AbstractHeadwayGTU gtu)
{
return this.yieldPlans.containsKey(conflict.getId())
&& this.yieldPlans.get(conflict.getId()).equals(gtu.getId());
}
/**
* Sets or maintains the plan to yield at the conflict for the given conflict RSU.
* @param conflict conflict to yield at
* @param gtu conflicting GTU
*/
void setYieldPlan(final HeadwayConflict conflict, final AbstractHeadwayGTU gtu)
{
this.yieldPlans.put(conflict.getId(), gtu.getId());
this.activeYieldPlans.add(conflict.getId());
}
/**
* Clears any yield plan that was no longer kept active in the last evaluation of conflicts.
*/
void cleanYieldPlans()
{
// remove any plan not represented in activePlans
Iterator<String> iterator = this.yieldPlans.keySet().iterator();
while (iterator.hasNext())
{
String conflictId = iterator.next();
if (!this.activeYieldPlans.contains(conflictId))
{
iterator.remove();
}
}
// clear the activePlans for the next consideration of conflicts
this.activeYieldPlans.clear();
}
/**
* Sets the estimated arrival time of a GTU.
* @param gtu GTU
* @param time estimated arrival time
*/
void setArrivalTime(final AbstractHeadwayGTU gtu, final Time time)
{
this.arrivalTimes.put(gtu.getId(), time);
}
/**
* Returns the estimated arrival time of given GTU.
* @param gtu GTU
* @return estimated arrival time of given GTU
*/
Time getArrivalTime(final AbstractHeadwayGTU gtu)
{
return this.arrivalTimes.get(gtu.getId());
}
/**
* Sets the current phase to 'approach' for the given stop line.
* @param stopLine stop line
*/
void setStopPhaseApproach(final HeadwayStopLine stopLine)
{
this.stopPhases.put(stopLine.getId(), StopPhase.APPROACH);
}
/**
* Sets the current phase to 'yield' for the given stop line.
* @param stopLine stop line
* @throws RuntimeException if the phase was not set to approach before
*/
void setStopPhaseYield(final HeadwayStopLine stopLine)
{
Throw.when(!this.stopPhases.containsKey(stopLine.getId())
|| !this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH), RuntimeException.class,
"Yield stop phase is set for stop line that was not approached.");
this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
}
/**
* Sets the current phase to 'run' for the given stop line.
* @param stopLine stop line
* @throws RuntimeException if the phase was not set to approach before
*/
void setStopPhaseRun(final HeadwayStopLine stopLine)
{
Throw.when(!this.stopPhases.containsKey(stopLine.getId()), RuntimeException.class,
"Run stop phase is set for stop line that was not approached.");
this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
}
/**
* @param stopLine stop line
* @return whether the current phase is 'approach' for the given stop line
*/
boolean isStopPhaseApproach(final HeadwayStopLine stopLine)
{
return this.stopPhases.containsKey(stopLine.getId())
&& this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH);
}
/**
* @param stopLine stop line
* @return whether the current phase is 'yield' for the given stop line
*/
boolean isStopPhaseYield(final HeadwayStopLine stopLine)
{
return this.stopPhases.containsKey(stopLine.getId())
&& this.stopPhases.get(stopLine.getId()).equals(StopPhase.YIELD);
}
/**
* @param stopLine stop line
* @return whether the current phase is 'run' for the given stop line
*/
boolean isStopPhaseRun(final HeadwayStopLine stopLine)
{
return this.stopPhases.containsKey(stopLine.getId())
&& this.stopPhases.get(stopLine.getId()).equals(StopPhase.RUN);
}
/** {@inheritDoc} */
@Override
public String toString()
{
return "ConflictPlans";
}
}
/**
* Phases of navigating an all-stop intersection.
* <p>
* Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
* <p>
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Jun 30, 2016 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
* @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
* @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
*/
private static enum StopPhase
{
/** Approaching stop intersection. */
APPROACH,
/** Yielding for stop intersection. */
YIELD,
/** Running over stop intersection. */
RUN;
}
}