1 package org.opentrafficsim.road.gtu.lane.tactical;
2
3 import java.util.Collections;
4 import java.util.Iterator;
5 import java.util.Set;
6
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.opentrafficsim.base.parameters.ParameterException;
9 import org.opentrafficsim.base.parameters.ParameterTypes;
10 import org.opentrafficsim.core.gtu.GtuException;
11 import org.opentrafficsim.core.gtu.plan.tactical.TacticalPlanner;
12 import org.opentrafficsim.core.network.LateralDirectionality;
13 import org.opentrafficsim.core.network.Link;
14 import org.opentrafficsim.core.network.Node;
15 import org.opentrafficsim.core.network.route.Route;
16 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
17 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
18 import org.opentrafficsim.road.gtu.lane.plan.operational.LaneBasedOperationalPlan;
19 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
20 import org.opentrafficsim.road.network.lane.Lane;
21
22
23
24
25
26
27
28
29
30
31 public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGtu, LanePerception>
32 {
33
34
35
36
37 CarFollowingModel getCarFollowingModel();
38
39
40
41
42
43
44
45
46 default Lane chooseLaneAtSplit(final Lane from, final Set<Lane> lanes) throws ParameterException
47 {
48 if (getGtu().getOperationalPlan() instanceof LaneBasedOperationalPlan
49 && ((LaneBasedOperationalPlan) getGtu().getOperationalPlan()).isDeviative())
50 {
51
52 LateralDirectionality forceSide = LateralDirectionality.NONE;
53 try
54 {
55 Set<Lane> leftLanes = from.accessibleAdjacentLanesPhysical(LateralDirectionality.LEFT, getGtu().getType());
56 if (!Collections.disjoint(getGtu().positions(getGtu().getReference()).keySet(), leftLanes))
57 {
58 forceSide = LateralDirectionality.LEFT;
59 }
60 else
61 {
62 Set<Lane> rightLanes =
63 from.accessibleAdjacentLanesPhysical(LateralDirectionality.RIGHT, getGtu().getType());
64 if (!Collections.disjoint(getGtu().positions(getGtu().getReference()).keySet(), rightLanes))
65 {
66 forceSide = LateralDirectionality.RIGHT;
67 }
68 }
69 }
70 catch (GtuException exception)
71 {
72 throw new RuntimeException("Exception obtaining reference position.", exception);
73 }
74 if (!forceSide.isNone())
75 {
76 if (lanes.isEmpty())
77 {
78
79 return null;
80 }
81 else
82 {
83 Iterator<Lane> iter = lanes.iterator();
84 Lane next = iter.next();
85 while (iter.hasNext())
86 {
87 Lane candidate = iter.next();
88 next = LaneBasedTacticalPlanner.mostOnSide(next, candidate, forceSide);
89 }
90 return next;
91 }
92 }
93 }
94 Route route = getGtu().getStrategicalPlanner().getRoute();
95 if (route == null)
96 {
97
98 Lane rightMost = null;
99 for (Lane lane : lanes)
100 {
101 rightMost = rightMost == null ? lane : mostOnSide(rightMost, lane, LateralDirectionality.RIGHT);
102 }
103 return rightMost;
104 }
105 Length maxDistance = Length.NEGATIVE_INFINITY;
106 Lane best = null;
107 for (Lane lane : lanes)
108 {
109 Lane next = getGtu().getNextLaneForRoute(lane);
110 if (next != null)
111 {
112 Length okDistance = okDistance(next, lane.getLength(), route,
113 getGtu().getParameters().getParameter(ParameterTypes.PERCEPTION));
114 if (maxDistance.eq(okDistance))
115 {
116 best = mostOnSide(best, lane, LateralDirectionality.RIGHT);
117 }
118 else if (okDistance.gt(maxDistance))
119 {
120 maxDistance = okDistance;
121 best = lane;
122 }
123 }
124 }
125 return best;
126 }
127
128
129
130
131
132
133
134
135
136
137
138 default Length okDistance(final Lane lane, final Length distance, final Route route, final Length maxDistance)
139 {
140 if (distance.gt(maxDistance))
141 {
142 return maxDistance;
143 }
144 Lane next = getGtu().getNextLaneForRoute(lane);
145 if (next == null)
146 {
147 Node endNode = lane.getLink().getEndNode();
148 Set<Link> links = endNode.getLinks().toSet();
149 links.remove(lane.getLink());
150 if (route.contains(endNode) && (links.isEmpty() || links.iterator().next().isConnector()))
151 {
152
153 return maxDistance;
154 }
155
156 return distance.plus(lane.getLength());
157 }
158 return okDistance(next, distance.plus(lane.getLength()), route, maxDistance);
159 }
160
161
162
163
164
165
166
167
168 static Lane mostOnSide(final Lane lane1, final Lane lane2, final LateralDirectionality lat)
169 {
170 Length offset1 = lane1.getOffsetAtBegin().plus(lane1.getOffsetAtEnd());
171 Length offset2 = lane2.getOffsetAtBegin().plus(lane2.getOffsetAtEnd());
172 if (lat.isLeft())
173 {
174 return offset1.gt(offset2) ? lane1 : lane2;
175 }
176 return offset1.gt(offset2) ? lane2 : lane1;
177 }
178
179 }