View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.util.HashMap;
4   import java.util.HashSet;
5   import java.util.Map;
6   import java.util.Set;
7   import java.util.TreeMap;
8   
9   import org.djunits.unit.LengthUnit;
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.djunits.value.vdouble.scalar.Time;
12  import org.opentrafficsim.core.gtu.GTUDirectionality;
13  import org.opentrafficsim.core.gtu.GTUException;
14  import org.opentrafficsim.core.gtu.GTUType;
15  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
16  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
17  import org.opentrafficsim.core.gtu.perception.AbstractPerception;
18  import org.opentrafficsim.core.network.LateralDirectionality;
19  import org.opentrafficsim.core.network.Link;
20  import org.opentrafficsim.core.network.NetworkException;
21  import org.opentrafficsim.core.network.Node;
22  import org.opentrafficsim.core.network.route.Route;
23  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
24  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
25  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
26  import org.opentrafficsim.road.network.lane.Lane;
27  
28  import nl.tudelft.simulation.language.Throw;
29  
30  /**
31   * The perception module of a GTU based on lanes. It is responsible for perceiving (sensing) the environment of the GTU, which
32   * includes the locations of other GTUs. Perception is done at a certain time, and the perceived information might have a
33   * limited validity. In that sense, Perception is stateful. Information can be requested as often as needed, but will only be
34   * recalculated when asked explicitly. This abstract class provides the building blocks for lane-based perception. <br>
35   * Perception for lane-based GTUs involves information about GTUs in front of the owner GTU on the same lane (the 'leader' GTU),
36   * parallel vehicles (important if we want to change lanes), distance to other vehicles on parallel lanes, as well in front as
37   * to the back (important if we want to change lanes), and information about obstacles, traffic lights, speed signs, and ending
38   * lanes.
39   * <p>
40   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
41   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
42   * </p>
43   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
44   * initial version Nov 15, 2015 <br>
45   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
46   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
47   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
48   */
49  public abstract class AbstractLanePerception extends AbstractPerception implements LanePerception
50  {
51  
52      /** */
53      private static final long serialVersionUID = 20151128L;
54  
55      /** Lane structure to perform the perception with. */
56      private LaneStructure laneStructure = null;
57  
58      /** Most recent update time of lane structure. */
59      private Time updateTime = null;
60  
61      /**
62       * Create a new LanePerception module. Because the constructor is often called inside the constructor of a GTU, this
63       * constructor does not ask for the pointer to the GTU, as it is often impossible to provide at the time of construction.
64       * Use the setter of the GTU instead.
65       * @param gtu GTU
66       */
67      public AbstractLanePerception(final LaneBasedGTU gtu)
68      {
69          super(gtu);
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public final LaneBasedGTU getGtu()
75      {
76          return (LaneBasedGTU) super.getGtu();
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public final LaneStructure getLaneStructure() throws ParameterException
82      {
83          if (this.laneStructure == null || this.updateTime.lt(getGtu().getSimulator().getSimulatorTime().getTime()))
84          {
85              // downstream structure length
86              Length down = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.PERCEPTION);
87              // upstream structure length
88              Length up = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKBACK);
89              // structure length downstream of split on link not on route
90              Length downSplit = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD);
91              // structure length upstream of merge on link not on route
92              Length upMerge = Length.max(up, downSplit);
93              // negative values for upstream
94              up = up.neg();
95              upMerge = upMerge.neg();
96              // Create Lane Structure
97              DirectedLanePosition dlp;
98              try
99              {
100                 dlp = getGtu().getReferencePosition();
101             }
102             catch (GTUException exception)
103             {
104                 // Should not happen, we get the lane from the GTU
105                 throw new RuntimeException("Could not get fraction on root lane.", exception);
106             }
107             Lane rootLane = dlp.getLane();
108             GTUDirectionality direction = dlp.getGtuDirection();
109             double fraction = dlp.getPosition().si / rootLane.getLength().si;
110             LaneStructureRecord rootLSR =
111                     new LaneStructureRecord(rootLane, direction, rootLane.getLength().multiplyBy(-fraction));
112             this.laneStructure = new LaneStructure(rootLSR, downSplit);
113             this.laneStructure.addLaneStructureRecord(rootLSR, RelativeLane.CURRENT);
114             this.relativeLaneMap.clear();
115             this.relativeLaneMap.put(rootLSR, RelativeLane.CURRENT);
116             startBuild(rootLSR, fraction, getGtu().getGTUType(), down, downSplit, up, upMerge);
117 
118             // TODO possibly optimize by using a 'singleton' lane structure source, per GTUType
119             // TODO possibly build and destroy at edges only
120             this.updateTime = getGtu().getSimulator().getSimulatorTime().getTime();
121         }
122         return this.laneStructure;
123     }
124 
125     /**
126      * Local map where relative lanes are store per record, such that other records can be linked to the correct relative lane.
127      */
128     private final Map<LaneStructureRecord, RelativeLane> relativeLaneMap = new HashMap<>();
129 
130     /** Set of lanes that can be ignored as they are beyond build bounds. */
131     private final Set<Lane> ignoreSet = new HashSet<>();
132 
133     /**
134      * Starts the build from the current lane and creates an initial lateral set with correct start distances based on the
135      * fraction.
136      * 
137      * <pre>
138      *  ---------
139      * |  /|\    |
140      *  ---|-----
141      * |  /|\    |
142      *  ---|-----
143      * |   o     | rootLSR
144      *  ---|-----
145      * |  \|/    |
146      *  ---------
147      *  
148      * (---) fraction
149      * </pre>
150      * 
151      * @param rootLSR record where the GTU is currently
152      * @param fraction fractional position where the gtu is
153      * @param gtuType GTU type
154      * @param down maximum downstream distance to build structure
155      * @param downSplit maximum downstream distance past split not following the route to build structure
156      * @param up maximum upstream distance to build structure
157      * @param upMerge maximum upstream distance upstream of downstream merges to build structure
158      */
159     private void startBuild(final LaneStructureRecord rootLSR, final double fraction, final GTUType gtuType, final Length down,
160             final Length downSplit, final Length up, final Length upMerge)
161     {
162         //System.out.println("Creating lane structure for gtu " + getGtu().getId());
163         // Build initial lateral set
164         Set<LaneStructureRecord> recordSet = new HashSet<>();
165         Set<Lane> laneSet = new HashSet<>();
166         recordSet.add(rootLSR);
167         laneSet.add(rootLSR.getLane());
168         for (LateralDirectionality latDirection : new LateralDirectionality[] { LateralDirectionality.LEFT,
169                 LateralDirectionality.RIGHT })
170         {
171             LaneStructureRecord current = rootLSR;
172             RelativeLane relativeLane = RelativeLane.CURRENT;
173             Set<Lane> adjacentLanes = current.getLane().accessibleAdjacentLanes(latDirection, gtuType);
174             while (!adjacentLanes.isEmpty())
175             {
176                 Throw.when(adjacentLanes.size() > 1, RuntimeException.class,
177                         "Multiple adjacent lanes encountered during construction of lane map.");
178                 relativeLane = latDirection.isLeft() ? relativeLane.getLeft() : relativeLane.getRight();
179                 Lane lane = adjacentLanes.iterator().next();
180                 LaneStructureRecord adjacentRecord =
181                         constructRecord(lane, current.getDirection(), lane.getLength().multiplyBy(-fraction), relativeLane);
182                 if (latDirection.isLeft())
183                 {
184                     if (lane.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).contains(current.getLane()))
185                     {
186                         adjacentRecord.setRight(current);
187                     }
188                     current.setLeft(adjacentRecord);
189                 }
190                 else
191                 {
192                     if (lane.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).contains(current.getLane()))
193                     {
194                         adjacentRecord.setLeft(current);
195                     }
196                     current.setRight(adjacentRecord);
197                 }
198                 
199                 recordSet.add(adjacentRecord);
200                 laneSet.add(lane);
201                 current = adjacentRecord;
202                 adjacentLanes = current.getLane().accessibleAdjacentLanes(latDirection, gtuType);
203             }
204         }
205         try
206         {
207             for (LaneStructureRecord record : recordSet)
208             {
209                 if (record.getStartDistance().plus(record.getLane().getLength()).ge(down))
210                 {
211                     record.setCutOffEnd(down.minus(record.getStartDistance()));
212                 }
213                 if (record.getStartDistance().le(up))
214                 {
215                     record.setCutOffStart(up.minus(record.getStartDistance()));
216                 }
217             }
218             this.ignoreSet.clear();
219             buildDownstreamRecursive(recordSet, gtuType, down, up, downSplit, upMerge);
220             this.ignoreSet.clear();
221             buildUpstreamRecursive(recordSet, gtuType, down, up, upMerge);
222         }
223         catch (GTUException | NetworkException exception)
224         {
225             throw new RuntimeException("Exception while building lane map.", exception);
226         }
227     }
228 
229     /**
230      * Extends the lane structure with the downstream lanes of the current set. Per downstream link, a new set results, which
231      * are extended laterally before performing the next downstream step. If the lateral extension finds new lanes, the
232      * structure is extended upstream from those lanes over a limited distance.
233      * 
234      * <pre>
235      *  --------- ---------
236      * |       --|-)     --|-?A       ?: possible next steps
237      *  --------- ---------
238      * |       --|-)     --|-?A
239      *  --------- =============       A, B: two separate downstream links
240      * |       --|-)         --|-?B
241      *  ----===== ------|------
242      *     | C?(-|--   \|/   --|-?B   C: extend upstream if merge
243      *      ----- -------------
244      * </pre>
245      * 
246      * @param recordSet current lateral set of records
247      * @param gtuType GTU type
248      * @param down maximum downstream distance to build structure
249      * @param up maximum upstream distance to build structure
250      * @param downSplit maximum downstream distance past split not following the route to build structure
251      * @param upMerge maximum upstream distance upstream of downstream merges to build structure
252      * @throws GTUException if an inconsistency in the lane map is encountered
253      * @throws NetworkException exception during movement over the network
254      */
255     private void buildDownstreamRecursive(final Set<LaneStructureRecord> recordSet, final GTUType gtuType, final Length down,
256             final Length up, final Length downSplit, final Length upMerge) throws GTUException, NetworkException
257     {
258         // Loop lanes and put downstream lanes in sets per downstream link
259         Map<Link, Set<Lane>> laneSets = new HashMap<>();
260         Map<Link, TreeMap<RelativeLane, LaneStructureRecord>> recordSets = new HashMap<>();
261         Map<Link, Length> maxStart = new HashMap<>();
262         for (LaneStructureRecord laneRecord : recordSet)
263         {
264             if (!laneRecord.isCutOffEnd())
265             {
266                 for (Lane nextLane : laneRecord.getLane().downstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).keySet())
267                 {
268                     Link nextLink = nextLane.getParentLink();
269                     if (!laneSets.containsKey(nextLink))
270                     {
271                         laneSets.put(nextLink, new HashSet<>());
272                         recordSets.put(nextLink, new TreeMap<>());
273                         maxStart.put(nextLink, new Length(Double.MIN_VALUE, LengthUnit.SI));
274                     }
275                     laneSets.get(nextLink).add(nextLane);
276                     RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
277                     Length start = laneRecord.getStartDistance().plus(laneRecord.getLane().getLength());
278                     maxStart.put(nextLink, Length.max(maxStart.get(nextLink), start));
279                     LaneStructureRecord nextRecord = constructRecord(nextLane,
280                             laneRecord.getLane().downstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).get(nextLane), start,
281                             relativeLane);
282                     if (start.plus(nextLane.getLength()).ge(down))
283                     {
284                         nextRecord.setCutOffEnd(down.minus(start));
285                     }
286                     recordSets.get(nextLink).put(relativeLane, nextRecord);
287                     laneRecord.addNext(nextRecord);
288                     nextRecord.addPrev(laneRecord);
289                 }
290             }
291             else
292             {
293                 for (Lane nextLane : laneRecord.getLane().downstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).keySet())
294                 {
295                     this.ignoreSet.add(nextLane); // beyond 'down', do not add in lateral step
296                 }
297             }
298         }
299         // loop links to connect the lanes laterally and continue the build
300         Link currentLink = recordSet.iterator().next().getLane().getParentLink();
301         GTUDirectionality direction = recordSet.iterator().next().getDirection();
302         Node nextNode = direction.isPlus() ? currentLink.getEndNode() : currentLink.getStartNode();
303         Route route = getGtu().getStrategicalPlanner().getRoute();
304         for (Link link : laneSets.keySet())
305         {
306             connectLaterally(recordSets.get(link), gtuType);
307             Set<LaneStructureRecord> set = new HashSet<>(recordSets.get(link).values()); // collection to set
308             // reduce remaining downstream length if not on route, to at most 'downSplit'
309             Length downLimit = down;
310             if (route != null && (!route.contains(nextNode) // if no route, do not limit
311                     || !((LaneBasedStrategicalRoutePlanner) getGtu().getStrategicalPlanner())
312                             .nextLinkDirection(nextNode, currentLink, gtuType).getLink().equals(link)))
313             {
314                 // as each lane has a separate start distance, use the maximum value from maxStart
315                 downLimit = Length.min(downLimit, maxStart.get(link).plus(downSplit));
316             }
317             else
318             {
319                 set = extendLateral(set, gtuType, down, up, upMerge, true);
320             }
321             buildDownstreamRecursive(set, gtuType, downLimit, up, downSplit, upMerge);
322         }
323     }
324 
325     /**
326      * Extends the lane structure with (multiple) left and right lanes of the current set. The extended lateral set is returned
327      * for the downstream or upstream build to continue.
328      * 
329      * <pre>
330      *  ---- ---------
331      * | ?(-|-- /|\   |
332      *  ---- ----|----   ?: extend upstream of merge if doMerge = true
333      * | ?(-|-- /|\   |
334      *  ---- ----|----  
335      *      |         | } 
336      *       ---------   } recordSet
337      *      |         | }
338      *       ----|---- 
339      *      |   \|/   |
340      *       ---------
341      * </pre>
342      * 
343      * @param recordSet current lateral set of records
344      * @param gtuType GTU type
345      * @param down maximum downstream distance to build structure
346      * @param up maximum upstream distance to build structure
347      * @param upMerge maximum upstream distance upstream of downstream merges to build structure
348      * @param downstreamBuild whether building downstream
349      * @return laterally extended set
350      * @throws GTUException if an inconsistency in the lane map is encountered
351      * @throws NetworkException exception during movement over the network
352      */
353     private Set<LaneStructureRecord> extendLateral(final Set<LaneStructureRecord> recordSet, final GTUType gtuType,
354             final Length down, final Length up, final Length upMerge, final boolean downstreamBuild)
355             throws GTUException, NetworkException
356     {
357         Set<Lane> laneSet = new HashSet<>();
358         for (LaneStructureRecord laneStructureRecord : recordSet)
359         {
360             laneSet.add(laneStructureRecord.getLane());
361         }
362         for (LateralDirectionality latDirection : new LateralDirectionality[] { LateralDirectionality.LEFT,
363                 LateralDirectionality.RIGHT })
364         {
365             Set<LaneStructureRecord> expandSet = new HashSet<>();
366             Length startDistance = null;
367             Length endDistance = null;
368             for (LaneStructureRecord laneRecord : recordSet)
369             {
370                 LaneStructureRecord current = laneRecord;
371                 startDistance = current.getStartDistance();
372                 endDistance = current.getStartDistance().plus(current.getLane().getLength());
373                 RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
374                 Set<Lane> adjacentLanes = current.getLane().accessibleAdjacentLanes(latDirection, gtuType);
375                 while (!adjacentLanes.isEmpty())
376                 {
377                     Throw.when(adjacentLanes.size() > 1, RuntimeException.class,
378                             "Multiple adjacent lanes encountered during construction of lane map.");
379                     Lane laneAdjacent = adjacentLanes.iterator().next();
380                     Length adjacentStart = downstreamBuild ? startDistance : endDistance.minus(laneAdjacent.getLength());
381                     // skip if lane is already in set, no effective length in structure, or in ignore list
382                     if (!laneSet.contains(laneAdjacent) && !adjacentStart.plus(laneAdjacent.getLength()).le(up)
383                             && !adjacentStart.ge(down) && !this.ignoreSet.contains(laneAdjacent))
384                     {
385                         laneSet.add(laneAdjacent);
386                         relativeLane = latDirection.isLeft() ? relativeLane.getLeft() : relativeLane.getRight();
387                         LaneStructureRecord recordAdjacent =
388                                 constructRecord(laneAdjacent, laneRecord.getDirection(), adjacentStart, relativeLane);
389                         expandSet.add(recordAdjacent);
390                         if (latDirection.isLeft())
391                         {
392                             if (laneAdjacent.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType)
393                                     .contains(current.getLane()))
394                             {
395                                 recordAdjacent.setRight(current);
396                             }
397                             current.setLeft(recordAdjacent);
398                         }
399                         else
400                         {
401                             if (laneAdjacent.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType)
402                                     .contains(current.getLane()))
403                             {
404                                 recordAdjacent.setLeft(current);
405                             }
406                             current.setRight(recordAdjacent);
407                         }
408                         if (adjacentStart.plus(laneAdjacent.getLength()).ge(down))
409                         {
410                             recordAdjacent.setCutOffEnd(down.minus(adjacentStart));
411                         }
412                         if (adjacentStart.le(up))
413                         {
414                             recordAdjacent.setCutOffStart(up.minus(adjacentStart));
415                         }
416                         current = recordAdjacent;
417                         adjacentLanes = current.getLane().accessibleAdjacentLanes(latDirection, gtuType);
418                     }
419                     else
420                     {
421                         break;
422                     }
423                 }
424             }
425             if (downstreamBuild & !expandSet.isEmpty())
426             {
427                 // limit search range and search upstream of merge
428                 buildUpstreamRecursive(expandSet, gtuType, down, startDistance.plus(upMerge), upMerge);
429             }
430             recordSet.addAll(expandSet);
431         }
432         return recordSet;
433     }
434 
435     /**
436      * Extends the lane structure with the upstream lanes of the current set. Per upstream link, a new set results, which are
437      * expanded laterally before performing the next upstream step.
438      * @param recordSet current lateral set of records
439      * @param gtuType GTU type
440      * @param down maximum downstream distance to build structure
441      * @param up maximum upstream distance to build structure
442      * @param upMerge maximum upstream distance upstream of downstream merges to build structure
443      * @throws GTUException if an inconsistency in the lane map is encountered
444      * @throws NetworkException exception during movement over the network
445      */
446     private void buildUpstreamRecursive(final Set<LaneStructureRecord> recordSet, final GTUType gtuType, final Length down,
447             final Length up, final Length upMerge) throws GTUException, NetworkException
448     {
449         // Loop lanes and put upstream lanes in sets per upstream link
450         Map<Link, Set<Lane>> laneSets = new HashMap<>();
451         Map<Link, TreeMap<RelativeLane, LaneStructureRecord>> recordSets = new HashMap<>();
452         Map<Link, Length> minStart = new HashMap<>();
453         for (LaneStructureRecord laneRecord : recordSet)
454         {
455             if (!laneRecord.isCutOffStart())
456             {
457                 for (Lane prevLane : laneRecord.getLane().upstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).keySet())
458                 {
459                     Link prevLink = prevLane.getParentLink();
460                     if (!laneSets.containsKey(prevLink))
461                     {
462                         laneSets.put(prevLink, new HashSet<>());
463                         recordSets.put(prevLink, new TreeMap<>());
464                         minStart.put(prevLink, new Length(Double.MAX_VALUE, LengthUnit.SI));
465                     }
466                     laneSets.get(prevLink).add(prevLane);
467                     RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
468                     Length start = laneRecord.getStartDistance().minus(prevLane.getLength());
469                     minStart.put(prevLink, Length.min(minStart.get(prevLink), start));
470                     LaneStructureRecord prevRecord = constructRecord(prevLane,
471                             laneRecord.getLane().upstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).get(prevLane), start,
472                             relativeLane);
473                     if (start.le(up))
474                     {
475                         prevRecord.setCutOffStart(up.minus(start));
476                     }
477                     recordSets.get(prevLink).put(relativeLane, prevRecord);
478                     laneRecord.addPrev(prevRecord);
479                     prevRecord.addNext(laneRecord);
480                 }
481             }
482             else
483             {
484                 for (Lane prevLane : laneRecord.getLane().upstreamLanes(GTUDirectionality.DIR_PLUS, gtuType).keySet())
485                 {
486                     this.ignoreSet.add(prevLane); // beyond 'up', do not add in lateral step
487                 }
488             }
489         }
490         // loop links to connect the lanes laterally and continue the build
491         for (Link link : laneSets.keySet())
492         {
493             connectLaterally(recordSets.get(link), gtuType);
494             Set<LaneStructureRecord> set = new HashSet<>(recordSets.get(link).values()); // collection to set
495             //set = extendLateral(set, gtuType, down, up, upMerge, false);
496             buildUpstreamRecursive(set, gtuType, down, up, upMerge);
497         }
498     }
499 
500     /**
501      * Creates a lane structure record and adds it to relevant maps.
502      * @param lane lane
503      * @param direction direction
504      * @param startDistance distance at start of record
505      * @param relativeLane relative lane
506      * @return created lane structure record
507      */
508     private LaneStructureRecord constructRecord(final Lane lane, final GTUDirectionality direction, final Length startDistance,
509             final RelativeLane relativeLane)
510     {
511         //System.out.println("Adding lane " + lane + " to structure.");
512         LaneStructureRecord record = new LaneStructureRecord(lane, direction, startDistance);
513         this.laneStructure.addLaneStructureRecord(record, relativeLane);
514         this.relativeLaneMap.put(record, relativeLane);
515         return record;
516     }
517 
518     /**
519      * Connects the lane structure records laterally if appropriate.
520      * @param map Map<RelativeLane, LaneStructureRecord>; map
521      * @param gtuType gtu type
522      */
523     private void connectLaterally(final Map<RelativeLane, LaneStructureRecord> map, final GTUType gtuType)
524     {
525         for (RelativeLane relativeLane : map.keySet())
526         {
527             if (map.containsKey(relativeLane.getRight()))
528             {
529                 Lane thisLane = map.get(relativeLane).getLane();
530                 Lane rightLane = map.get(relativeLane.getRight()).getLane();
531                 if (thisLane.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).contains(rightLane))
532                 {
533                     map.get(relativeLane).setRight(map.get(relativeLane.getRight()));
534                 }
535                 if (rightLane.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).contains(thisLane))
536                 {
537                     map.get(relativeLane.getRight()).setLeft(map.get(relativeLane));
538                 }
539             }
540         }
541     }
542 
543 }