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