View Javadoc
1   package org.opentrafficsim.road.gtu.perception.mental.channel;
2   
3   import java.util.Iterator;
4   import java.util.NoSuchElementException;
5   import java.util.Set;
6   import java.util.function.Function;
7   import java.util.function.Predicate;
8   
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.opentrafficsim.base.DistancedObject;
11  import org.opentrafficsim.base.OtsRuntimeException;
12  import org.opentrafficsim.base.parameters.ParameterTypeDouble;
13  import org.opentrafficsim.base.parameters.ParameterTypeLength;
14  import org.opentrafficsim.base.parameters.constraint.NumericConstraint;
15  import org.opentrafficsim.road.gtu.LaneBasedGtu;
16  import org.opentrafficsim.road.gtu.perception.LanePerception;
17  import org.opentrafficsim.road.gtu.perception.RelativeLane;
18  import org.opentrafficsim.road.gtu.perception.categories.neighbors.NeighborsPerception;
19  import org.opentrafficsim.road.gtu.perception.mental.AbstractTask;
20  
21  /**
22   * Task demand for signal (front: brake lights, left: right indicator, right: left indicator). This applies to the first leader
23   * with signal, and is defined as {@code TD_signal * (1 - s/x0)}, where {@code TD_signal} is a constant, {@code s} is the
24   * distance to the leader with signal and {@code x0} is the look-ahead distance.
25   * <p>
26   * Copyright (c) 2024-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * </p>
29   * @author Wouter Schakel
30   */
31  public class ChannelTaskSignal extends AbstractTask implements ChannelTask
32  {
33  
34      /** Signal task demand. */
35      public static final ParameterTypeDouble TDSIGNAL =
36              new ParameterTypeDouble("td_signal", "Signal task demand", 0.2, NumericConstraint.POSITIVEZERO);
37  
38      /** Distance discount range. */
39      public static final ParameterTypeLength X0_D = ChannelMental.X0_D;
40  
41      /** Standard set of left, right and front signal task. */
42      private static final Set<ChannelTask> SET =
43              Set.of(new ChannelTaskSignal(LEFT), new ChannelTaskSignal(RIGHT), new ChannelTaskSignal(FRONT));
44  
45      /** Standard supplier that supplies instances for left, right and front signal task. */
46      public static final Function<LanePerception, Set<ChannelTask>> SUPPLIER = (p) -> SET;
47  
48      /** Channel. */
49      private final Object channel;
50  
51      /** Predicate to test the signal on a GTU. */
52      private final Predicate<LaneBasedGtu> predicate;
53  
54      /** Relative lane that applies. */
55      private final RelativeLane lane;
56  
57      /**
58       * Constructor.
59       * @param channel channel.
60       */
61      public ChannelTaskSignal(final Object channel)
62      {
63          super("signal");
64          this.channel = channel;
65          if (channel.equals(FRONT))
66          {
67              this.predicate = (t) -> t.isBrakingLightsOn();
68              this.lane = RelativeLane.CURRENT;
69          }
70          else if (channel.equals(LEFT))
71          {
72              this.predicate = (t) -> t.getTurnIndicatorStatus().isRightOrBoth();
73              this.lane = RelativeLane.LEFT;
74          }
75          else if (channel.equals(RIGHT))
76          {
77              this.predicate = (t) -> t.getTurnIndicatorStatus().isLeftOrBoth();
78              this.lane = RelativeLane.RIGHT;
79          }
80          else
81          {
82              throw new IllegalArgumentException("Channel " + channel + " is not supported by signal channel.");
83          }
84      }
85  
86      @Override
87      public String getId()
88      {
89          return String.format("signal (%s)", this.channel);
90      }
91  
92      @Override
93      public Object getChannel()
94      {
95          return this.channel;
96      }
97  
98      @Override
99      public double calculateTaskDemand(final LanePerception perception)
100     {
101         NeighborsPerception neighbors = perception.getPerceptionCategoryOptional(NeighborsPerception.class)
102                 .orElseThrow(() -> new NoSuchElementException("NeighborsPerception not present."));
103         Iterator<DistancedObject<LaneBasedGtu>> leaders = neighbors.getLeaders(this.lane).underlyingWithDistance();
104         while (leaders.hasNext())
105         {
106             DistancedObject<LaneBasedGtu> leader = leaders.next();
107             if (this.predicate.test(leader.object()))
108             {
109                 Length x0 = perception.getGtu().getParameters().getOptionalParameter(X0_D)
110                         .orElseThrow(() -> new OtsRuntimeException("Parameter x0_d not present."));
111                 double tdSignal = perception.getGtu().getParameters().getOptionalParameter(TDSIGNAL)
112                         .orElseThrow(() -> new OtsRuntimeException("Parameter td_signal not available."));
113                 return tdSignal * (1.0 - leader.distance().si / x0.si);
114             }
115         }
116         return 0.0;
117     }
118 
119 }