1 package org.opentrafficsim.road.gtu.lane.perception.mental;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashMap;
5 import java.util.LinkedHashSet;
6 import java.util.Map;
7 import java.util.OptionalDouble;
8 import java.util.Set;
9 import java.util.function.BiFunction;
10
11 import org.djunits.value.vdouble.scalar.Duration;
12 import org.djunits.value.vdouble.scalar.Length;
13 import org.djutils.event.Event;
14 import org.djutils.event.EventListener;
15 import org.opentrafficsim.base.parameters.ParameterException;
16 import org.opentrafficsim.core.gtu.RelativePosition;
17 import org.opentrafficsim.core.network.LateralDirectionality;
18 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
19 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
20 import org.opentrafficsim.road.gtu.lane.perception.structure.LaneStructure;
21 import org.opentrafficsim.road.gtu.lane.perception.structure.NavigatingIterable.Entry;
22 import org.opentrafficsim.road.network.lane.object.RoadSideDistraction;
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class DistractionField implements EventListener
37 {
38
39
40 private final LaneBasedGtu gtu;
41
42
43 private Duration updateTime = null;
44
45
46 private final Map<RoadSideDistraction, Double> odos = new LinkedHashMap<>();
47
48
49 private final Map<RoadSideDistraction, Double> taskDemands = new LinkedHashMap<>();
50
51
52 private Map<RelativeLane, Set<RoadSideDistraction>> lanes = new LinkedHashMap<>();
53
54
55
56
57
58 public DistractionField(final LaneBasedGtu gtu)
59 {
60 this.gtu = gtu;
61 gtu.addListener(this, LaneBasedGtu.LANE_CHANGE_EVENT);
62 }
63
64 @Override
65 public void notify(final Event event)
66 {
67 LateralDirectionality dir = LateralDirectionality.valueOf((String) ((Object[]) event.getContent())[1]);
68 RelativeLane shift = new RelativeLane(dir, 1);
69 Map<RelativeLane, Set<RoadSideDistraction>> newMap = new LinkedHashMap<>();
70 this.lanes.entrySet().stream().forEach((e) -> newMap.put(e.getKey().add(shift), e.getValue()));
71 this.lanes = newMap;
72 }
73
74
75
76
77
78
79
80 public double getDistraction(final BiFunction<RelativeLane, RoadSideDistraction, Boolean> filter) throws ParameterException
81 {
82 perceiveDistractions();
83 double taskDemand = 0.0;
84 for (RelativeLane lane : this.lanes.keySet())
85 {
86 for (RoadSideDistraction distraction : this.lanes.get(lane))
87 {
88 if (filter.apply(lane, distraction))
89 {
90 taskDemand += this.taskDemands.get(distraction);
91 }
92 }
93 }
94 return taskDemand;
95 }
96
97
98
99
100
101
102 private void perceiveDistractions() throws ParameterException
103 {
104 if (this.updateTime != null && this.gtu.getSimulator().getSimulatorTime().le(this.updateTime))
105 {
106 return;
107 }
108 this.updateTime = this.gtu.getSimulator().getSimulatorTime();
109
110
111 LaneStructure laneStructure = this.gtu.getTacticalPlanner().getPerception().getLaneStructure();
112 double odo = this.gtu.getOdometer().si;
113 for (RelativeLane lane : laneStructure.getRootCrossSection())
114 {
115 for (Entry<RoadSideDistraction> distraction : laneStructure.getDownstreamObjects(lane, RoadSideDistraction.class,
116 RelativePosition.FRONT, false))
117 {
118 this.odos.put(distraction.object(), odo + distraction.distance().si);
119 this.lanes.computeIfAbsent(lane, (l) -> new LinkedHashSet<>()).add(distraction.object());
120 }
121 }
122
123
124 Iterator<RoadSideDistraction> distractionIterator = this.odos.keySet().iterator();
125 while (distractionIterator.hasNext())
126 {
127 RoadSideDistraction distraction = distractionIterator.next();
128 OptionalDouble td = distraction.getDistraction(Length.ofSI(odo - this.odos.get(distraction)));
129 if (td.isEmpty())
130 {
131 distractionIterator.remove();
132 this.taskDemands.remove(distraction);
133 this.lanes.values().stream().forEach((s) -> s.remove(distraction));
134 }
135 else
136 {
137 this.taskDemands.put(distraction, td.getAsDouble());
138 }
139 }
140
141
142 Iterator<Set<RoadSideDistraction>> laneIterator = this.lanes.values().iterator();
143 while (laneIterator.hasNext())
144 {
145 if (laneIterator.next().isEmpty())
146 {
147 laneIterator.remove();
148 }
149 }
150 }
151
152 }