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