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.headway.Headway; 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 <H> headway type 20 * @param <U> underlying object type 21 */ 22 public interface PerceptionCollectable<H extends Headway, U> extends PerceptionIterable<H> 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 interface PerceptionAccumulator<U, I> 93 { 94 /** 95 * Accumulate the next object to intermediate result. 96 * @param intermediate intermediate result before accumulation of object 97 * @param object next object to include 98 * @param distance distance to the considered object 99 * @return intermediate result after accumulation of object 100 */ 101 Intermediate<I> accumulate(Intermediate<I> intermediate, U object, Length distance); 102 } 103 104 /** 105 * Wrapper of intermediate result with info for the iterator algorithm. 106 * @param <I> intermediate result type 107 */ 108 class Intermediate<I> 109 { 110 /** Number of underlying object being iterated. */ 111 private int number = 0; 112 113 /** Intermediate object. */ 114 private I object; 115 116 /** Whether to stop accumulating. */ 117 private boolean stop = false; 118 119 /** 120 * Constructor. 121 * @param object identity value 122 */ 123 public Intermediate(final I object) 124 { 125 this.object = object; 126 } 127 128 /** 129 * Get intermediate object. 130 * @return intermediate object 131 */ 132 public I getObject() 133 { 134 return this.object; 135 } 136 137 /** 138 * Set intermediate object. 139 * @param object intermediate object 140 */ 141 public void setObject(final I object) 142 { 143 this.object = object; 144 } 145 146 /** 147 * Returns the number of the underlying object currently being accumulated, starts at 0 for the first. 148 * @return number of the underlying object currently being accumulated 149 */ 150 public int getNumber() 151 { 152 return this.number; 153 } 154 155 /** 156 * Method for the iterator to increase the underlying object number. 157 */ 158 public void step() 159 { 160 this.number++; 161 } 162 163 /** 164 * Method for the accumulator to indicate the iterator can stop. 165 */ 166 public void stop() 167 { 168 this.stop = true; 169 } 170 171 /** 172 * Method for the iterator to check if it can stop. 173 * @return whether the iterator can stop 174 */ 175 public boolean isStop() 176 { 177 return this.stop; 178 } 179 } 180 181 /** 182 * Wrapper for object and its distance. 183 * @param object underlying object 184 * @param distance distance to object 185 * @param <U> underlying object type 186 */ 187 record UnderlyingDistance<U>(U object, Length distance) implements Comparable<UnderlyingDistance<U>> 188 { 189 @Override 190 public int compareTo(final UnderlyingDistance<U> o) 191 { 192 int out = this.distance.compareTo(o.distance); 193 if (out != 0) 194 { 195 return out; 196 } 197 if (this.object == null) 198 { 199 if (o.object == null) 200 { 201 return 0; 202 } 203 return -1; 204 } 205 if (o.object == null) 206 { 207 return 1; 208 } 209 return Integer.compare(this.object.hashCode(), o.object.hashCode()); 210 } 211 } 212 213 }