1 package org.opentrafficsim.road.gtu.perception.mental.channel;
2
3 import java.util.SortedSet;
4 import java.util.TreeSet;
5
6 import org.djutils.exceptions.Throw;
7 import org.djutils.exceptions.Try;
8 import org.opentrafficsim.base.parameters.ParameterException;
9 import org.opentrafficsim.core.gtu.RelativePosition;
10 import org.opentrafficsim.core.gtu.perception.AbstractPerceptionCategory;
11 import org.opentrafficsim.core.network.LateralDirectionality;
12 import org.opentrafficsim.road.gtu.LaneBasedGtu;
13 import org.opentrafficsim.road.gtu.perception.LanePerception;
14 import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
15 import org.opentrafficsim.road.gtu.perception.PerceptionReiterable;
16 import org.opentrafficsim.road.gtu.perception.RelativeLane;
17 import org.opentrafficsim.road.gtu.perception.categories.neighbors.Anticipation;
18 import org.opentrafficsim.road.gtu.perception.categories.neighbors.DirectNeighborsPerception;
19 import org.opentrafficsim.road.gtu.perception.categories.neighbors.Estimation;
20 import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
21 import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType;
22 import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType.AnticipationPerceivedGtuType;
23 import org.opentrafficsim.road.gtu.perception.object.PerceivedGtu;
24 import org.opentrafficsim.road.gtu.perception.structure.NavigatingIterable.Entry;
25
26
27
28
29
30
31
32
33
34
35 public class NeighborsPerceptionChannel extends AbstractPerceptionCategory<LaneBasedGtu, LanePerception>
36 implements NeighborsPerception
37 {
38
39
40 private final PerceivedGtuType perceivedGtuTypeLeft;
41
42
43 private final PerceivedGtuType perceivedGtuTypeRight;
44
45
46 private final PerceivedGtuType perceivedGtuTypeFront;
47
48
49 private final PerceivedGtuType perceivedGtuTypeRear;
50
51
52
53
54
55
56
57 public NeighborsPerceptionChannel(final LanePerception perception, final Estimation estimation,
58 final Anticipation anticipation)
59 {
60 super(perception);
61 Throw.when(!(getPerception().getMental().get() instanceof ChannelMental), IllegalArgumentException.class,
62 "Mental module is not channel based.");
63 ChannelMental mental = (ChannelMental) getPerception().getMental().get();
64 this.perceivedGtuTypeLeft =
65 new AnticipationPerceivedGtuType(estimation, anticipation, () -> mental.getPerceptionDelay(ChannelTask.LEFT));
66 this.perceivedGtuTypeRight =
67 new AnticipationPerceivedGtuType(estimation, anticipation, () -> mental.getPerceptionDelay(ChannelTask.RIGHT));
68 this.perceivedGtuTypeFront =
69 new AnticipationPerceivedGtuType(estimation, anticipation, () -> mental.getPerceptionDelay(ChannelTask.FRONT));
70 this.perceivedGtuTypeRear =
71 new AnticipationPerceivedGtuType(estimation, anticipation, () -> mental.getPerceptionDelay(ChannelTask.REAR));
72 }
73
74
75 @Override
76 public SortedSet<PerceivedGtu> getFirstLeaders(final LateralDirectionality lat)
77 throws ParameterException, NullPointerException, IllegalArgumentException
78 {
79 checkLateralDirectionality(lat);
80 return computeIfAbsent("firstLeaders", () -> computeFirstLeaders(lat), lat);
81 }
82
83
84
85
86
87
88 private SortedSet<PerceivedGtu> computeFirstLeaders(final LateralDirectionality lat)
89 {
90 try
91 {
92 SortedSet<PerceivedGtu> set = new TreeSet<>();
93 PerceivedGtuType perceivedGtuType = lat.isLeft() ? this.perceivedGtuTypeLeft : this.perceivedGtuTypeRight;
94 for (Entry<LaneBasedGtu> entry : getPerception().getLaneStructure().getFirstDownstreamGtus(new RelativeLane(lat, 1),
95 RelativePosition.FRONT, RelativePosition.REAR, RelativePosition.FRONT, RelativePosition.REAR))
96 {
97 set.add(perceivedGtuType.createPerceivedGtu(getGtu(), getGtu(), entry.object(), entry.distance(), true));
98 }
99 return set;
100 }
101 catch (ParameterException | IllegalArgumentException exception)
102 {
103 throw new RuntimeException("Unexpected exception while computing first leaders.", exception);
104 }
105 }
106
107
108 @Override
109 public SortedSet<PerceivedGtu> getFirstFollowers(final LateralDirectionality lat)
110 throws ParameterException, NullPointerException, IllegalArgumentException
111 {
112 checkLateralDirectionality(lat);
113 return computeIfAbsent("firstFollowers", () -> computeFirstFollowers(lat), lat);
114 }
115
116
117
118
119
120
121 private SortedSet<PerceivedGtu> computeFirstFollowers(final LateralDirectionality lat)
122 {
123 try
124 {
125 SortedSet<PerceivedGtu> set = new TreeSet<>();
126 PerceivedGtuType perceivedGtuType = lat.isLeft() ? this.perceivedGtuTypeLeft : this.perceivedGtuTypeRight;
127 for (Entry<LaneBasedGtu> entry : getPerception().getLaneStructure().getFirstUpstreamGtus(new RelativeLane(lat, 1),
128 RelativePosition.REAR, RelativePosition.FRONT, RelativePosition.REAR, RelativePosition.FRONT))
129 {
130 set.add(perceivedGtuType.createPerceivedGtu(getGtu(), getGtu(), entry.object(), entry.distance(), false));
131 }
132 return set;
133 }
134 catch (ParameterException | IllegalArgumentException exception)
135 {
136 throw new RuntimeException("Unexpected exception while computing first followers.", exception);
137 }
138 }
139
140
141 @Override
142 public boolean isGtuAlongside(final LateralDirectionality lat)
143 throws ParameterException, NullPointerException, IllegalArgumentException
144 {
145 checkLateralDirectionality(lat);
146 return computeIfAbsent("gtuAlongside", () -> computeGtuAlongside(lat), lat);
147 }
148
149
150
151
152
153
154 public boolean computeGtuAlongside(final LateralDirectionality lat)
155 {
156 try
157 {
158
159 for (Entry<LaneBasedGtu> entry : getPerception().getLaneStructure().getFirstDownstreamGtus(new RelativeLane(lat, 1),
160 RelativePosition.REAR, RelativePosition.FRONT, RelativePosition.FRONT, RelativePosition.REAR))
161 {
162 if (entry.distance().le0())
163 {
164 return true;
165 }
166 }
167
168
169 for (Entry<LaneBasedGtu> entry : getPerception().getLaneStructure().getFirstUpstreamGtus(new RelativeLane(lat, 1),
170 RelativePosition.FRONT, RelativePosition.REAR, RelativePosition.REAR, RelativePosition.FRONT))
171 {
172 if (entry.distance().le0())
173 {
174 return true;
175 }
176 }
177 }
178 catch (ParameterException | IllegalArgumentException exception)
179 {
180 throw new RuntimeException("Unexpected exception while computing gtu alongside.", exception);
181 }
182
183 return false;
184 }
185
186
187 @Override
188 public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getLeaders(final RelativeLane lane)
189 {
190 Throw.whenNull(lane, "Lane may not be null.");
191 return computeIfAbsent("leaders", () -> computeLeaders(lane), lane);
192 }
193
194
195
196
197
198
199 private PerceptionCollectable<PerceivedGtu, LaneBasedGtu> computeLeaders(final RelativeLane lane)
200 {
201 Iterable<Entry<LaneBasedGtu>> iterable = Try.assign(() ->
202 {
203 return getPerception().getLaneStructure().getDownstreamGtus(lane, RelativePosition.FRONT, RelativePosition.FRONT,
204 RelativePosition.FRONT, RelativePosition.REAR);
205 }, "Unable to get leaders from LaneStructure");
206 PerceivedGtuType perceivedGtuType = lane.getLateralDirectionality().isNone() ? this.perceivedGtuTypeFront
207 : (lane.getLateralDirectionality().isLeft() ? this.perceivedGtuTypeLeft : this.perceivedGtuTypeRight);
208 return new PerceptionReiterable<>(getGtu(), iterable, (perceivedGtu, distance) ->
209 {
210 return Try.assign(() -> perceivedGtuType.createPerceivedGtu(getGtu(), getGtu(), perceivedGtu, distance, true),
211 "Exception during perception of leader.");
212 });
213 }
214
215
216 @Override
217 public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getFollowers(final RelativeLane lane)
218 {
219 Throw.whenNull(lane, "Lane may not be null.");
220 return computeIfAbsent("followers", () -> computeFollowers(lane), lane);
221 }
222
223
224
225
226
227
228 private PerceptionCollectable<PerceivedGtu, LaneBasedGtu> computeFollowers(final RelativeLane lane)
229 {
230 Iterable<Entry<LaneBasedGtu>> iterable = Try.assign(() ->
231 {
232 return getPerception().getLaneStructure().getUpstreamGtus(lane, RelativePosition.FRONT, RelativePosition.FRONT,
233 RelativePosition.REAR, RelativePosition.FRONT);
234 }, "Unable to get followers from LaneStructure");
235 PerceivedGtuType perceivedGtuType = lane.getLateralDirectionality().isNone() ? this.perceivedGtuTypeRear
236 : (lane.getLateralDirectionality().isLeft() ? this.perceivedGtuTypeLeft : this.perceivedGtuTypeRight);
237 return new PerceptionReiterable<>(getGtu(), iterable, (perceivedGtu, distance) ->
238 {
239 return Try.assign(() -> perceivedGtuType.createPerceivedGtu(getGtu(), getGtu(), perceivedGtu, distance, false),
240 "ParameterException during perception of leader.");
241 });
242 }
243
244
245
246
247
248
249
250
251 private void checkLateralDirectionality(final LateralDirectionality lat)
252 throws ParameterException, NullPointerException, IllegalArgumentException
253 {
254 Throw.whenNull(lat, "Lateral directionality may not be null.");
255 Throw.when(lat.equals(LateralDirectionality.NONE), IllegalArgumentException.class,
256 "Lateral directionality may not be NONE.");
257 Throw.when(!getPerception().getLaneStructure().exists(lat.isLeft() ? RelativeLane.LEFT : RelativeLane.RIGHT),
258 IllegalArgumentException.class, "Lateral directionality may only point to an existing adjacent lane.");
259 }
260
261
262 @Override
263 public final String toString()
264 {
265 return "NeighborsPerceptionChannel";
266 }
267
268 }