1   package org.opentrafficsim.road.gtu.lane.perception.mental;
2   
3   import java.util.function.Supplier;
4   
5   import org.djunits.value.vdouble.scalar.Duration;
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djunits.value.vdouble.scalar.Speed;
8   import org.djutils.exceptions.Try;
9   import org.opentrafficsim.base.parameters.ParameterException;
10  import org.opentrafficsim.base.parameters.ParameterTypes;
11  import org.opentrafficsim.base.parameters.Parameters;
12  import org.opentrafficsim.core.gtu.perception.EgoPerception;
13  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
14  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
15  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.Intermediate;
16  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionAccumulator;
17  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionCollector;
18  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable.PerceptionFinalizer;
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  public abstract class TaskHeadwayBased extends AbstractTask
32  {
33  
34      
35  
36  
37  
38      public TaskHeadwayBased(final String id)
39      {
40          super(id);
41      }
42  
43      
44      private Speed speed;
45  
46      
47      @Override
48      public double calculateTaskDemand(final LanePerception perception, final LaneBasedGTU gtu, final Parameters parameters)
49              throws ParameterException
50      {
51          double a = gtu.getAcceleration().si;
52          double b = parameters.getParameter(ParameterTypes.B).si;
53          double tMin = parameters.getParameter(ParameterTypes.TMIN).si;
54          double hMin = a < -b ? (1.0 - (a + b) / (8.0 - b)) * tMin : tMin;
55          EgoPerception<?, ?> ego = perception.getPerceptionCategoryOrNull(EgoPerception.class);
56          Try.execute(() -> ego.updateSpeed(), "Could not update perception of ego speed.");
57          this.speed = ego.getSpeed();
58          Duration h = getHeadway(perception, gtu, parameters);
59          if (h == null)
60          {
61              return 0.0; 
62          }
63          return h.si <= hMin ? 1.0 : (h.si > 3.0 ? 0.5 : 1.0 - (1.0 - 0.5) * (h.si - hMin) / (3.0 - hMin));
64      }
65  
66      
67  
68  
69  
70      protected Speed getSpeed()
71      {
72          return this.speed;
73      }
74  
75      
76  
77  
78  
79  
80  
81  
82  
83      protected abstract Duration getHeadway(LanePerception perception, LaneBasedGTU gtu, Parameters parameters)
84              throws ParameterException;
85  
86      
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98      public static class TaskHeadwayCollector implements PerceptionCollector<Duration, LaneBasedGTU, Duration>
99      {
100 
101         
102         private final Speed speed;
103 
104         
105 
106 
107 
108         public TaskHeadwayCollector(final Speed speed)
109         {
110             this.speed = speed;
111         }
112 
113         
114         @Override
115         public Supplier<Duration> getIdentity()
116         {
117             return new Supplier<Duration>()
118             {
119                 @Override
120                 public Duration get()
121                 {
122                     return null; 
123                 }
124             };
125         }
126 
127         
128         @Override
129         public PerceptionAccumulator<LaneBasedGTU, Duration> getAccumulator()
130         {
131             return new PerceptionAccumulator<LaneBasedGTU, Duration>()
132             {
133                 @SuppressWarnings("synthetic-access")
134                 @Override
135                 public Intermediate<Duration> accumulate(final Intermediate<Duration> intermediate, final LaneBasedGTU object,
136                         final Length distance)
137                 {
138                     intermediate.setObject(distance.divideBy(TaskHeadwayCollector.this.speed));
139                     intermediate.stop(); 
140                     return intermediate;
141                 }
142             };
143         }
144 
145         
146         @Override
147         public PerceptionFinalizer<Duration, Duration> getFinalizer()
148         {
149             return new PerceptionFinalizer<Duration, Duration>()
150             {
151                 @Override
152                 public Duration collect(final Duration intermediate)
153                 {
154                     return intermediate == null ? intermediate : (intermediate.gt0() ? intermediate : Duration.ZERO);
155                 }
156             };
157         }
158 
159     }
160 
161 }