View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical;
2   
3   import java.util.LinkedHashSet;
4   import java.util.Set;
5   
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djutils.immutablecollections.ImmutableSortedSet;
8   import org.opentrafficsim.base.OtsRuntimeException;
9   import org.opentrafficsim.base.parameters.ParameterException;
10  import org.opentrafficsim.base.parameters.ParameterTypes;
11  import org.opentrafficsim.core.gtu.plan.tactical.TacticalPlanner;
12  import org.opentrafficsim.core.network.LateralDirectionality;
13  import org.opentrafficsim.core.network.route.Route;
14  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
15  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
16  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
17  import org.opentrafficsim.road.network.LaneAccessLaw;
18  import org.opentrafficsim.road.network.LaneChangeInfo;
19  import org.opentrafficsim.road.network.lane.Lane;
20  
21  /**
22   * <p>
23   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
25   * </p>
26   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
27   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
28   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
29   */
30  public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGtu, LanePerception>
31  {
32      /**
33       * Returns the car-following model.
34       * @return car following model
35       */
36      CarFollowingModel getCarFollowingModel();
37  
38      /**
39       * Selects a lane from a possible set. This set contains all viable lanes in to which a lane splits.
40       * @param from lane we come from
41       * @param lanes set of lanes possible
42       * @return preferred lane
43       * @throws ParameterException in case of a missing parameter
44       */
45      default Lane chooseLaneAtSplit(final Lane from, final Set<Lane> lanes) throws ParameterException
46      {
47          Route route = getGtu().getStrategicalPlanner().getRoute()
48                  .orElseThrow(() -> new OtsRuntimeException("Choosing lane at split without a route."));
49          Length perception = getGtu().getParameters().getParameter(ParameterTypes.LANE_STRUCTURE);
50          Set<Lane> bestRegardingRoute = new LinkedHashSet<>();
51          LaneChangeInfo bestInfo = null;
52          for (Lane lane : lanes)
53          {
54              ImmutableSortedSet<LaneChangeInfo> lcInfo =
55                      lane.getNetwork().getLaneChangeInfo(lane, route, getGtu().getType(), perception, LaneAccessLaw.LEGAL);
56              LaneChangeInfo info = lcInfo.isEmpty() ? null : lcInfo.first();
57              int comp = bestInfo == null ? (info == null ? 0 : -info.compareTo(bestInfo)) : bestInfo.compareTo(info);
58              if (comp >= 0)
59              {
60                  if (comp > 0)
61                  {
62                      bestRegardingRoute.clear();
63                      bestInfo = info;
64                  }
65                  bestRegardingRoute.add(lane);
66              }
67          }
68          if (bestRegardingRoute.size() > 1)
69          {
70              Lane rightMost = null;
71              for (Lane lane : bestRegardingRoute)
72              {
73                  rightMost = rightMost == null ? lane : mostOnSide(rightMost, lane, LateralDirectionality.RIGHT);
74              }
75              return rightMost;
76          }
77          return bestRegardingRoute.iterator().next();
78      }
79  
80      /**
81       * Returns the right-most of two lanes.
82       * @param lane1 lane 1
83       * @param lane2 lane 2
84       * @param lat lateral side
85       * @return right-most of two lanes
86       */
87      static Lane mostOnSide(final Lane lane1, final Lane lane2, final LateralDirectionality lat)
88      {
89          Length offset1 = lane1.getOffsetAtBegin().plus(lane1.getOffsetAtEnd());
90          Length offset2 = lane2.getOffsetAtBegin().plus(lane2.getOffsetAtEnd());
91          if (lat.isLeft())
92          {
93              return offset1.gt(offset2) ? lane1 : lane2;
94          }
95          return offset1.gt(offset2) ? lane2 : lane1;
96      }
97  
98  }