1   package org.opentrafficsim.road.gtu.lane.tactical;
2   
3   import java.util.Set;
4   
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.opentrafficsim.base.parameters.ParameterException;
7   import org.opentrafficsim.base.parameters.ParameterTypes;
8   import org.opentrafficsim.core.gtu.plan.tactical.TacticalPlanner;
9   import org.opentrafficsim.core.network.Link;
10  import org.opentrafficsim.core.network.Node;
11  import org.opentrafficsim.core.network.route.Route;
12  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
13  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
14  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
15  import org.opentrafficsim.road.network.lane.LaneDirection;
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGTU, LanePerception>
29  {
30      
31  
32  
33  
34      CarFollowingModel getCarFollowingModel();
35  
36      
37  
38  
39  
40  
41  
42      default LaneDirection chooseLaneAtSplit(final Set<LaneDirection> lanes) throws ParameterException
43      {
44          Route route = getGtu().getStrategicalPlanner().getRoute();
45          if (route == null)
46          {
47              
48              LaneDirection rightMost = null;
49              for (LaneDirection lane : lanes)
50              {
51                  rightMost = rightMost == null ? lane : rightMost(rightMost, lane);
52              }
53              return rightMost;
54          }
55          Length maxDistance = Length.NEGATIVE_INFINITY;
56          LaneDirection best = null;
57          for (LaneDirection lane : lanes)
58          {
59              LaneDirection next = lane.getNextLaneDirection(getGtu());
60              if (next != null)
61              {
62                  Length okDistance = okDistance(next, lane.getLength(), route,
63                          getGtu().getParameters().getParameter(ParameterTypes.PERCEPTION));
64                  if (maxDistance.eq(okDistance))
65                  {
66                      best = rightMost(best, lane);
67                  }
68                  else if (okDistance.gt(maxDistance))
69                  {
70                      maxDistance = okDistance;
71                      best = lane;
72                  }
73              }
74          }
75          return best;
76      }
77  
78      
79  
80  
81  
82  
83  
84  
85  
86  
87      
88      default Length okDistance(final LaneDirection lane, final Length distance, final Route route, final Length maxDistance)
89      {
90          if (distance.gt(maxDistance))
91          {
92              return maxDistance;
93          }
94          LaneDirection next = lane.getNextLaneDirection(getGtu());
95          if (next == null)
96          {
97              Node endNode = lane.getDirection().isPlus() ? lane.getLane().getParentLink().getEndNode()
98                      : lane.getLane().getParentLink().getStartNode();
99              Set<Link> links = endNode.getLinks().toSet();
100             links.remove(lane.getLane().getParentLink());
101             if (route.contains(endNode) && (links.isEmpty() || links.iterator().next().getLinkType().isConnector()))
102             {
103                 
104                 return maxDistance;
105             }
106             
107             return distance.plus(lane.getLength());
108         }
109         return okDistance(next, distance.plus(lane.getLength()), route, maxDistance);
110     }
111 
112     
113 
114 
115 
116 
117 
118     
119     default LaneDirection rightMost(final LaneDirection lane1, final LaneDirection lane2)
120     {
121         Length offset1 = lane1.getLane().getDesignLineOffsetAtBegin().plus(lane1.getLane().getDesignLineOffsetAtEnd());
122         offset1 = lane1.getDirection().isPlus() ? offset1 : offset1.neg();
123         Length offset2 = lane2.getLane().getDesignLineOffsetAtBegin().plus(lane2.getLane().getDesignLineOffsetAtEnd());
124         offset2 = lane2.getDirection().isPlus() ? offset2 : offset2.neg();
125         return offset1.lt(offset2) ? lane1 : lane2;
126     }
127 
128 }