View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.io.Serializable;
4   import java.util.HashMap;
5   import java.util.HashSet;
6   import java.util.Iterator;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.SortedSet;
10  import java.util.TreeMap;
11  
12  import org.djunits.value.vdouble.scalar.Length;
13  import org.djunits.value.vdouble.scalar.Time;
14  import org.opentrafficsim.core.gtu.GTUException;
15  import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
16  
17  import nl.tudelft.simulation.language.Throw;
18  
19  /**
20   * This data structure can clearly indicate the lane structure ahead of us, e.g. in the following situation:
21   * 
22   * <pre>
23   *     (---- a ----)(---- b ----)(---- c ----)(---- d ----)(---- e ----)(---- f ----)(---- g ----)  
24   *                                             __________                             __________
25   *                                            / _________ 1                          / _________ 2
26   *                                           / /                                    / /
27   *                                __________/ /             _______________________/ /
28   *  1  ____________ ____________ /_ _ _ _ _ _/____________ /_ _ _ _ _ _ _ _ _ _ _ _ /      
29   *  0 |_ _X_ _ _ _ |_ _ _ _ _ _ |_ _ _ _ _ _ |_ _ _ _ _ _ |_ _ _ _ _ _ |_ _ _ _ _ _ \____________
30   * -1 |____________|_ _ _ _ _ _ |____________|____________|  __________|____________|____________| 3
31   * -2              / __________/                           \ \  
32   *        ________/ /                                       \ \___________  
33   *      5 _________/                                         \____________  4
34   * </pre>
35   * 
36   * When the GTU is looking ahead, it needs to know that when it continues to destination 3, it needs to shift one lane to the
37   * right at some point, but <b>not</b> two lanes to the right in link b, and not later than at the end of link f. When it needs
38   * to go to destination 1, it needs to shift to the left in link c. When it has to go to destination 2, it has to shift to the
39   * left, but not earlier than at link e. At node [de], it is possible to leave the rightmost lane of link e, and go to
40   * destination 4. The rightmost lane just splits into two lanes at the end of link d, and the GTU can either continue driving to
41   * destination 3, turn right to destination 4. This means that the right lane of link d has <b>two</b> successor lanes.
42   * <p>
43   * In the data structures, lanes are numbered laterally. Suppose that the lane where vehicle X resides would be number 0.
44   * Consistent with "left is positive" for angles, the lane right of X would have number -1, and entry 5 would have number -2.
45   * <p>
46   * In the data structure, this can be indicated as follows (N = next, P = previous, L = left, R = right, D = lane drop, . =
47   * continued but not in this structure). The merge lane in b is considered "off limits" for the GTUs on the "main" lane -1; the
48   * "main" lane 0 is considered off limits from the exit lanes on c, e, and f. Still, we need to maintain pointers to these
49   * lanes, as we are interested in the GTUs potentially driving next to us, feeding into our lane, etc.
50   * 
51   * <pre>
52   *       1                0               -1               -2
53   *       
54   *                       ROOT 
55   *                   _____|_____      ___________      ___________            
56   *                  |_-_|_._|_R_|----|_L_|_._|_-_|    |_-_|_._|_-_|  a           
57   *                        |                |                |
58   *                   _____V_____      _____V_____      _____V_____            
59   *                  |_-_|_N_|_R_|----|_L_|_N_|_R_|&lt;---|_L_|_D_|_-_|  b           
60   *                        |                |                 
61   *  ___________      _____V_____      _____V_____                 
62   * |_-_|_N_|_R_|&lt;---|_L_|_N_|_R_|----|_L_|_N_|_-_|                   c
63   *       |                |                |                 
64   *  _____V_____      _____V_____      _____V_____                 
65   * |_-_|_._|_-_|    |_-_|_N_|_R_|----|_L_|_NN|_-_|                   d          
66   *                        |                ||_______________ 
67   *  ___________      _____V_____      _____V_____      _____V_____            
68   * |_-_|_N_|_R_|&lt;---|_L_|_N_|_R_|----|_L_|_N_|_-_|    |_-_|_N_|_-_|  e          
69   *       |                |                |                |
70   *  _____V_____      _____V_____      _____V_____      _____V_____            
71   * |_-_|_N_|_R_|&lt;---|_L_|_D_|_R_|----|_L_|_N_|_-_|    |_-_|_._|_-_|  f          
72   *       |                                 |                 
73   *  _____V_____                       _____V_____                             
74   * |_-_|_._|_-_|                     |_-_|_._|_-_|                   g
75   * 
76   * 
77   * </pre>
78   * <p>
79   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
80   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
81   * </p>
82   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
83   * initial version Feb 20, 2016 <br>
84   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
85   */
86  public class LaneStructure implements EnvironmentState, Serializable
87  {
88      /** */
89      private static final long serialVersionUID = 20160400L;
90  
91      /** The lanes from which we observe the situation. */
92      private LaneStructureRecord rootLSR;
93      
94      /** Look ahead distance. */
95      private Length lookAhead;
96      
97      /** Lane structure records of the cross section. */
98      private TreeMap<RelativeLane, LaneStructureRecord> crossSectionRecords = new TreeMap<>();
99  
100 //    /** Time of last cross section update. */
101 //    private Time crossSectionUpdateTime;
102     
103     /** Lane structure records grouped per relative lane. */
104     private final Map<RelativeLane, Set<LaneStructureRecord>> relativeLaneMap = new HashMap<>(); 
105 
106     /**
107      * @param rootLSR the root record.
108      * @param lookAhead look ahead distance
109      */
110     public LaneStructure(final LaneStructureRecord rootLSR, final Length lookAhead)
111     {
112         this.rootLSR = rootLSR;
113         this.lookAhead = lookAhead;
114     }
115     
116     /**
117      * @return rootLSR
118      */
119     public final LaneStructureRecord getRootLSR()
120     {
121         return this.rootLSR;
122     }
123 
124     /**
125      * Returns the cross section.
126      * @return cross section
127      */
128     public final SortedSet<RelativeLane> getCrossSection()
129     {
130         //updateCrossSection(now);
131         return this.crossSectionRecords.navigableKeySet();
132     }
133     
134 //    /**
135 //     * @param now current time to check if the cross section needs to be updated
136 //     */
137 //    private void updateCrossSection(final Time now)
138 //    {
139 //        if (this.crossSectionRecords == null || now.gt(this.crossSectionUpdateTime))
140 //        {
141 //            this.crossSectionRecords = new TreeMap<>();
142 //            // current lane
143 //            this.crossSectionRecords.put(RelativeLane.CURRENT, getRootLSR());
144 //            // left
145 //            LaneStructureRecord lane = getRootLSR();
146 //            int left = 1;
147 //            while (lane.getLeft() != null)
148 //            {
149 //                RelativeLane relLane = new RelativeLane(LateralDirectionality.LEFT, left);
150 //                this.crossSectionRecords.put(relLane, lane.getLeft());
151 //                left++;
152 //                lane = lane.getLeft();
153 //            }
154 //            addFirstMergeToCrossSection(lane, LateralDirectionality.LEFT, left);
155 //            // right
156 //            lane = getRootLSR();
157 //            int right = 1;
158 //            while (lane.getRight() != null)
159 //            {
160 //                RelativeLane relLane = new RelativeLane(LateralDirectionality.RIGHT, right);
161 //                this.crossSectionRecords.put(relLane, lane.getRight());
162 //                right++;
163 //                lane = lane.getRight();
164 //            }
165 //            addFirstMergeToCrossSection(lane, LateralDirectionality.RIGHT, right);
166 //        }
167 //    }
168 //    
169 //    /**
170 //     * Adds a single lane of the other link to the current cross section at a merge.
171 //     * @param farMost record on far-most left or right side of current link
172 //     * @param dir direction to search in, left or right
173 //     * @param n number of lanes in left or right direction that the next lane will be
174 //     */
175 //    private void
176 //        addFirstMergeToCrossSection(final LaneStructureRecord farMost, final LateralDirectionality dir, final int n)
177 //    {
178 //        Length cumulLengthDown = farMost.getLane().getLength();
179 //        LaneStructureRecord next = getNextOnSide(farMost, dir);
180 //        LaneStructureRecord mergeRecord = null; // first downstream record past merge
181 //        while (next != null)
182 //        {
183 //            if (next.isLinkMerge())
184 //            {
185 //                mergeRecord = next;
186 //                next = null;
187 //            }
188 //            else
189 //            {
190 //                cumulLengthDown = cumulLengthDown.plus(next.getLane().getLength());
191 //                next = getNextOnSide(next, dir);
192 //            }
193 //        }
194 //        if (mergeRecord != null)
195 //        {
196 //            LaneStructureRecord adjacentRecord =
197 //                dir.equals(LateralDirectionality.LEFT) ? mergeRecord.getLeft() : mergeRecord.getRight();
198 //            if (adjacentRecord == null)
199 //            {
200 //                // merge is on other side, add nothing
201 //                return;
202 //            }
203 //            adjacentRecord = getPrevOnSide(adjacentRecord, dir);
204 //            Length cumulLengthUp = Length.ZERO;
205 //            while (adjacentRecord != null)
206 //            {
207 //                cumulLengthUp = cumulLengthUp.plus(adjacentRecord.getLane().getLength());
208 //                if (cumulLengthUp.ge(cumulLengthDown))
209 //                {
210 //                    RelativeLane relLane = new RelativeLane(dir, n);
211 //                    this.crossSectionRecords.put(relLane, adjacentRecord);
212 //                    return;
213 //                }
214 //                adjacentRecord = getPrevOnSide(adjacentRecord, dir);
215 //            }
216 //        }
217 //    }
218 //    
219 //    /**
220 //     * Returns the correct next record for searching the next merge.
221 //     * @param lane current lane record
222 //     * @param dir direction of search
223 //     * @return correct next record for searching the next merge
224 //     */
225 //    private LaneStructureRecord getNextOnSide(final LaneStructureRecord lane, final LateralDirectionality dir)
226 //    {
227 //        if (lane.getNext().size() == 1)
228 //        {
229 //            return lane.getNext().get(0);
230 //        }
231 //        for (LaneStructureRecord next : lane.getNext())
232 //        {
233 //            if ((dir.equals(LateralDirectionality.LEFT) && next.getLeft() == null)
234 //                || (dir.equals(LateralDirectionality.RIGHT) && next.getRight() == null))
235 //            {
236 //                return next;
237 //            }
238 //        }
239 //        return null;
240 //    }
241 //    
242 //    /**
243 //     * Returns the correct previous record for searching upstream from the next merge.
244 //     * @param lane current lane record
245 //     * @param dir direction of search
246 //     * @return correct previous record for searching upstream from the next merge
247 //     */
248 //    private LaneStructureRecord getPrevOnSide(final LaneStructureRecord lane, final LateralDirectionality dir)
249 //    {
250 //        if (lane.getPrev().size() == 1)
251 //        {
252 //            return lane.getPrev().get(0);
253 //        }
254 //        for (LaneStructureRecord prev : lane.getPrev())
255 //        {
256 //            // note: looking left from current link, requires looking right from left adjacent link at merge
257 //            if ((dir.equals(LateralDirectionality.LEFT) && prev.getRight() == null)
258 //                || (dir.equals(LateralDirectionality.RIGHT) && prev.getLeft() == null))
259 //            {
260 //                return prev;
261 //            }
262 //        }
263 //        return null;
264 //    }
265     
266     /**
267      * @param lane lane to check
268      * @param now current time to check if the cross section needs to be updated
269      * @return record at given lane
270      * @throws GTUException if the lane is not in the cross section
271      */
272     public final LaneStructureRecord getLaneLSR(final RelativeLane lane, final Time now)  throws GTUException
273     {
274         //updateCrossSection(now);
275         Throw.when(!this.crossSectionRecords.containsKey(lane), GTUException.class,
276             "The requested lane %s is not in the most recent cross section.", lane);
277         return this.crossSectionRecords.get(lane);
278     }
279     
280     /**
281      * Removes all mappings to relative lanes that are not in the most recent cross section.
282      * @param map map to clear mappings from
283      */
284     public final void removeInvalidMappings(final Map<RelativeLane, ?> map)
285     {
286         Iterator<RelativeLane> iterator = map.keySet().iterator();
287         while (iterator.hasNext())
288         {
289             RelativeLane lane = iterator.next();
290             if (!this.crossSectionRecords.containsKey(lane))
291             {
292                 iterator.remove();
293             }
294         }
295     }
296 
297     /**
298      * Adds a lane structure record in a mapping from relative lanes.
299      * @param lsr lane structure record
300      * @param relativeLane relative lane
301      */
302     public final void addLaneStructureRecord(final LaneStructureRecord lsr, final RelativeLane relativeLane)
303     {
304         if (!this.relativeLaneMap.containsKey(relativeLane))
305         {
306             this.relativeLaneMap.put(relativeLane, new HashSet<>());
307         }
308         this.relativeLaneMap.get(relativeLane).add(lsr);
309         if (lsr.getStartDistance().le(Length.ZERO) && lsr.getStartDistance().plus(lsr.getLane().getLength()).ge(Length.ZERO))
310         {
311             this.crossSectionRecords.put(relativeLane, lsr);
312         }
313     }
314     
315     /**
316      * {@inheritDoc} 
317      * Returns objects over a maximum length of the look ahead distance downstream, or as far as the lane map goes. Upstream,
318      * only the map limits included objects.
319      */
320     @Override
321     public final <T extends LaneBasedObject> TreeMap<Length, Set<T>> getSortedObjects(final ViewingDirection viewingDirection,
322             final RelativeLane relativeLane, final Class<T> clazz)
323     {
324         // TODO
325         return new TreeMap<>();
326     }
327     
328     /** {@inheritDoc} */
329     @Override
330     public final String toString()
331     {
332         return "LaneStructure [rootLSR=" + this.rootLSR + "]";
333     }
334 }