1 package org.opentrafficsim.road.gtu.perception.mental.channel;
2
3 import java.util.Iterator;
4
5 import org.djunits.value.vdouble.scalar.Length;
6 import org.djutils.exceptions.Throw;
7 import org.djutils.exceptions.Try;
8 import org.opentrafficsim.base.OtsRuntimeException;
9 import org.opentrafficsim.base.parameters.ParameterException;
10 import org.opentrafficsim.base.parameters.ParameterTypeLength;
11 import org.opentrafficsim.base.parameters.ParameterTypes;
12 import org.opentrafficsim.core.gtu.RelativePosition;
13 import org.opentrafficsim.core.gtu.perception.AbstractPerceptionCategory;
14 import org.opentrafficsim.core.network.LateralDirectionality;
15 import org.opentrafficsim.core.network.route.Route;
16 import org.opentrafficsim.road.gtu.LaneBasedGtu;
17 import org.opentrafficsim.road.gtu.perception.LanePerception;
18 import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
19 import org.opentrafficsim.road.gtu.perception.PerceptionReiterable;
20 import org.opentrafficsim.road.gtu.perception.RelativeLane;
21 import org.opentrafficsim.road.gtu.perception.categories.DirectIntersectionPerception;
22 import org.opentrafficsim.road.gtu.perception.categories.IntersectionPerception;
23 import org.opentrafficsim.road.gtu.perception.categories.neighbors.Anticipation;
24 import org.opentrafficsim.road.gtu.perception.categories.neighbors.Estimation;
25 import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType;
26 import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType.AnticipationPerceivedGtuType;
27 import org.opentrafficsim.road.gtu.perception.object.PerceivedConflict;
28 import org.opentrafficsim.road.gtu.perception.object.PerceivedTrafficLight;
29 import org.opentrafficsim.road.gtu.perception.object.PerceivedTrafficLightChannel;
30 import org.opentrafficsim.road.gtu.perception.structure.NavigatingIterable.Entry;
31 import org.opentrafficsim.road.network.conflict.Conflict;
32 import org.opentrafficsim.road.network.object.trafficlight.TrafficLight;
33
34
35
36
37
38
39
40
41
42
43 public class IntersectionPerceptionChannel extends AbstractPerceptionCategory<LaneBasedGtu, LanePerception>
44 implements IntersectionPerception
45 {
46
47
48 private final ChannelMental mental;
49
50
51 private final Estimation estimation;
52
53
54 private final Anticipation anticipation;
55
56
57 protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
58
59
60
61
62
63
64
65 public IntersectionPerceptionChannel(final LanePerception perception, final Estimation estimation,
66 final Anticipation anticipation)
67 {
68 super(perception);
69 Throw.when(!(getPerception().getMental().get() instanceof ChannelMental), IllegalArgumentException.class,
70 "Mental module is not channel based.");
71 this.mental = (ChannelMental) getPerception().getMental().get();
72 this.estimation = estimation;
73 this.anticipation = anticipation;
74 }
75
76 @Override
77 public final PerceptionCollectable<PerceivedTrafficLight, TrafficLight> getTrafficLights(final RelativeLane lane)
78 {
79 return computeIfAbsent("trafficLights", () -> computeTrafficLights(lane), lane);
80 }
81
82 @Override
83 public final PerceptionCollectable<PerceivedConflict, Conflict> getConflicts(final RelativeLane lane)
84 {
85 return computeIfAbsent("conflicts", () -> computeConflicts(lane), lane);
86 }
87
88 @Override
89 public final boolean isAlongsideConflictLeft()
90 {
91 return computeIfAbsent("alongside", () -> computeConflictAlongside(LateralDirectionality.LEFT),
92 LateralDirectionality.LEFT);
93 }
94
95 @Override
96 public final boolean isAlongsideConflictRight()
97 {
98 return computeIfAbsent("alongside", () -> computeConflictAlongside(LateralDirectionality.RIGHT),
99 LateralDirectionality.RIGHT);
100 }
101
102
103
104
105
106
107 private PerceptionCollectable<PerceivedTrafficLight, TrafficLight> computeTrafficLights(final RelativeLane lane)
108 {
109 Iterable<Entry<TrafficLight>> iterable = Try.assign(() ->
110 {
111 return getPerception().getLaneStructure().getDownstreamObjects(lane, TrafficLight.class, RelativePosition.FRONT,
112 true);
113 }, "Unable to get downstream traffic lights from LaneStructure");
114 Route route = getPerception().getGtu().getStrategicalPlanner().getRoute()
115 .orElseThrow(() -> new OtsRuntimeException("Unable to obtain route"));
116 return new PerceptionReiterable<>(getGtu(), iterable, (trafficLight, distance) ->
117 {
118 return new PerceivedTrafficLightChannel(trafficLight, distance,
119 trafficLight.canTurnOnRed(route, getGtu().getType()),
120 () -> IntersectionPerceptionChannel.this.mental.getPerceptionDelay(ChannelTask.FRONT));
121 });
122 }
123
124
125
126
127
128
129 private PerceptionCollectable<PerceivedConflict, Conflict> computeConflicts(final RelativeLane lane)
130 {
131 Iterable<Entry<Conflict>> iterable = Try.assign(() -> getPerception().getLaneStructure().getDownstreamObjects(lane,
132 Conflict.class, RelativePosition.FRONT, true), "Unable to get downstream conflicts from LaneStructure");
133 return new PerceptionReiterable<>(getGtu(), iterable, (conflict, distance) ->
134 {
135 Length lookAhead = getGtu().getParameters().getOptionalParameter(LOOKAHEAD)
136 .orElseThrow(() -> new OtsRuntimeException("Parameter LOOKAHEAD not present."));
137
138 Length conflictingVisibility = lookAhead;
139 PerceivedConflict perceivedConflict;
140 PerceivedGtuType perceivedGtuType = new AnticipationPerceivedGtuType(IntersectionPerceptionChannel.this.estimation,
141 IntersectionPerceptionChannel.this.anticipation,
142 () -> IntersectionPerceptionChannel.this.mental.getPerceptionDelay(conflict));
143 perceivedConflict = PerceivedConflict.of(getGtu(), conflict, perceivedGtuType, distance, conflictingVisibility);
144 return perceivedConflict;
145 });
146 }
147
148
149
150
151
152
153 private boolean computeConflictAlongside(final LateralDirectionality lat)
154 {
155 try
156 {
157 RelativeLane lane = new RelativeLane(lat, 1);
158 if (getPerception().getLaneStructure().exists(lane))
159 {
160 Iterator<Entry<Conflict>> conflicts = getPerception().getLaneStructure()
161 .getUpstreamObjects(lane, Conflict.class, RelativePosition.FRONT).iterator();
162 if (conflicts.hasNext())
163 {
164 Entry<Conflict> entry = conflicts.next();
165 return entry.distance().si < entry.object().getLength().si + getGtu().getLength().si;
166 }
167 }
168 return false;
169 }
170 catch (ParameterException exception)
171 {
172 throw new RuntimeException("Unexpected exception while computing conflict alongside.", exception);
173 }
174 }
175
176 @Override
177 public final String toString()
178 {
179 return "IntersectionPerceptionChannel " + cacheAsString();
180 }
181
182 }