View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception.categories.neighbors;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.SortedSet;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djutils.exceptions.Throw;
9   import org.opentrafficsim.base.TimeStampedObject;
10  import org.opentrafficsim.base.parameters.ParameterException;
11  import org.opentrafficsim.base.parameters.ParameterTypeLength;
12  import org.opentrafficsim.base.parameters.ParameterTypes;
13  import org.opentrafficsim.core.gtu.GTUException;
14  import org.opentrafficsim.core.gtu.RelativePosition;
15  import org.opentrafficsim.core.network.LateralDirectionality;
16  import org.opentrafficsim.core.network.NetworkException;
17  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
18  import org.opentrafficsim.road.gtu.lane.perception.DownstreamNeighborsIterable;
19  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
20  import org.opentrafficsim.road.gtu.lane.perception.LaneStructureRecord;
21  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
22  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
23  import org.opentrafficsim.road.gtu.lane.perception.UpstreamNeighborsIterable;
24  import org.opentrafficsim.road.gtu.lane.perception.categories.LaneBasedAbstractPerceptionCategory;
25  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsUtil.DistanceGTU;
26  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
27  
28  /**
29   * Perception of surrounding traffic on the own road, i.e. without crossing traffic.
30   * <p>
31   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
32   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
33   * <p>
34   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Jul 22, 2016 <br>
35   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
36   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
37   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
38   */
39  public class DirectNeighborsPerception extends LaneBasedAbstractPerceptionCategory implements NeighborsPerception
40  {
41  
42      /** */
43      private static final long serialVersionUID = 20160811L;
44  
45      /** Look ahead parameter type. */
46      protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
47  
48      /** Look back parameter type. */
49      protected static final ParameterTypeLength LOOKBACK = ParameterTypes.LOOKBACK;
50  
51      /** Set of followers per relative lane. */
52      private final Map<RelativeLane, TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>>> followers =
53              new HashMap<>();
54  
55      /** Set of leaders per relative lane. */
56      private final Map<RelativeLane, TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>>> leaders =
57              new HashMap<>();
58  
59      /** Set of first followers per lane upstream of merge per lateral direction, i.e. in the left or right lane. */
60      private final Map<LateralDirectionality, TimeStampedObject<SortedSet<HeadwayGTU>>> firstFollowers = new HashMap<>();
61  
62      /** Set of first leaders per lane downstream of split per lateral direction, i.e. in the left or right lane. */
63      private final Map<LateralDirectionality, TimeStampedObject<SortedSet<HeadwayGTU>>> firstLeaders = new HashMap<>();
64  
65      /** Whether a GTU is alongside per lateral direction, i.e. in the left or right lane. */
66      private final Map<LateralDirectionality, TimeStampedObject<Boolean>> gtuAlongside = new HashMap<>();
67  
68      /** Headway GTU type that should be used. */
69      private final HeadwayGtuType headwayGtuType;
70  
71      /**
72       * @param perception LanePerception; perception
73       * @param headwayGtuType HeadwayGtuType; type of headway gtu to generate
74       */
75      public DirectNeighborsPerception(final LanePerception perception, final HeadwayGtuType headwayGtuType)
76      {
77          super(perception);
78          this.headwayGtuType = headwayGtuType;
79      }
80  
81      /** {@inheritDoc} */
82      @Override
83      public final void updateAll() throws GTUException, NetworkException, ParameterException
84      {
85          this.firstLeaders.clear();
86          this.firstFollowers.clear();
87          this.gtuAlongside.clear();
88          if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT))
89          {
90              updateFirstLeaders(LateralDirectionality.LEFT);
91              updateFirstFollowers(LateralDirectionality.LEFT);
92              updateGtuAlongside(LateralDirectionality.LEFT);
93          }
94          if (getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT))
95          {
96              updateFirstLeaders(LateralDirectionality.RIGHT);
97              updateFirstFollowers(LateralDirectionality.RIGHT);
98              updateGtuAlongside(LateralDirectionality.RIGHT);
99          }
100         this.leaders.clear();
101         this.followers.clear();
102         for (RelativeLane lane : getPerception().getLaneStructure().getExtendedCrossSection())
103         {
104             updateLeaders(lane);
105             updateFollowers(lane);
106         }
107     }
108 
109     /** {@inheritDoc} */
110     @Override
111     public final void updateFirstLeaders(final LateralDirectionality lat)
112             throws ParameterException, GTUException, NetworkException
113     {
114         checkLateralDirectionality(lat);
115         SortedSet<HeadwayGTU> headwaySet = NeighborsUtil.perceive(
116                 NeighborsUtil.getFirstDownstreamGTUs(
117                         getPerception().getLaneStructure().getFirstRecord(new RelativeLane(lat, 1)), getGtu().getFront(),
118                         getGtu().getFront(), RelativePosition.REAR, getTimestamp()),
119                 this.headwayGtuType, getGtu(), true);
120         this.firstLeaders.put(lat, new TimeStampedObject<>(headwaySet, getTimestamp()));
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public final void updateFirstFollowers(final LateralDirectionality lat)
126             throws GTUException, ParameterException, NetworkException
127     {
128         checkLateralDirectionality(lat);
129         SortedSet<HeadwayGTU> headwaySet = NeighborsUtil.perceive(
130                 NeighborsUtil.getFirstUpstreamGTUs(getPerception().getLaneStructure().getFirstRecord(new RelativeLane(lat, 1)),
131                         getGtu().getRear(), getGtu().getRear(), RelativePosition.FRONT, getTimestamp()),
132                 this.headwayGtuType, getGtu(), false);
133         this.firstFollowers.put(lat, new TimeStampedObject<>(headwaySet, getTimestamp()));
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     public final void updateGtuAlongside(final LateralDirectionality lat) throws GTUException, ParameterException
139     {
140 
141         checkLateralDirectionality(lat);
142         // check if any GTU is downstream of the rear, within the vehicle length
143         SortedSet<DistanceGTU> headwaySet = NeighborsUtil.getFirstDownstreamGTUs(
144                 getPerception().getLaneStructure().getFirstRecord(new RelativeLane(lat, 1)), getGtu().getRear(),
145                 getGtu().getFront(), RelativePosition.FRONT, getTimestamp());
146         if (!headwaySet.isEmpty() && headwaySet.first().getDistance().le0())
147         {
148             this.gtuAlongside.put(lat, new TimeStampedObject<>(true, getTimestamp()));
149             return;
150         }
151         // check if any GTU is upstream of the front, within the vehicle length
152         headwaySet =
153                 NeighborsUtil.getFirstUpstreamGTUs(getPerception().getLaneStructure().getFirstRecord(new RelativeLane(lat, 1)),
154                         getGtu().getFront(), getGtu().getRear(), RelativePosition.REAR, getTimestamp());
155         if (!headwaySet.isEmpty() && headwaySet.first().getDistance().le0())
156         {
157             this.gtuAlongside.put(lat, new TimeStampedObject<>(true, getTimestamp()));
158             return;
159         }
160         // no such GTU
161         this.gtuAlongside.put(lat, new TimeStampedObject<>(false, getTimestamp()));
162 
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public final void updateLeaders(final RelativeLane lane) throws ParameterException, GTUException, NetworkException
168     {
169         Throw.whenNull(lane, "Lane may not be null.");
170         LaneStructureRecord record = getPerception().getLaneStructure().getFirstRecord(lane);
171         Length pos = record.getStartDistance().neg();
172         pos = record.getDirection().isPlus() ? pos.plus(getGtu().getFront().getDx()) : pos.minus(getGtu().getFront().getDx());
173         boolean ignoreIfUpstream = true;
174         PerceptionCollectable<HeadwayGTU,
175                 LaneBasedGTU> it = new DownstreamNeighborsIterable(getGtu(), record, Length.max(Length.ZERO, pos),
176                         getGtu().getParameters().getParameter(LOOKAHEAD), getGtu().getFront(), this.headwayGtuType, getGtu(),
177                         lane, ignoreIfUpstream);
178         this.leaders.put(lane, new TimeStampedObject<>(it, getTimestamp()));
179     }
180 
181     /** {@inheritDoc} */
182     @Override
183     public final void updateFollowers(final RelativeLane lane) throws GTUException, NetworkException, ParameterException
184     {
185         Throw.whenNull(lane, "Lane may not be null.");
186         LaneStructureRecord record = getPerception().getLaneStructure().getFirstRecord(lane);
187         Length pos = record.getStartDistance().neg();
188         pos = record.getDirection().isPlus() ? pos.plus(getGtu().getFront().getDx()) : pos.minus(getGtu().getFront().getDx());
189         PerceptionCollectable<HeadwayGTU, LaneBasedGTU> it =
190                 new UpstreamNeighborsIterable(getGtu(), record, Length.max(Length.ZERO, pos),
191                         getGtu().getParameters().getParameter(LOOKBACK), getGtu().getRear(), this.headwayGtuType, lane);
192         this.followers.put(lane, new TimeStampedObject<>(it, getTimestamp()));
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public final SortedSet<HeadwayGTU> getFirstLeaders(final LateralDirectionality lat)
198             throws ParameterException, NullPointerException, IllegalArgumentException
199     {
200         checkLateralDirectionality(lat);
201         return this.firstLeaders.get(lat).getObject();
202     }
203 
204     /** {@inheritDoc} */
205     @Override
206     public final SortedSet<HeadwayGTU> getFirstFollowers(final LateralDirectionality lat)
207             throws ParameterException, NullPointerException, IllegalArgumentException
208     {
209         checkLateralDirectionality(lat);
210         return getObjectOrNull(this.firstFollowers.get(lat));
211     }
212 
213     /** {@inheritDoc} */
214     @Override
215     public final boolean isGtuAlongside(final LateralDirectionality lat)
216             throws ParameterException, NullPointerException, IllegalArgumentException
217     {
218         checkLateralDirectionality(lat);
219         return getObjectOrNull(this.gtuAlongside.get(lat));
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     public final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getLeaders(final RelativeLane lane)
225     {
226         return getObjectOrNull(this.leaders.get(lane));
227     }
228 
229     /** {@inheritDoc} */
230     @Override
231     public final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getFollowers(final RelativeLane lane)
232     {
233         return getObjectOrNull(this.followers.get(lane));
234     }
235 
236     /**
237      * Set of leaders on a lane, which is usually 0 or 1, but possibly more in case of a downstream split with no intermediate
238      * GTU. This is shown below. Suppose A needs to go straight. If A considers a lane change to the left, both GTUs B (who's
239      * tail ~ is still on the straight lane) and C need to be considered for whether it's safe to do so. In case of multiple
240      * splits close to one another, the returned set may contain even more than 2 leaders. Leaders are sorted by headway value.
241      * 
242      * <pre>
243      *          | |
244      * _________/B/_____
245      * _ _?_ _ _~_ _C_ _
246      * _ _A_ _ _ _ _ _ _
247      * _________________
248      * </pre>
249      * 
250      * @param lat LateralDirectionality; LEFT or RIGHT
251      * @return list of followers on a lane
252      * @throws ParameterException if parameter is not defined
253      * @throws NullPointerException if {@code lat} is {@code null}
254      * @throws IllegalArgumentException if {@code lat} is {@code NONE}
255      */
256     public final TimeStampedObject<SortedSet<HeadwayGTU>> getTimeStampedFirstLeaders(final LateralDirectionality lat)
257             throws ParameterException, NullPointerException, IllegalArgumentException
258     {
259         checkLateralDirectionality(lat);
260         return this.firstLeaders.get(lat);
261     }
262 
263     /**
264      * Set of followers on a lane, which is usually 0 or 1, but possibly more in case of an upstream merge with no intermediate
265      * GTU. This is shown below. If A considers a lane change to the left, both GTUs B and C need to be considered for whether
266      * it's safe to do so. In case of multiple merges close to one another, the returned set may contain even more than 2
267      * followers. Followers are sorted by tailway value.
268      * 
269      * <pre>
270      *        | |
271      *        |C| 
272      * ________\ \______
273      * _ _B_|_ _ _ _ _?_
274      * _ _ _|_ _ _ _ _A_ 
275      * _____|___________
276      * </pre>
277      * 
278      * @param lat LateralDirectionality; LEFT or RIGHT
279      * @return list of followers on a lane
280      * @throws ParameterException if parameter is not defined
281      * @throws NullPointerException if {@code lat} is {@code null}
282      * @throws IllegalArgumentException if {@code lat} is {@code NONE}
283      */
284     public final TimeStampedObject<SortedSet<HeadwayGTU>> getTimeStampedFirstFollowers(final LateralDirectionality lat)
285             throws ParameterException, NullPointerException, IllegalArgumentException
286     {
287         checkLateralDirectionality(lat);
288         return this.firstFollowers.get(lat);
289     }
290 
291     /**
292      * Whether there is a GTU alongside, i.e. with overlap, in an adjacent lane.
293      * @param lat LateralDirectionality; LEFT or RIGHT
294      * @return whether there is a GTU alongside, i.e. with overlap, in an adjacent lane
295      * @throws ParameterException if parameter is not defined
296      * @throws NullPointerException if {@code lat} is {@code null}
297      * @throws IllegalArgumentException if {@code lat} is {@code NONE}
298      */
299     public final TimeStampedObject<Boolean> isGtuAlongsideTimeStamped(final LateralDirectionality lat)
300             throws ParameterException, NullPointerException, IllegalArgumentException
301     {
302         checkLateralDirectionality(lat);
303         return this.gtuAlongside.get(lat);
304     }
305 
306     /**
307      * Set of leaders on a lane, including adjacent GTU's who's FRONT is ahead of the own vehicle FRONT. Leaders are sorted by
308      * headway value.
309      * @param lane RelativeLane; relative lateral lane
310      * @return set of leaders on a lane, including adjacent GTU's who's FRONT is ahead of the own vehicle FRONT
311      */
312     public final TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> getTimeStampedLeaders(
313             final RelativeLane lane)
314     {
315         return this.leaders.get(lane);
316     }
317 
318     /**
319      * Set of followers on a lane, including adjacent GTU's who's REAR is back of the own vehicle REAR. Follower are are sorted
320      * by tailway value.
321      * @param lane RelativeLane; relative lateral lane
322      * @return set of followers on a lane, including adjacent GTU's who's REAR is back of the own vehicle REAR
323      */
324     public final TimeStampedObject<PerceptionCollectable<HeadwayGTU, LaneBasedGTU>> getTimeStampedFollowers(
325             final RelativeLane lane)
326     {
327         return this.followers.get(lane);
328     }
329 
330     /**
331      * Checks that lateral directionality is either left or right and an existing lane.
332      * @param lat LateralDirectionality; LEFT or RIGHT
333      * @throws ParameterException if parameter is not defined
334      * @throws NullPointerException if {@code lat} is {@code null}
335      * @throws IllegalArgumentException if {@code lat} is {@code NONE}
336      */
337     private void checkLateralDirectionality(final LateralDirectionality lat)
338             throws ParameterException, NullPointerException, IllegalArgumentException
339     {
340         // TODO not use this check when synchronizing or cooperating
341         Throw.whenNull(lat, "Lateral directionality may not be null.");
342         Throw.when(lat.equals(LateralDirectionality.NONE), IllegalArgumentException.class,
343                 "Lateral directionality may not be NONE.");
344         Throw.when(
345                 (lat.equals(LateralDirectionality.LEFT)
346                         && !getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.LEFT))
347                         || (lat.equals(LateralDirectionality.RIGHT)
348                                 && !getPerception().getLaneStructure().getExtendedCrossSection().contains(RelativeLane.RIGHT)),
349                 IllegalArgumentException.class, "Lateral directionality may only point to an existing adjacent lane.");
350     }
351 
352     /** {@inheritDoc} */
353     @Override
354     public final String toString()
355     {
356         return "DirectNeighborsPesrception";
357     }
358 
359 }