1 package org.opentrafficsim.road.network.lane.object.trafficlight;
2
3 import java.util.LinkedHashSet;
4 import java.util.Set;
5
6 import org.djunits.unit.LengthUnit;
7 import org.djunits.value.vdouble.scalar.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djutils.event.EventType;
10 import org.djutils.metadata.MetaData;
11 import org.djutils.metadata.ObjectDescriptor;
12 import org.opentrafficsim.base.OtsRuntimeException;
13 import org.opentrafficsim.base.logger.Logger;
14 import org.opentrafficsim.core.gtu.GtuType;
15 import org.opentrafficsim.core.network.Link;
16 import org.opentrafficsim.core.network.NetworkException;
17 import org.opentrafficsim.core.network.Node;
18 import org.opentrafficsim.core.network.route.Route;
19 import org.opentrafficsim.core.perception.Historical;
20 import org.opentrafficsim.core.perception.HistoricalValue;
21 import org.opentrafficsim.road.network.lane.Lane;
22 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
23 import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
24
25
26
27
28
29
30
31
32
33
34
35 public class TrafficLight extends AbstractLaneBasedObject
36 {
37
38 private final Historical<TrafficLightColor> trafficLightColor;
39
40
41 private Set<Node> turnOnRed = null;
42
43
44 public static final Length DEFAULT_TRAFFICLIGHT_ELEVATION = new Length(1, LengthUnit.METER);
45
46
47
48
49
50 public static final EventType TRAFFICLIGHT_CHANGE_EVENT = new EventType("TRAFFICLIGHT.CHANGE",
51 new MetaData("Traffic light changed", "Color of traffic light has changed",
52 new ObjectDescriptor("Traffic light id", "Id of the traffic light", String.class),
53 new ObjectDescriptor("Traffic light", "The traffic light itself", TrafficLight.class),
54 new ObjectDescriptor("Traffic light color", "New traffic light color", TrafficLightColor.class)));
55
56
57
58
59
60
61
62
63
64 public TrafficLight(final String id, final Lane lane, final Length longitudinalPosition, final Length height)
65 throws NetworkException
66 {
67 super(id, lane, longitudinalPosition, LaneBasedObject.makeLine(lane, longitudinalPosition), height);
68 this.trafficLightColor = new HistoricalValue<>(getSimulator().getReplication().getHistoryManager(getSimulator()), this,
69 TrafficLightColor.RED);
70 init();
71 }
72
73
74
75
76
77
78
79
80 public TrafficLight(final String id, final Lane lane, final Length longitudinalPosition) throws NetworkException
81 {
82 this(id, lane, longitudinalPosition, DEFAULT_TRAFFICLIGHT_ELEVATION);
83 }
84
85
86
87
88
89 public final TrafficLightColor getTrafficLightColor()
90 {
91 return this.trafficLightColor.get();
92 }
93
94
95
96
97
98
99 public final TrafficLightColor getTrafficLightColor(final Duration time)
100 {
101 return this.trafficLightColor.get(time);
102 }
103
104
105
106
107
108 public final void setTrafficLightColor(final TrafficLightColor trafficLightColor)
109 {
110 this.trafficLightColor.set(trafficLightColor);
111 fireTimedEvent(TRAFFICLIGHT_CHANGE_EVENT, new Object[] {getId(), this, trafficLightColor},
112 getSimulator().getSimulatorTime());
113 }
114
115
116
117
118
119 public void addTurnOnRed(final Node node)
120 {
121 if (this.turnOnRed == null)
122 {
123 this.turnOnRed = new LinkedHashSet<>();
124 }
125 this.turnOnRed.add(node);
126 }
127
128
129
130
131
132
133
134 public boolean canTurnOnRed(final Route route, final GtuType gtuType)
135 {
136 if (this.turnOnRed == null)
137 {
138 return false;
139 }
140 try
141 {
142
143 Link link = getLane().getLink();
144 Set<Link> next = link.getEndNode().getLinks().toSet();
145 next.remove(link);
146 while (next.size() == 1)
147 {
148 link = next.iterator().next();
149 next = link.getEndNode().getLinks().toSet();
150 next.remove(link);
151 }
152
153 Node nextEndNode;
154 if (route != null)
155 {
156 int nodeIndex = route.indexOf(link.getEndNode());
157 if (nodeIndex < 0 || nodeIndex == route.size() - 1)
158 {
159 return false;
160 }
161 nextEndNode = route.getNode(nodeIndex + 1);
162 }
163 else
164 {
165 next = link.getEndNode().nextLinks(gtuType, link);
166 if (next.size() == 1)
167 {
168 nextEndNode = next.iterator().next().getEndNode();
169 }
170 else
171 {
172 Logger.ots().warn("GTU without route cannot determine whether it can turn on red at node {}.",
173 link.getEndNode());
174 return false;
175 }
176 }
177 return this.turnOnRed.contains(nextEndNode);
178 }
179 catch (NetworkException ex)
180 {
181
182 throw new OtsRuntimeException(ex);
183 }
184 }
185
186 @Override
187 @SuppressWarnings("checkstyle:designforextension")
188 public String toString()
189 {
190 return "TrafficLight [trafficLightColor=" + getTrafficLightColor() + "]";
191 }
192
193 }