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
23
24
25
26
27
28
29
30
31 public class ChannelTaskSignal extends AbstractTask implements ChannelTask
32 {
33
34
35 public static final ParameterTypeDouble TDSIGNAL =
36 new ParameterTypeDouble("td_signal", "Signal task demand", 0.2, NumericConstraint.POSITIVEZERO);
37
38
39 public static final ParameterTypeLength X0_D = ChannelMental.X0_D;
40
41
42 private static final Set<ChannelTask> SET =
43 Set.of(new ChannelTaskSignal(LEFT), new ChannelTaskSignal(RIGHT), new ChannelTaskSignal(FRONT));
44
45
46 public static final Function<LanePerception, Set<ChannelTask>> SUPPLIER = (p) -> SET;
47
48
49 private final Object channel;
50
51
52 private final Predicate<LaneBasedGtu> predicate;
53
54
55 private final RelativeLane lane;
56
57
58
59
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 }