View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.util.Set;
4   import java.util.SortedSet;
5   
6   import org.djunits.value.vdouble.scalar.Duration;
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djunits.value.vdouble.scalar.Speed;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.core.gtu.GtuException;
11  import org.opentrafficsim.core.network.NetworkException;
12  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.Placement;
13  import org.opentrafficsim.road.gtu.generator.LaneBasedGtuGenerator.RoomChecker;
14  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedGtuCharacteristics;
15  import org.opentrafficsim.road.gtu.perception.object.PerceivedGtu;
16  import org.opentrafficsim.road.gtu.tactical.util.SpeedLimitUtil;
17  import org.opentrafficsim.road.network.Lane;
18  import org.opentrafficsim.road.network.LanePosition;
19  import org.opentrafficsim.road.network.speed.SpeedLimits;
20  
21  /**
22   * This class places GTU's behind the leader at the desired headway (i.e. CF, car-following) and the speed of the leader, but no
23   * further than the GTU could have traveled at the desired speed during the time since the desired arrival. With multiple
24   * leaders, the leader that causes the most upstream following position is used.
25   * <p>
26   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * </p>
29   * @author Alexander Verbraeck
30   * @author Peter Knoppers
31   * @author Wouter Schakel
32   */
33  public class CfRoomChecker implements RoomChecker
34  {
35  
36      /**
37       * Constructor.
38       */
39      public CfRoomChecker()
40      {
41          //
42      }
43  
44      @Override
45      public Placement canPlace(final SortedSet<PerceivedGtu> leaders, final LaneBasedGtuCharacteristics characteristics,
46              final Duration since, final LanePosition initialPosition) throws NetworkException, GtuException
47      {
48          SpeedLimits speedLimits = initialPosition.lane().getSpeedLimits(characteristics.getGtuType());
49          Throw.when(speedLimits == null, IllegalStateException.class, "No speed limit could be determined for GtuType %s.",
50                  characteristics.getGtuType());
51          Speed desiredSpeed = characteristics.getStrategicalPlannerFactory()
52                  .peekDesiredSpeed(characteristics.getGtuType(), speedLimits, characteristics.getMaximumSpeed())
53                  .orElse(SpeedLimitUtil.getDesiredSpeedProxy(speedLimits, characteristics.getMaximumSpeed()));
54          if (leaders.isEmpty())
55          {
56              // no leaders: free
57              return new Placement(desiredSpeed, initialPosition);
58          }
59          Length desiredHeadway =
60                  characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), desiredSpeed)
61                          .orElseGet(() -> desiredSpeed.times(Duration.ofSI(1.0))); // 1s def.
62          // loop leaders and determine most downstream location that would be ok
63          Length move = Length.POSITIVE_INFINITY;
64          Speed generationSpeed = desiredSpeed;
65          for (PerceivedGtu leader : leaders)
66          {
67              Speed speed = Speed.min(desiredSpeed, leader.getSpeed());
68              Length headway =
69                      characteristics.getStrategicalPlannerFactory().peekDesiredHeadway(characteristics.getGtuType(), speed)
70                              .orElseGet(() -> desiredSpeed.times(Duration.ofSI(1.0))); // 1s def.
71              double f = headwayFactor(desiredSpeed, desiredHeadway, speed, headway, leader.getLength());
72              headway = headway.times(f);
73              if (leader.getDistance().lt(headway))
74              {
75                  // not enough space to this leader
76                  return Placement.NO;
77              }
78              Length moveToLeader = leader.getDistance().minus(headway);
79              if (moveToLeader.lt(move))
80              {
81                  move = moveToLeader;
82                  generationSpeed = speed;
83              }
84          }
85          move = Length.min(move, since.times(generationSpeed)); // max distance the GTU would have moved until now
86          // move this distance
87          LanePosition generationPosition;
88          if (move.eq0())
89          {
90              generationPosition = initialPosition;
91          }
92          else
93          {
94              Lane lane = initialPosition.lane();
95              Length position = initialPosition.position();
96              Length canMove = lane.getLength().minus(position);
97              while (canMove.lt(move))
98              {
99                  Set<Lane> down = lane.nextLanes(characteristics.getGtuType());
100                 if (down.size() != 1)
101                 {
102                     // split or dead-end, fall back to original position
103                     return new Placement(generationSpeed, initialPosition);
104                 }
105                 else
106                 {
107                     move = move.minus(canMove);
108                     lane = down.iterator().next();
109                     position = Length.ZERO;
110                     canMove = lane.getLength();
111                 }
112             }
113             position = position.plus(move);
114             generationPosition = new LanePosition(lane, position);
115         }
116         return new Placement(generationSpeed, generationPosition);
117     }
118 
119     /**
120      * Returns a situation dependent headway factor to deal with spillback.
121      * @param desiredSpeed desired speed
122      * @param desiredHeadway desired headway at desired speed
123      * @param generationSpeed generation speed
124      * @param generationHeadway desired headway at generation speed
125      * @param leaderLength length of the leader
126      * @return situation dependent headway factor to deal with spillback
127      */
128     protected double headwayFactor(final Speed desiredSpeed, final Length desiredHeadway, final Speed generationSpeed,
129             final Length generationHeadway, final Length leaderLength)
130     {
131         return 1.0;
132     }
133 
134 }