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