View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import java.awt.Container;
4   import java.awt.Frame;
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.ArrayList;
10  import java.util.Arrays;
11  import java.util.Iterator;
12  import java.util.LinkedHashSet;
13  import java.util.List;
14  import java.util.Random;
15  import java.util.Set;
16  
17  import javax.naming.NamingException;
18  import javax.swing.JComponent;
19  import javax.swing.JPanel;
20  import javax.swing.JScrollPane;
21  import javax.swing.SwingUtilities;
22  
23  import nl.tudelft.simulation.dsol.SimRuntimeException;
24  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
25  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
26  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
27  
28  import org.djunits.unit.TimeUnit;
29  import org.djunits.unit.UNITS;
30  import org.djunits.value.vdouble.scalar.Acceleration;
31  import org.djunits.value.vdouble.scalar.DoubleScalar;
32  import org.djunits.value.vdouble.scalar.DoubleScalar.Abs;
33  import org.djunits.value.vdouble.scalar.DoubleScalar.Rel;
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.core.dsol.OTSDEVSSimulatorInterface;
38  import org.opentrafficsim.core.dsol.OTSModelInterface;
39  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
40  import org.opentrafficsim.core.geometry.OTSGeometryException;
41  import org.opentrafficsim.core.geometry.OTSLine3D;
42  import org.opentrafficsim.core.geometry.OTSPoint3D;
43  import org.opentrafficsim.core.gtu.GTUDirectionality;
44  import org.opentrafficsim.core.gtu.GTUException;
45  import org.opentrafficsim.core.gtu.GTUType;
46  import org.opentrafficsim.core.gtu.animation.GTUColorer;
47  import org.opentrafficsim.core.network.LongitudinalDirectionality;
48  import org.opentrafficsim.core.network.NetworkException;
49  import org.opentrafficsim.core.network.OTSNetwork;
50  import org.opentrafficsim.core.network.OTSNode;
51  import org.opentrafficsim.graphs.AccelerationContourPlot;
52  import org.opentrafficsim.graphs.ContourPlot;
53  import org.opentrafficsim.graphs.DensityContourPlot;
54  import org.opentrafficsim.graphs.FlowContourPlot;
55  import org.opentrafficsim.graphs.LaneBasedGTUSampler;
56  import org.opentrafficsim.graphs.SpeedContourPlot;
57  import org.opentrafficsim.graphs.TrajectoryPlot;
58  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
59  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
60  import org.opentrafficsim.road.gtu.lane.driver.LaneBasedBehavioralCharacteristics;
61  import org.opentrafficsim.road.gtu.lane.perception.LanePerceptionFull;
62  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
63  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
64  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
65  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
66  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.AbstractLaneChangeModel;
67  import org.opentrafficsim.road.gtu.lane.tactical.lanechangemobil.Egoistic;
68  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
69  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
70  import org.opentrafficsim.road.network.factory.LaneFactory;
71  import org.opentrafficsim.road.network.lane.CrossSectionLink;
72  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
73  import org.opentrafficsim.road.network.lane.Lane;
74  import org.opentrafficsim.road.network.lane.LaneType;
75  import org.opentrafficsim.road.network.lane.Sensor;
76  import org.opentrafficsim.road.network.lane.SinkSensor;
77  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
78  import org.opentrafficsim.simulationengine.OTSSimulationException;
79  import org.opentrafficsim.simulationengine.properties.AbstractProperty;
80  import org.opentrafficsim.simulationengine.properties.BooleanProperty;
81  import org.opentrafficsim.simulationengine.properties.CompoundProperty;
82  import org.opentrafficsim.simulationengine.properties.IDMPropertySet;
83  import org.opentrafficsim.simulationengine.properties.ProbabilityDistributionProperty;
84  import org.opentrafficsim.simulationengine.properties.PropertyException;
85  import org.opentrafficsim.simulationengine.properties.SelectionProperty;
86  
87  /**
88   * Single lane road consisting of three consecutive links.<br>
89   * Tests that GTUs correctly transfer themselves onto the next lane and that the graph samplers handle this situation.
90   * <p>
91   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
92   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
93   * <p>
94   * $LastChangedDate: 2016-04-05 21:30:47 +0200 (Tue, 05 Apr 2016) $, @version $Revision: 1889 $, by $Author: pknoppers $,
95   * initial version 30 jan. 2015 <br>
96   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
97   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
98   */
99  public class SequentialLanes extends AbstractWrappableAnimation implements UNITS
100 {
101     /** The model. */
102     private SequentialModel model;
103 
104     /** Create a SequentialLanes simulation. */
105     public SequentialLanes()
106     {
107         ArrayList<AbstractProperty<?>> outputProperties = new ArrayList<AbstractProperty<?>>();
108         outputProperties.add(new BooleanProperty("Density", "Density contour plot", true, false, 0));
109         outputProperties.add(new BooleanProperty("Flow", "Flow contour plot", true, false, 1));
110         outputProperties.add(new BooleanProperty("Speed", "Speed contour plot", true, false, 2));
111         outputProperties.add(new BooleanProperty("Acceleration", "Acceleration contour plot", true, false, 3));
112         outputProperties.add(new BooleanProperty("Trajectories", "Trajectory (time/distance) diagram", true, false, 4));
113         this.properties.add(new CompoundProperty("Output graphs", "Select the graphical output", outputProperties,
114             true, 1000));
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public final void stopTimersThreads()
120     {
121         super.stopTimersThreads();
122         this.model = null;
123     }
124 
125     /**
126      * Main program.
127      * @param args String[]; the command line arguments (not used)
128      * @throws SimRuntimeException when simulation cannot be created with given parameters
129      */
130     public static void main(final String[] args) throws SimRuntimeException
131     {
132         SwingUtilities.invokeLater(new Runnable()
133         {
134             @Override
135             public void run()
136             {
137                 try
138                 {
139                     SequentialLanes sequential = new SequentialLanes();
140                     ArrayList<AbstractProperty<?>> localProperties = sequential.getProperties();
141                     try
142                     {
143                         localProperties.add(new ProbabilityDistributionProperty("Traffic composition",
144                             "<html>Mix of passenger cars and trucks</html>", new String[]{"passenger car", "truck"},
145                             new Double[]{0.8, 0.2}, false, 10));
146                     }
147                     catch (PropertyException exception)
148                     {
149                         exception.printStackTrace();
150                     }
151                     localProperties.add(new SelectionProperty("Car following model",
152                         "<html>The car following model determines "
153                             + "the acceleration that a vehicle will make taking into account "
154                             + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
155                             + "curvature of the road) capabilities of the vehicle and personality "
156                             + "of the driver.</html>", new String[]{"IDM", "IDM+"}, 1, false, 1));
157                     localProperties.add(IDMPropertySet.makeIDMPropertySet("Car", new Acceleration(1.0,
158                         METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2), new Length.Rel(2.0, METER),
159                         new Time.Rel(1.0, SECOND), 2));
160                     localProperties.add(IDMPropertySet.makeIDMPropertySet("Truck", new Acceleration(0.5,
161                         METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2), new Length.Rel(2.0, METER),
162                         new Time.Rel(1.0, SECOND), 3));
163                     sequential.buildAnimator(new Time.Abs(0.0, SECOND), new Time.Rel(0.0, SECOND), new Time.Rel(3600.0,
164                         SECOND), localProperties, null, true);
165                     sequential.panel.getTabbedPane().addTab("info", sequential.makeInfoPane());
166                 }
167                 catch (SimRuntimeException | NamingException | OTSSimulationException exception)
168                 {
169                     exception.printStackTrace();
170                 }
171             }
172         });
173     }
174 
175     /** {@inheritDoc} */
176     @Override
177     protected final Rectangle2D.Double makeAnimationRectangle()
178     {
179         return new Rectangle2D.Double(0, -100, 2010, 200);
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     protected final OTSModelInterface makeModel(final GTUColorer colorer)
185     {
186         this.model = new SequentialModel(this.savedUserModifiedProperties, colorer);
187         return this.model;
188     }
189 
190     /**
191      * @return an info pane to be added to the tabbed pane.
192      */
193     protected final JComponent makeInfoPane()
194     {
195         // Make the info tab
196         String helpSource = "/" + StraightModel.class.getPackage().getName().replace('.', '/') + "/IDMPlus.html";
197         URL page = StraightModel.class.getResource(helpSource);
198         if (page != null)
199         {
200             try
201             {
202                 HTMLPanel htmlPanel = new HTMLPanel(page);
203                 return new JScrollPane(htmlPanel);
204             }
205             catch (IOException exception)
206             {
207                 exception.printStackTrace();
208             }
209         }
210         return new JPanel();
211     }
212 
213     /** {@inheritDoc} */
214     @Override
215     protected final JPanel makeCharts() throws OTSSimulationException
216     {
217         // Make the tab with the plots
218         AbstractProperty<?> output =
219             new CompoundProperty("", "", this.properties, false, 0).findByShortName("Output graphs");
220         if (null == output)
221         {
222             throw new Error("Cannot find output properties");
223         }
224         ArrayList<BooleanProperty> graphs = new ArrayList<BooleanProperty>();
225         if (output instanceof CompoundProperty)
226         {
227             CompoundProperty outputProperties = (CompoundProperty) output;
228             for (AbstractProperty<?> ap : outputProperties.getValue())
229             {
230                 if (ap instanceof BooleanProperty)
231                 {
232                     BooleanProperty bp = (BooleanProperty) ap;
233                     if (bp.getValue())
234                     {
235                         graphs.add(bp);
236                     }
237                 }
238             }
239         }
240         else
241         {
242             throw new Error("output properties should be compound");
243         }
244         int graphCount = graphs.size();
245         int columns = (int) Math.ceil(Math.sqrt(graphCount));
246         int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
247         TablePanel charts = new TablePanel(columns, rows);
248 
249         for (int i = 0; i < graphCount; i++)
250         {
251             String graphName = graphs.get(i).getShortName();
252             Container container = null;
253             LaneBasedGTUSampler graph;
254             if (graphName.contains("Trajectories"))
255             {
256                 TrajectoryPlot tp =
257                     new TrajectoryPlot("TrajectoryPlot", new Time.Rel(0.5, SECOND), this.model.getPath());
258                 tp.setTitle("Trajectory Graph");
259                 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
260                 graph = tp;
261                 container = tp.getContentPane();
262             }
263             else
264             {
265                 ContourPlot cp;
266                 if (graphName.contains("Density"))
267                 {
268                     cp = new DensityContourPlot("DensityPlot", this.model.getPath());
269                     cp.setTitle("Density Contour Graph");
270                 }
271                 else if (graphName.contains("Speed"))
272                 {
273                     cp = new SpeedContourPlot("SpeedPlot", this.model.getPath());
274                     cp.setTitle("Speed Contour Graph");
275                 }
276                 else if (graphName.contains("Flow"))
277                 {
278                     cp = new FlowContourPlot("FlowPlot", this.model.getPath());
279                     cp.setTitle("Flow Contour Graph");
280                 }
281                 else if (graphName.contains("Acceleration"))
282                 {
283                     cp = new AccelerationContourPlot("AccelerationPlot", this.model.getPath());
284                     cp.setTitle("Acceleration Contour Graph");
285                 }
286                 else
287                 {
288                     continue;
289                     // throw new Error("Unhandled type of contourplot: " + graphName);
290                 }
291                 graph = cp;
292                 container = cp.getContentPane();
293             }
294             // Add the container to the matrix
295             charts.setCell(container, i % columns, i / columns);
296             this.model.getPlots().add(graph);
297         }
298         return charts;
299     }
300 
301     /** {@inheritDoc} */
302     @Override
303     public final String shortName()
304     {
305         return "Sequential Lanes";
306     }
307 
308     /** {@inheritDoc} */
309     @Override
310     public final String description()
311     {
312         return "<html><h1>Simulation of a straight one-lane road consisting of three consecutive Links</H1>"
313             + "Simulation of a single lane road consisting of two 1 km stretches with a 1m stretch in between. "
314             + "This will test transition of a GTU from one lane section onto the next.<br>"
315             + "Vehicles are generated at a constant rate of 1500 veh/hour.<br>"
316             + "Selected trajectory and contour plots are generated during the simulation.</html>";
317     }
318 
319 }
320 
321 /**
322  * Build the sequential model.
323  * <p>
324  * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
325  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
326  * <p>
327  * $LastChangedDate: 2016-04-05 21:30:47 +0200 (Tue, 05 Apr 2016) $, @version $Revision: 1889 $, by $Author: pknoppers $,
328  * initial version 0 jan. 2015 <br>
329  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
330  */
331 class SequentialModel implements OTSModelInterface, UNITS
332 {
333     /** */
334     private static final long serialVersionUID = 20150130L;
335 
336     /** The simulator. */
337     private OTSDEVSSimulatorInterface simulator;
338 
339     /** The network. */
340     private OTSNetwork network = new OTSNetwork("network");
341 
342     /** The nodes of our network in the order that all GTUs will visit them. */
343     private ArrayList<OTSNode> nodes = new ArrayList<OTSNode>();
344 
345     /** The car following model, e.g. IDM Plus for cars. */
346     private GTUFollowingModelOld carFollowingModelCars;
347 
348     /** The car following model, e.g. IDM Plus for trucks. */
349     private GTUFollowingModelOld carFollowingModelTrucks;
350 
351     /** The probability that the next generated GTU is a passenger car. */
352     private double carProbability;
353 
354     /** The lane change model. */
355     private AbstractLaneChangeModel laneChangeModel = new Egoistic();
356 
357     /** The headway (inter-vehicle time). */
358     private Time.Rel headway;
359 
360     /** Number of cars created. */
361     private int carsCreated = 0;
362 
363     /** Type of all GTUs. */
364     private GTUType gtuType = GTUType.makeGTUType("Car");
365 
366     /** Minimum distance. */
367     private Length.Rel minimumDistance = new Length.Rel(0, METER);
368 
369     /** The Lane where newly created Cars initially placed on. */
370     private Lane initialLane;
371 
372     /** Maximum distance. */
373     private Length.Rel maximumDistance = new Length.Rel(2001, METER);
374 
375     /** The contour plots. */
376     private ArrayList<LaneBasedGTUSampler> plots = new ArrayList<LaneBasedGTUSampler>();
377 
378     /** The random number generator used to decide what kind of GTU to generate. */
379     private Random randomGenerator = new Random(12345);
380 
381     /** User settable properties. */
382     private ArrayList<AbstractProperty<?>> properties = null;
383 
384     /** The sequence of Lanes that all vehicles will follow. */
385     private List<Lane> path = new ArrayList<Lane>();
386 
387     /** The speedLimit on all Lanes. */
388     private Speed speedLimit;
389 
390     /** The GTUColorer for the generated vehicles. */
391     private final GTUColorer gtuColorer;
392 
393     /**
394      * @param properties the user settable properties
395      * @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer.
396      */
397     public SequentialModel(final ArrayList<AbstractProperty<?>> properties, final GTUColorer gtuColorer)
398     {
399         this.properties = properties;
400         this.gtuColorer = gtuColorer;
401     }
402 
403     /**
404      * @return a newly created path (which all GTUs in this simulation will follow).
405      */
406     public List<Lane> getPath()
407     {
408         return new ArrayList<Lane>(this.path);
409     }
410 
411     /** {@inheritDoc} */
412     @Override
413     public final void constructModel(
414         final SimulatorInterface<Abs<TimeUnit>, Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
415         throws SimRuntimeException, RemoteException
416     {
417         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
418         this.speedLimit = new Speed(100, KM_PER_HOUR);
419 
420         // TODO Bezier curves make 180 degree mistake when minus is true
421         boolean minus = false;
422 
423         this.nodes = new ArrayList<OTSNode>();
424         OTSNode n0 = new OTSNode("Node(0,0)", new OTSPoint3D(0, 0));
425         OTSNode n1 = new OTSNode("Node(1000,0)", new OTSPoint3D(1000, 0));
426         OTSNode n2 = new OTSNode("Node(1020,3)", new OTSPoint3D(1020, 3));
427         OTSNode n3 = new OTSNode("Node(2000,197)", new OTSPoint3D(2000, 197));
428         OTSNode n4 = new OTSNode("Node(2020,200)", new OTSPoint3D(2020, 200));
429         OTSNode n5 = new OTSNode("Node(2200,200)", new OTSPoint3D(2200, 200));
430         this.nodes.addAll(Arrays.asList(new OTSNode[]{n0, n1, n2, n3, n4, n5}));
431 
432         LaneType laneType = new LaneType("CarLane");
433         laneType.addCompatibility(this.gtuType);
434 
435         try
436         {
437             // Now we can build a series of Links with one Lane on them
438             ArrayList<CrossSectionLink> links = new ArrayList<CrossSectionLink>();
439             OTSLine3D l01 = new OTSLine3D(n0.getPoint(), n1.getPoint());
440             OTSLine3D l12 = LaneFactory.makeBezier(n0, n1, n2, n3);
441             OTSLine3D l23 =
442                 minus ? new OTSLine3D(n3.getPoint(), n2.getPoint()) : new OTSLine3D(n2.getPoint(), n3.getPoint());
443             OTSLine3D l34 = LaneFactory.makeBezier(n2, n3, n4, n5);
444             OTSLine3D l45 = new OTSLine3D(n4.getPoint(), n5.getPoint());
445             OTSLine3D[] lines = new OTSLine3D[]{l01, l12, l23, l34, l45};
446 
447             for (int i = 1; i < this.nodes.size(); i++)
448             {
449                 OTSNode fromNode = this.nodes.get(i - 1);
450                 OTSNode toNode = this.nodes.get(i);
451                 OTSLine3D line = lines[i - 1];
452                 String linkName = fromNode.getId() + "-" + toNode.getId();
453                 LongitudinalDirectionality direction =
454                     line.equals(l23) && minus ? LongitudinalDirectionality.DIR_MINUS
455                         : LongitudinalDirectionality.DIR_PLUS;
456                 Lane[] lanes =
457                     LaneFactory.makeMultiLane(linkName, fromNode, toNode, line.getPoints(), 1, laneType,
458                         this.speedLimit, this.simulator, direction);
459                 if (i == this.nodes.size() - 1)
460                 {
461                     Sensor sensor = new SinkSensor(lanes[0], new Length.Rel(100.0, METER), this.simulator);
462                     lanes[0].addSensor(sensor, GTUType.ALL);
463                 }
464                 this.path.add(lanes[0]);
465                 links.add(lanes[0].getParentLink());
466                 if (1 == i)
467                 {
468                     this.initialLane = lanes[0];
469                 }
470             }
471         }
472         catch (NamingException | NetworkException | OTSGeometryException exception)
473         {
474             exception.printStackTrace();
475         }
476 
477         // 1500 [veh / hour] == 2.4s headway
478         this.headway = new Time.Rel(3600.0 / 1500.0, SECOND);
479         // Schedule creation of the first car (it will re-schedule itself one headway later, etc.).
480         this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, SECOND), this, this, "generateCar", null);
481         // Schedule regular updates of the graphs
482         for (int t = 1; t <= 1800; t++)
483         {
484             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, SECOND), this, this,
485                 "drawGraphs", null);
486         }
487         try
488         {
489             String carFollowingModelName = null;
490             CompoundProperty propertyContainer = new CompoundProperty("", "", this.properties, false, 0);
491             AbstractProperty<?> cfmp = propertyContainer.findByShortName("Car following model");
492             if (null == cfmp)
493             {
494                 throw new Error("Cannot find \"Car following model\" property");
495             }
496             if (cfmp instanceof SelectionProperty)
497             {
498                 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
499             }
500             else
501             {
502                 throw new Error("\"Car following model\" property has wrong type");
503             }
504             Iterator<AbstractProperty<ArrayList<AbstractProperty<?>>>> iterator =
505                 new CompoundProperty("", "", this.properties, false, 0).iterator();
506             while (iterator.hasNext())
507             {
508                 AbstractProperty<?> ap = iterator.next();
509                 if (ap instanceof SelectionProperty)
510                 {
511                     SelectionProperty sp = (SelectionProperty) ap;
512                     if ("Car following model".equals(sp.getShortName()))
513                     {
514                         carFollowingModelName = sp.getValue();
515                     }
516                 }
517                 else if (ap instanceof ProbabilityDistributionProperty)
518                 {
519                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
520                     if (ap.getShortName().equals("Traffic composition"))
521                     {
522                         this.carProbability = pdp.getValue()[0];
523                     }
524                 }
525                 else if (ap instanceof CompoundProperty)
526                 {
527                     CompoundProperty cp = (CompoundProperty) ap;
528                     if (ap.getShortName().equals("Output graphs"))
529                     {
530                         continue; // Output settings are handled elsewhere
531                     }
532                     if (ap.getShortName().contains("IDM"))
533                     {
534                         // System.out.println("Car following model name appears to be " + ap.getShortName());
535                         Acceleration a = IDMPropertySet.getA(cp);
536                         Acceleration b = IDMPropertySet.getB(cp);
537                         Length.Rel s0 = IDMPropertySet.getS0(cp);
538                         Time.Rel tSafe = IDMPropertySet.getTSafe(cp);
539                         GTUFollowingModelOld gtuFollowingModel = null;
540                         if (carFollowingModelName.equals("IDM"))
541                         {
542                             gtuFollowingModel = new IDMOld(a, b, s0, tSafe, 1.0);
543                         }
544                         else if (carFollowingModelName.equals("IDM+"))
545                         {
546                             gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
547                         }
548                         else
549                         {
550                             throw new Error("Unknown gtu following model: " + carFollowingModelName);
551                         }
552                         if (ap.getShortName().contains(" Car "))
553                         {
554                             this.carFollowingModelCars = gtuFollowingModel;
555                         }
556                         else if (ap.getShortName().contains(" Truck "))
557                         {
558                             this.carFollowingModelTrucks = gtuFollowingModel;
559                         }
560                         else
561                         {
562                             throw new Error("Cannot determine gtu type for " + ap.getShortName());
563                         }
564                     }
565                 }
566             }
567         }
568         catch (Exception e)
569         {
570             System.out.println("Caught exception " + e);
571         }
572     }
573 
574     /** {@inheritDoc} */
575     @Override
576     public SimulatorInterface<Abs<TimeUnit>, Rel<TimeUnit>, OTSSimTimeDouble> getSimulator() throws RemoteException
577     {
578         return this.simulator;
579     }
580 
581     /**
582      * @return contourPlots
583      */
584     public final ArrayList<LaneBasedGTUSampler> getPlots()
585     {
586         return this.plots;
587     }
588 
589     /**
590      * @return minimumDistance
591      */
592     public final Length.Rel getMinimumDistance()
593     {
594         return this.minimumDistance;
595     }
596 
597     /**
598      * @return maximumDistance
599      */
600     public final Length.Rel getMaximumDistance()
601     {
602         return this.maximumDistance;
603     }
604 
605     /**
606      * Notify the contour plots that the underlying data has changed.
607      */
608     protected final void drawGraphs()
609     {
610         for (LaneBasedGTUSampler plot : this.plots)
611         {
612             plot.reGraph();
613         }
614     }
615 
616     /**
617      * Generate cars at a fixed rate (implemented by re-scheduling this method).
618      */
619     protected final void generateCar()
620     {
621         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
622         Length.Rel initialPosition = new Length.Rel(0, METER);
623         Speed initialSpeed = new Speed(100, KM_PER_HOUR);
624         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
625         try
626         {
627             initialPositions
628                 .add(new DirectedLanePosition(this.initialLane, initialPosition, GTUDirectionality.DIR_PLUS));
629             Length.Rel vehicleLength = new Length.Rel(generateTruck ? 15 : 4, METER);
630             GTUFollowingModelOld gtuFollowingModel =
631                 generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
632             if (null == gtuFollowingModel)
633             {
634                 throw new Error("gtuFollowingModel is null");
635             }
636             LaneBasedBehavioralCharacteristics drivingCharacteristics =
637                 new LaneBasedBehavioralCharacteristics(gtuFollowingModel, this.laneChangeModel);
638             LaneBasedStrategicalPlanner strategicalPlanner =
639                 new LaneBasedStrategicalRoutePlanner(drivingCharacteristics, new LaneBasedGTUFollowingTacticalPlanner());
640             new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, initialPositions, initialSpeed,
641                 vehicleLength, new Length.Rel(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator,
642                 strategicalPlanner, new LanePerceptionFull(), DefaultCarAnimation.class, this.gtuColorer, this.network);
643             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
644         }
645         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
646         {
647             exception.printStackTrace();
648         }
649     }
650 
651 }