View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.util.LinkedHashSet;
4   import java.util.List;
5   import java.util.Set;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.opentrafficsim.core.gtu.RelativePosition;
9   import org.opentrafficsim.core.network.route.Route;
10  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
11  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
12  import org.opentrafficsim.road.gtu.lane.perception.structure.LaneRecordInterface;
13  import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
14  
15  /**
16   * Iterable that searches downstream or upstream for a certain type of lane based object.
17   * <p>
18   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
19   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
20   * </p>
21   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
22   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
23   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
24   * @param <H> headway type
25   * @param <L> lane based object type
26   */
27  public abstract class LaneBasedObjectIterable<H extends Headway, L extends LaneBasedObject>
28          extends AbstractPerceptionIterable<H, L, Boolean>
29  {
30  
31      /** Margin for start and end of lane. */
32      private static final Length MARGIN = Length.instantiateSI(1e-9);
33  
34      /** Class of lane based objects to return. */
35      private final Class<L> clazz;
36  
37      /**
38       * Constructor.
39       * @param perceivingGtu LaneBasedGtu; perceiving GTU
40       * @param clazz Class&lt;L&gt;; class of lane based objects to return
41       * @param root LaneRecord&lt;?&gt;; root record
42       * @param initialPosition Length; initial position
43       * @param downstream boolean; downstream
44       * @param maxDistance Length; max distance to search
45       * @param relativePosition RelativePosition; relative position
46       * @param route Route; route of the GTU, may be {@code null}
47       */
48      public LaneBasedObjectIterable(final LaneBasedGtu perceivingGtu, final Class<L> clazz, final LaneRecordInterface<?> root,
49              final Length initialPosition, final boolean downstream, final Length maxDistance,
50              final RelativePosition relativePosition, final Route route)
51      {
52          super(perceivingGtu, root, initialPosition, downstream, maxDistance, relativePosition, route);
53          this.clazz = clazz;
54      }
55  
56      /** {@inheritDoc} */
57      @SuppressWarnings("unchecked")
58      @Override
59      protected Entry getNext(final LaneRecordInterface<?> record, final Length position, final Boolean counter)
60      {
61          List<LaneBasedObject> list;
62          if (isDownstream())
63          {
64              if (!record.isDownstreamBranch())
65              {
66                  return null;
67              }
68              Length pos = position.eq0() && counter == null ? MARGIN.neg() : position;
69              list = record.getLane().getObjectAhead(pos);
70          }
71          else
72          {
73              Length pos = position.eq(record.getLane().getLength()) && counter == null
74                      ? record.getLane().getLength().plus(MARGIN) : position;
75              list = record.getLane().getObjectBehind(pos);
76          }
77          while (list != null)
78          {
79              Set<L> set = new LinkedHashSet<>();
80              Length pos = list.get(0).getLongitudinalPosition();
81              for (LaneBasedObject object : list)
82              {
83                  if (this.clazz.isAssignableFrom(object.getClass()))
84                  {
85                      // is assignable, so safe cast
86                      set.add((L) object);
87                  }
88              }
89              if (!set.isEmpty())
90              {
91                  if (set.size() == 1)
92                  {
93                      return new Entry(set.iterator().next(), true, pos);
94                  }
95                  return new Entry(set, true, pos);
96              }
97              if (isDownstream())
98              {
99                  list = record.getLane().getObjectAhead(pos);
100             }
101             else
102             {
103                 list = record.getLane().getObjectBehind(pos);
104             }
105         }
106         return null;
107     }
108 
109     /** {@inheritDoc} */
110     @Override
111     protected final Length getDistance(final L object, final LaneRecordInterface<?> record, final Length position)
112     {
113         return isDownstream() ? record.getDistanceToPosition(position).minus(getDx())
114                 : record.getDistanceToPosition(position).neg().plus(getDx());
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public String toString()
120     {
121         return "LaneBasedObjectIterable [class=" + this.clazz + ", downstream=" + isDownstream() + "]";
122     }
123 
124 }