View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.util.HashMap;
4   import java.util.Iterator;
5   import java.util.Map;
6   import java.util.NoSuchElementException;
7   import java.util.SortedMap;
8   import java.util.TreeMap;
9   
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.opentrafficsim.base.parameters.ParameterException;
12  import org.opentrafficsim.core.gtu.GTUException;
13  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
14  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
15  
16  /**
17   * Iterable class to search over multiple lanes.
18   * <p>
19   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
21   * <p>
22   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 20 feb. 2018 <br>
23   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
24   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
25   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
26   * @param <H> headway type
27   * @param <U> underlying headway type
28   */
29  public class MultiLanePerceptionIterable<H extends Headway, U> extends AbstractPerceptionReiterable<H, U>
30  {
31  
32      /** Set of iterators per lane. */
33      final Map<RelativeLane, Iterator<PrimaryIteratorEntry>> iterators = new HashMap<>();
34  
35      /** Map of lane per object. */
36      final Map<U, RelativeLane> laneMap = new HashMap<>();
37  
38      /** Map of iterable per lane. */
39      final Map<RelativeLane, AbstractPerceptionReiterable<H, U>> iterables = new HashMap<>();
40  
41      /**
42       * Constructor.
43       * @param perceivingGtu LaneBasedGTU; perceiving GTU
44       */
45      public MultiLanePerceptionIterable(final LaneBasedGTU perceivingGtu)
46      {
47          super(perceivingGtu);
48      }
49  
50      /**
51       * Adds an iterable for a lane.
52       * @param lane Lane; lane
53       * @param iterable AbstractPerceptionReiterable; iterable
54       */
55      public void addIterable(final RelativeLane lane, final AbstractPerceptionReiterable<H, U> iterable)
56      {
57          this.iterators.put(lane, iterable.getPrimaryIterator());
58          this.iterables.put(lane, iterable);
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      public Iterator<PrimaryIteratorEntry> primaryIterator()
64      {
65          return new MultiLaneIterator();
66      }
67  
68      /**
69       * Iterator that returns the closest element from a set of lanes.
70       * <p>
71       * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
72       * <br>
73       * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
74       * <p>
75       * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
76       * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
77       * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
78       * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
79       */
80      private class MultiLaneIterator implements Iterator<PrimaryIteratorEntry>
81      {
82  
83          /** Sorted elements per lane. */
84          SortedMap<PrimaryIteratorEntry, RelativeLane> elements;
85  
86          /** Constructor. */
87          public MultiLaneIterator()
88          {
89              //
90          }
91  
92          /** {@inheritDoc} */
93          @Override
94          public boolean hasNext()
95          {
96              assureNext();
97              return !this.elements.isEmpty();
98          }
99  
100         /** {@inheritDoc} */
101         @Override
102         public PrimaryIteratorEntry next()
103         {
104             assureNext();
105             if (this.elements.isEmpty())
106             {
107                 throw new NoSuchElementException();
108             }
109 
110             // get and remove next
111             PrimaryIteratorEntry next = this.elements.firstKey();
112             RelativeLane lane = this.elements.get(next);
113             this.elements.remove(next);
114 
115             // prepare next
116             Iterator<PrimaryIteratorEntry> laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane);
117             if (laneIterator != null)
118             {
119                 if (laneIterator.hasNext())
120                 {
121                     this.elements.put(laneIterator.next(), lane);
122                 }
123                 else
124                 {
125                     // remove it, it has no more elements to offer
126                     MultiLanePerceptionIterable.this.iterators.remove(lane);
127                 }
128             }
129 
130             MultiLanePerceptionIterable.this.laneMap.put(next.object, lane);
131             return next;
132         }
133 
134         /**
135          * Starts the process.
136          */
137         public void assureNext()
138         {
139             if (this.elements == null)
140             {
141                 this.elements = new TreeMap<>();
142                 for (RelativeLane lane : MultiLanePerceptionIterable.this.iterators.keySet())
143                 {
144                     Iterator<PrimaryIteratorEntry> laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane);
145                     if (laneIterator.hasNext())
146                     {
147                         this.elements.put(laneIterator.next(), lane);
148                     }
149                 }
150             }
151         }
152 
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public H perceive(final LaneBasedGTU perceivingGtu, final U object, final Length distance)
158             throws GTUException, ParameterException
159     {
160         return this.iterables.get(this.laneMap.get(object)).perceive(perceivingGtu, object, distance);
161     }
162 }