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
23
24
25
26
27
28
29
30 public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGtu, LanePerception>
31 {
32
33
34
35
36 CarFollowingModel getCarFollowingModel();
37
38
39
40
41
42
43
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
82
83
84
85
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 }