View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.util.Iterator;
4   import java.util.function.Function;
5   import java.util.function.Supplier;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.opentrafficsim.road.gtu.lane.perception.object.PerceivedObject;
9   
10  /**
11   * Iterable that additionally provides support for PerceptionCollectors. These gather raw data, to only 'perceive' the result.
12   * <p>
13   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
15   * </p>
16   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
17   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
18   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
19   * @param <P> perceived object type
20   * @param <U> underlying object type
21   */
22  public interface PerceptionCollectable<P extends PerceivedObject, U> extends PerceptionIterable<P>
23  {
24  
25      /**
26       * Collect the underlying objects in to a perceived result. This methodology is loosely based on Stream.collect().
27       * @param collector collector
28       * @param <C> collection result type
29       * @param <I> intermediate type
30       * @return collection result
31       */
32      default <C, I> C collect(final PerceptionCollector<C, ? super U, I> collector)
33      {
34          return collect(collector.getIdentity(), collector.getAccumulator(), collector.getFinalizer());
35      }
36  
37      /**
38       * Collect the underlying objects in to a perceived result. This methodology is loosely based on Stream.collect().
39       * @param identity the initial intermediate result value
40       * @param accumulator accumulator
41       * @param finalizer finalizer
42       * @param <C> collection result type
43       * @param <I> intermediate type
44       * @return collection result
45       */
46      <C, I> C collect(Supplier<I> identity, PerceptionAccumulator<? super U, I> accumulator, Function<I, C> finalizer);
47  
48      /**
49       * Returns an iterator over the underlying objects.
50       * @return iterator
51       */
52      Iterator<U> underlying();
53  
54      /**
55       * Returns an iterator over the underlying objects coupled with the distance.
56       * @return iterator
57       */
58      Iterator<UnderlyingDistance<U>> underlyingWithDistance();
59  
60      /**
61       * Combination of an accumulator and a finalizer.
62       * @param <C> collection result type
63       * @param <U> underlying object type
64       * @param <I> intermediate result type
65       */
66      interface PerceptionCollector<C, U, I>
67      {
68          /**
69           * Returns the identity value, the initial intermediate value.
70           * @return identity value, the initial intermediate value
71           */
72          Supplier<I> getIdentity();
73  
74          /**
75           * Returns the accumulator.
76           * @return accumulator
77           */
78          PerceptionAccumulator<U, I> getAccumulator();
79  
80          /**
81           * Returns the finalizer.
82           * @return finalizer
83           */
84          Function<I, C> getFinalizer();
85      }
86  
87      /**
88       * Accumulates an object one at a time in to an accumulating intermediate result.
89       * @param <U> underlying object type
90       * @param <I> intermediate result type
91       */
92      @FunctionalInterface
93      interface PerceptionAccumulator<U, I>
94      {
95          /**
96           * Accumulate the next object to intermediate result.
97           * @param intermediate intermediate result before accumulation of object
98           * @param object next object to include
99           * @param distance distance to the considered object
100          * @return intermediate result after accumulation of object
101          */
102         Intermediate<I> accumulate(Intermediate<I> intermediate, U object, Length distance);
103     }
104 
105     /**
106      * Wrapper of intermediate result with info for the iterator algorithm.
107      * @param <I> intermediate result type
108      */
109     class Intermediate<I>
110     {
111         /** Number of underlying objects being iterated. */
112         private int number = 0;
113 
114         /** Intermediate object. */
115         private I object;
116 
117         /** Whether to stop accumulating. */
118         private boolean stop = false;
119 
120         /**
121          * Constructor.
122          * @param object identity value
123          */
124         public Intermediate(final I object)
125         {
126             this.object = object;
127         }
128 
129         /**
130          * Get intermediate object.
131          * @return intermediate object
132          */
133         public I getObject()
134         {
135             return this.object;
136         }
137 
138         /**
139          * Set intermediate object.
140          * @param object intermediate object
141          */
142         public void setObject(final I object)
143         {
144             this.object = object;
145         }
146 
147         /**
148          * Returns the number of the underlying object currently being accumulated, starts at 0 for the first.
149          * @return number of the underlying object currently being accumulated
150          */
151         public int getNumber()
152         {
153             return this.number;
154         }
155 
156         /**
157          * Method for the iterator to increase the underlying object number.
158          */
159         public void step()
160         {
161             this.number++;
162         }
163 
164         /**
165          * Method for the accumulator to indicate the iterator can stop.
166          */
167         public void stop()
168         {
169             this.stop = true;
170         }
171 
172         /**
173          * Method for the iterator to check if it can stop.
174          * @return whether the iterator can stop
175          */
176         public boolean isStop()
177         {
178             return this.stop;
179         }
180     }
181 
182     /**
183      * Wrapper for object and its distance.
184      * @param object underlying object
185      * @param distance distance to object
186      * @param <U> underlying object type
187      */
188     record UnderlyingDistance<U>(U object, Length distance) implements Comparable<UnderlyingDistance<U>>
189     {
190         @Override
191         public int compareTo(final UnderlyingDistance<U> o)
192         {
193             int out = this.distance.compareTo(o.distance);
194             if (out != 0)
195             {
196                 return out;
197             }
198             if (this.object == null)
199             {
200                 if (o.object == null)
201                 {
202                     return 0;
203                 }
204                 return -1;
205             }
206             if (o.object == null)
207             {
208                 return 1;
209             }
210             return Integer.compare(this.object.hashCode(), o.object.hashCode());
211         }
212     }
213 
214 }