1 package org.opentrafficsim.demo.carFollowing;
2
3 import static org.opentrafficsim.road.gtu.lane.RoadGTUTypes.CAR;
4 import java.awt.geom.Rectangle2D;
5 import java.io.IOException;
6 import java.net.URL;
7 import java.rmi.RemoteException;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.LinkedHashSet;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14
15 import javax.naming.NamingException;
16 import javax.swing.JComponent;
17 import javax.swing.JPanel;
18 import javax.swing.JScrollPane;
19 import javax.swing.SwingUtilities;
20
21 import nl.tudelft.simulation.dsol.SimRuntimeException;
22 import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
23 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
24 import nl.tudelft.simulation.jstats.distributions.DistTriangular;
25 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
26 import nl.tudelft.simulation.jstats.streams.StreamInterface;
27
28 import org.djunits.unit.LengthUnit;
29 import org.djunits.unit.SpeedUnit;
30 import org.djunits.unit.TimeUnit;
31 import org.djunits.unit.UNITS;
32 import org.djunits.value.vdouble.scalar.Acceleration;
33 import org.djunits.value.vdouble.scalar.Duration;
34 import org.djunits.value.vdouble.scalar.Length;
35 import org.djunits.value.vdouble.scalar.Speed;
36 import org.djunits.value.vdouble.scalar.Time;
37 import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
38 import org.opentrafficsim.base.modelproperties.Property;
39 import org.opentrafficsim.base.modelproperties.PropertyException;
40 import org.opentrafficsim.base.modelproperties.SelectionProperty;
41 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
42 import org.opentrafficsim.core.dsol.OTSModelInterface;
43 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
44 import org.opentrafficsim.core.geometry.OTSGeometryException;
45 import org.opentrafficsim.core.geometry.OTSPoint3D;
46 import org.opentrafficsim.core.gtu.GTUDirectionality;
47 import org.opentrafficsim.core.gtu.GTUException;
48 import org.opentrafficsim.core.gtu.GTUType;
49 import org.opentrafficsim.core.gtu.animation.GTUColorer;
50 import org.opentrafficsim.core.network.LongitudinalDirectionality;
51 import org.opentrafficsim.core.network.NetworkException;
52 import org.opentrafficsim.core.network.OTSNetwork;
53 import org.opentrafficsim.core.network.OTSNode;
54 import org.opentrafficsim.core.network.route.Route;
55 import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
56 import org.opentrafficsim.demo.PropertiesParser;
57 import org.opentrafficsim.road.animation.AnimationToggles;
58 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
59 import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
60 import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
61 import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.LaneChangeModel;
62 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
63 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
64 import org.opentrafficsim.road.modelproperties.IDMPropertySet;
65 import org.opentrafficsim.road.network.factory.LaneFactory;
66 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
67 import org.opentrafficsim.road.network.lane.Lane;
68 import org.opentrafficsim.road.network.lane.LaneType;
69 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
70 import org.opentrafficsim.road.network.lane.object.trafficlight.SimpleTrafficLight;
71 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
72 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
73 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
74 import org.opentrafficsim.simulationengine.OTSSimulationException;
75
76
77
78
79
80
81
82
83
84
85
86 public class CrossingTrafficLights extends AbstractWrappableAnimation implements UNITS
87 {
88
89 private static final long serialVersionUID = 1L;
90
91
92 private CrossingTrafficLightstModel model;
93
94
95 protected static final Duration TGREEN = new Duration(39.0, TimeUnit.SI);
96
97
98 protected static final Duration TYELLOW = new Duration(6.0, TimeUnit.SI);
99
100
101 protected static final Duration TRED = new Duration(45.0, TimeUnit.SI);
102
103
104
105
106
107 public CrossingTrafficLights() throws PropertyException
108 {
109 this.properties.add(new SelectionProperty("LaneChanging", "Lane changing",
110 "<html>The lane change strategies vary in politeness.<br>"
111 + "Two types are implemented:<ul><li>Egoistic (looks only at personal gain).</li>"
112 + "<li>Altruistic (assigns effect on new and current follower the same weight as "
113 + "the personal gain).</html>",
114 new String[] { "Egoistic", "Altruistic" }, 0, false, 500));
115 this.properties.add(new SelectionProperty("TacticalPlanner", "Tactical planner",
116 "<html>The tactical planner determines if a lane change is desired and possible.</html>",
117 new String[] { "IDM", "MOBIL/IDM", "DIRECTED/IDM", "LMRS", "Toledo" }, 0, false, 600));
118 }
119
120
121 @Override
122 public final void stopTimersThreads()
123 {
124 super.stopTimersThreads();
125 this.model = null;
126 }
127
128
129
130
131
132
133 public static void main(final String[] args) throws SimRuntimeException
134 {
135 SwingUtilities.invokeLater(new Runnable()
136 {
137 @SuppressWarnings("synthetic-access")
138 @Override
139 public void run()
140 {
141 try
142 {
143 CrossingTrafficLights crossingTrafficLights = new CrossingTrafficLights();
144 List<Property<?>> localProperties = crossingTrafficLights.getProperties();
145 try
146 {
147 localProperties.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
148 "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
149 new Double[] { 0.8, 0.2 }, false, 10));
150 }
151 catch (PropertyException exception)
152 {
153 exception.printStackTrace();
154 }
155 localProperties.add(new SelectionProperty("CarFollowingModel", "Car following model",
156 "<html>The car following model determines "
157 + "the acceleration that a vehicle will make taking into account "
158 + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
159 + "curvature of the road) capabilities of the vehicle and personality "
160 + "of the driver.</html>", new String[] { "IDM", "IDM+" }, 1, false, 1));
161 localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMCar", "Car", new Acceleration(1.0,
162 METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2), new Length(2.0, METER),
163 new Duration(1.0, SECOND), 2));
164 localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMTruck", "Truck", new Acceleration(0.5,
165 METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2), new Length(2.0, METER),
166 new Duration(1.0, SECOND), 3));
167
168 crossingTrafficLights.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND),
169 new Duration(3600.0, SECOND), localProperties, null, true);
170
171 crossingTrafficLights.panel.getTabbedPane().addTab("info", crossingTrafficLights.makeInfoPane());
172 }
173 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
174 {
175 exception.printStackTrace();
176 }
177 }
178 });
179 }
180
181
182 @Override
183 protected final void addAnimationToggles()
184 {
185 AnimationToggles.setIconAnimationTogglesStandard(this);
186 }
187
188
189 @Override
190 protected final Rectangle2D makeAnimationRectangle()
191 {
192 return new Rectangle2D.Double(-50, -50, 100, 100);
193 }
194
195
196 @Override
197 protected final OTSModelInterface makeModel(final GTUColorer colorer)
198 {
199 this.model = new CrossingTrafficLightstModel(this.savedUserModifiedProperties, colorer);
200 return this.model;
201 }
202
203
204
205
206 protected final JComponent makeInfoPane()
207 {
208
209 String helpSource = "/" + CrossingTrafficLightstModel.class.getPackage().getName().replace('.', '/') + "/IDMPlus.html";
210 URL page = CrossingTrafficLightstModel.class.getResource(helpSource);
211 if (page != null)
212 {
213 try
214 {
215 HTMLPanel htmlPanel = new HTMLPanel(page);
216 return new JScrollPane(htmlPanel);
217 }
218 catch (IOException exception)
219 {
220 exception.printStackTrace();
221 }
222 }
223 return new JPanel();
224 }
225
226
227 @Override
228 public final String shortName()
229 {
230 return "Crossing with Traffic Lights";
231 }
232
233
234 @Override
235 public final String description()
236 {
237 return "<html><h1>Simulation of a crossing with traffic lights</h1>"
238 + "Simulation of four double lane roads with a crossing in the middle.</html>";
239 }
240
241 }
242
243
244
245
246
247
248
249
250
251
252
253 class CrossingTrafficLightstModel implements OTSModelInterface, UNITS
254 {
255
256 private static final long serialVersionUID = 20140815L;
257
258
259 private OTSDEVSSimulatorInterface simulator;
260
261
262 private final OTSNetwork network = new OTSNetwork("network");
263
264
265 private StreamInterface stream = new MersenneTwister(555);
266
267
268 private ContinuousDistDoubleScalar.Rel<Duration, TimeUnit> headwayDistribution =
269 new ContinuousDistDoubleScalar.Rel<>(new DistTriangular(this.stream, 7, 9, 15), TimeUnit.SECOND);
270
271
272 private ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> speedDistribution =
273 new ContinuousDistDoubleScalar.Rel<>(new DistTriangular(this.stream, 50, 60, 70), SpeedUnit.KM_PER_HOUR);
274
275
276 private int carsCreated = 0;
277
278
279 private GTUType gtuType = CAR;
280
281
282 private GTUFollowingModelOld carFollowingModel;
283
284
285 private LaneChangeModel laneChangeModel;
286
287
288 private List<Property<?>> properties = null;
289
290
291 private final GTUColorer gtuColorer;
292
293
294 private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerFactory;
295
296
297 private Speed speedLimit = new Speed(80, KM_PER_HOUR);
298
299
300
301
302
303 CrossingTrafficLightstModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
304 {
305 this.properties = properties;
306 this.gtuColorer = gtuColorer;
307 }
308
309
310 @Override
311 public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
312 throws SimRuntimeException, RemoteException
313 {
314 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
315 try
316 {
317 OTSNode[][] nodes = new OTSNode[4][4];
318 nodes[0][0] = new OTSNode(this.network, "sn1", new OTSPoint3D(10, -500));
319 nodes[0][1] = new OTSNode(this.network, "sn2", new OTSPoint3D(10, -20));
320 nodes[0][2] = new OTSNode(this.network, "sn3", new OTSPoint3D(10, +20));
321 nodes[0][3] = new OTSNode(this.network, "sn4", new OTSPoint3D(10, +5000));
322
323 nodes[1][0] = new OTSNode(this.network, "we1", new OTSPoint3D(-500, -10));
324 nodes[1][1] = new OTSNode(this.network, "we2", new OTSPoint3D(-20, -10));
325 nodes[1][2] = new OTSNode(this.network, "we3", new OTSPoint3D(+20, -10));
326 nodes[1][3] = new OTSNode(this.network, "we4", new OTSPoint3D(+5000, -10));
327
328 nodes[2][0] = new OTSNode(this.network, "ns1", new OTSPoint3D(-10, +500));
329 nodes[2][1] = new OTSNode(this.network, "ns2", new OTSPoint3D(-10, +20));
330 nodes[2][2] = new OTSNode(this.network, "ns3", new OTSPoint3D(-10, -20));
331 nodes[2][3] = new OTSNode(this.network, "ns4", new OTSPoint3D(-10, -5000));
332
333 nodes[3][0] = new OTSNode(this.network, "ew1", new OTSPoint3D(+500, 10));
334 nodes[3][1] = new OTSNode(this.network, "ew2", new OTSPoint3D(+20, 10));
335 nodes[3][2] = new OTSNode(this.network, "ew3", new OTSPoint3D(-20, 10));
336 nodes[3][3] = new OTSNode(this.network, "ew4", new OTSPoint3D(-5000, 10));
337
338 Set<GTUType> compatibility = new HashSet<>();
339 compatibility.add(this.gtuType);
340 LaneType laneType = new LaneType("CarLane", compatibility);
341
342 Map<Lane, SimpleTrafficLight> trafficLights = new HashMap<>();
343
344 for (int i = 0; i < 4; i++)
345 {
346 for (int j = 0; j < 3; j++)
347 {
348 Lane[] lanes = LaneFactory.makeMultiLane(this.network,
349 "Lane_" + nodes[i][j].getId() + "-" + nodes[i][j + 1].getId(), nodes[i][j], nodes[i][j + 1], null,
350 2, laneType, this.speedLimit, this.simulator, LongitudinalDirectionality.DIR_PLUS);
351 if (j == 0)
352 {
353 for (Lane lane : lanes)
354 {
355 this.simulator.scheduleEventRel(this.headwayDistribution.draw(), this, this, "generateCar",
356 new Object[] { lane });
357 SimpleTrafficLight tl = new SimpleTrafficLight(lane.getId() + "_TL", lane,
358 new Length(lane.getLength().minus(new Length(10.0, LengthUnit.METER))), this.simulator);
359 lane.addLaneBasedObject(tl);
360 trafficLights.put(lane, tl);
361 if (i == 0 || i == 2)
362 {
363 this.simulator.scheduleEventRel(Duration.ZERO, this, this, "changeTL",
364 new Object[] { tl });
365 }
366 else
367 {
368 this.simulator.scheduleEventRel(CrossingTrafficLights.TRED, this, this, "changeTL",
369 new Object[] { tl });
370 }
371 }
372 }
373 if (j == 2)
374 {
375 for (Lane lane : lanes)
376 {
377 new SinkSensor(lane, new Length(500.0, METER), this.simulator);
378 }
379 }
380 }
381 }
382
383 this.carFollowingModel = PropertiesParser.parseGTUFollowingModelOld(this.properties, "Car");
384 this.laneChangeModel = PropertiesParser.parseLaneChangeModel(this.properties);
385 this.strategicalPlannerFactory =
386 PropertiesParser.parseStrategicalPlannerFactory(this.properties, this.carFollowingModel, this.laneChangeModel);
387 }
388 catch (SimRuntimeException | NamingException | NetworkException | OTSGeometryException | PropertyException
389 | GTUException exception)
390 {
391 exception.printStackTrace();
392 }
393 }
394
395
396
397
398
399
400 protected final void changeTL(final TrafficLight tl) throws SimRuntimeException
401 {
402 if (tl.getTrafficLightColor().isRed())
403 {
404 tl.setTrafficLightColor(TrafficLightColor.GREEN);
405 this.simulator.scheduleEventRel(CrossingTrafficLights.TGREEN, this, this, "changeTL", new Object[] { tl });
406 }
407 else if (tl.getTrafficLightColor().isGreen())
408 {
409 tl.setTrafficLightColor(TrafficLightColor.YELLOW);
410 this.simulator.scheduleEventRel(CrossingTrafficLights.TYELLOW, this, this, "changeTL", new Object[] { tl });
411 }
412 else if (tl.getTrafficLightColor().isYellow())
413 {
414 tl.setTrafficLightColor(TrafficLightColor.RED);
415 this.simulator.scheduleEventRel(CrossingTrafficLights.TRED, this, this, "changeTL", new Object[] { tl });
416 }
417 }
418
419
420
421
422
423 protected final void generateCar(final Lane lane)
424 {
425 Length initialPosition = new Length(10, METER);
426 Speed initialSpeed = new Speed(0, KM_PER_HOUR);
427 Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
428 try
429 {
430 initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
431 Length vehicleLength = new Length(4, METER);
432 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
433 new Length(1.8, METER), this.speedDistribution.draw(), this.simulator, this.network);
434 Route route = null;
435 LaneBasedStrategicalPlanner strategicalPlanner = this.strategicalPlannerFactory.create(gtu, route);
436 gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
437 this.gtuColorer);
438 this.simulator.scheduleEventRel(this.headwayDistribution.draw(), this, this, "generateCar", new Object[] { lane });
439 }
440 catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
441 {
442 exception.printStackTrace();
443 }
444 }
445
446
447 @Override
448 public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
449 {
450 return this.simulator;
451 }
452
453
454 @Override
455 public OTSNetwork getNetwork()
456 {
457 return this.network;
458 }
459
460 }