View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import java.awt.Frame;
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.ArrayList;
9   import java.util.Collection;
10  import java.util.HashMap;
11  import java.util.Map;
12  import java.util.Random;
13  
14  import javax.naming.NamingException;
15  import javax.swing.JScrollPane;
16  import javax.swing.SwingUtilities;
17  
18  import nl.tudelft.simulation.dsol.SimRuntimeException;
19  import nl.tudelft.simulation.dsol.gui.swing.DSOLPanel;
20  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
21  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
22  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
23  
24  import org.opentrafficsim.car.Car;
25  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
26  import org.opentrafficsim.core.dsol.OTSModelInterface;
27  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
28  import org.opentrafficsim.core.gtu.GTUType;
29  import org.opentrafficsim.core.gtu.following.GTUFollowingModel;
30  import org.opentrafficsim.core.gtu.following.GTUFollowingModel.GTUFollowingModelResult;
31  import org.opentrafficsim.core.gtu.following.IDM;
32  import org.opentrafficsim.core.gtu.following.IDMPlus;
33  import org.opentrafficsim.core.network.NetworkException;
34  import org.opentrafficsim.core.network.factory.LaneFactory;
35  import org.opentrafficsim.core.network.factory.Node;
36  import org.opentrafficsim.core.network.lane.Lane;
37  import org.opentrafficsim.core.network.lane.LaneType;
38  import org.opentrafficsim.core.unit.AccelerationUnit;
39  import org.opentrafficsim.core.unit.LengthUnit;
40  import org.opentrafficsim.core.unit.SpeedUnit;
41  import org.opentrafficsim.core.unit.TimeUnit;
42  import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
43  import org.opentrafficsim.graphs.TrajectoryPlot;
44  import org.opentrafficsim.simulationengine.AbstractProperty;
45  import org.opentrafficsim.simulationengine.ControlPanel;
46  import org.opentrafficsim.simulationengine.ProbabilityDistributionProperty;
47  import org.opentrafficsim.simulationengine.PropertyException;
48  import org.opentrafficsim.simulationengine.SelectionProperty;
49  import org.opentrafficsim.simulationengine.SimpleSimulator;
50  import org.opentrafficsim.simulationengine.SimulatorFrame;
51  import org.opentrafficsim.simulationengine.WrappableSimulation;
52  
53  import com.vividsolutions.jts.geom.Coordinate;
54  
55  /**
56   * Demonstrate the Trajectories plot.
57   * <p>
58   * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
59   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
60   * <p>
61   * @version 17 dec. 2014 <br>
62   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
63   */
64  public class Trajectories implements WrappableSimulation
65  {
66      /** The properties exhibited by this simulation. */
67      private ArrayList<AbstractProperty<?>> properties = new ArrayList<AbstractProperty<?>>();
68  
69      /** Create a Trajectories simulation. */
70      public Trajectories()
71      {
72          try
73          {
74              this.properties.add(new SelectionProperty("Car following model", "<html>The car following model determines "
75                  + "the acceleration that a vehicle will make taking into account nearby vehicles, infrastructural "
76                  + "restrictions (e.g. speed limit, curvature of the road) capabilities of the vehicle and "
77                  + "personality of the driver.</html>", new String[] {"IDM", "IDM+"}, 1, false, 10));
78              this.properties.add(new ProbabilityDistributionProperty("Traffic composition",
79                  "<html>Mix of passenger cars and trucks</html>", new String[] {"passenger car", "truck"}, new Double[] {0.8,
80                      0.2}, false, 9));
81          }
82          catch (PropertyException exception)
83          {
84              exception.printStackTrace();
85          }
86      }
87  
88      /**
89       * Main program.
90       * @param args String[]; the command line arguments (not used)
91       * @throws SimRuntimeException
92       * @throws RemoteException
93       */
94      public static void main(final String[] args) throws RemoteException, SimRuntimeException
95      {
96          // Create the simulation and wrap its panel in a JFrame. It does not get much easier/shorter than this...
97          SwingUtilities.invokeLater(new Runnable()
98          {
99              @Override
100             public void run()
101             {
102                 try
103                 {
104                     Trajectories trajectories = new Trajectories();
105                     new SimulatorFrame("Trajectory Plots animation", trajectories.buildSimulator(
106                         trajectories.getProperties()).getPanel());
107                 }
108                 catch (RemoteException | SimRuntimeException exception)
109                 {
110                     exception.printStackTrace();
111                 }
112             }
113         });
114     }
115 
116     /**
117      * Create a new simulation.
118      * @return SimpleSimulator; the new simulation
119      * @throws SimRuntimeException
120      * @throws RemoteException
121      */
122     public SimpleSimulator buildSimulator(ArrayList<AbstractProperty<?>> userModifiedProperties) throws RemoteException,
123         SimRuntimeException
124     {
125         TrajectoriesModel model = new TrajectoriesModel(userModifiedProperties);
126         SimpleSimulator result =
127             new SimpleSimulator(new OTSSimTimeDouble(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND)),
128                 new DoubleScalar.Rel<TimeUnit>(0.0, TimeUnit.SECOND),
129                 new DoubleScalar.Rel<TimeUnit>(1800.0, TimeUnit.SECOND), model, new Rectangle2D.Double(0, -100, 5000, 200));
130         new ControlPanel(result);
131         makePlot(model, result.getPanel());
132         addInfoTab(result.getPanel());
133         return result;
134     }
135 
136     /**
137      * make the stand-alone plot for the model and put it in the statistics panel.
138      * @param model the model.
139      * @param panel DSOLPanel
140      */
141     private static void makePlot(final TrajectoriesModel model,
142         final DSOLPanel<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> panel)
143     {
144         TablePanel charts = new TablePanel(1, 1);
145         panel.getTabbedPane().addTab("statistics", charts);
146         DoubleScalar.Rel<TimeUnit> sampleInterval = new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND);
147         TrajectoryPlot tp =
148             new TrajectoryPlot("Trajectory Plot", sampleInterval, model.getMinimumDistance(), model.getMaximumDistance());
149         tp.setTitle("Density Contour Graph");
150         tp.setExtendedState(Frame.MAXIMIZED_BOTH);
151         model.setTrajectoryPlot(tp);
152         charts.setCell(tp.getContentPane(), 0, 0);
153     }
154 
155     /**
156      * @param panel DSOLPanel
157      */
158     private static void addInfoTab(
159         final DSOLPanel<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> panel)
160     {
161         // Let's find some content for our info screen and add it to our tabbedPane
162         String helpSource = "/" + TrajectoriesModel.class.getPackage().getName().replace('.', '/') + "/package.html";
163         URL page = TrajectoriesModel.class.getResource(helpSource);
164         if (page != null)
165         {
166             HTMLPanel htmlPanel;
167             try
168             {
169                 htmlPanel = new HTMLPanel(page);
170                 panel.getTabbedPane().addTab("info", new JScrollPane(htmlPanel));
171             }
172             catch (IOException exception)
173             {
174                 exception.printStackTrace();
175             }
176         }
177     }
178 
179     /** {@inheritDoc} */
180     @Override
181     public String shortName()
182     {
183         return "Trajectory plot";
184     }
185 
186     /** {@inheritDoc} */
187     @Override
188     public String description()
189     {
190         return "<html><H1>Trajectories</H1>"
191             + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
192             + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
193             + "420s. This blockade simulates a bridge opening.<br/>"
194             + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br />"
195             + "Output is a Trajectory plots.</html>";
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public ArrayList<AbstractProperty<?>> getProperties()
201     {
202         // Create and return a deep copy of the internal list
203         return new ArrayList<AbstractProperty<?>>(this.properties);
204     }
205 
206 }
207 
208 /**
209  * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
210  * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+ <a
211  * href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
212  * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
213  * Output is a trajectory plot with simulation time along the horizontal axis and distance along the road along the vertical
214  * axis.
215  * <p>
216  * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
217  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
218  * <p>
219  * @version Aug 1, 2014 <br>
220  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
221  */
222 class TrajectoriesModel implements OTSModelInterface
223 {
224     /** */
225     private static final long serialVersionUID = 20140815L;
226 
227     /** the simulator. */
228     private OTSDEVSSimulatorInterface simulator;
229 
230     /** the headway (inter-vehicle time). */
231     private DoubleScalar.Rel<TimeUnit> headway;
232 
233     /** number of cars created. */
234     private int carsCreated = 0;
235 
236     /** the car following model, e.g. IDM Plus for cars. */
237     protected GTUFollowingModel carFollowingModelCars;
238 
239     /** the car following model, e.g. IDM Plus for trucks. */
240     protected GTUFollowingModel carFollowingModelTrucks;
241 
242     /** The probability that the next generated GTU is a passenger car. */
243     double carProbability;
244 
245     /** cars in the model. */
246     ArrayList<Car<Integer>> cars = new ArrayList<Car<Integer>>();
247 
248     /** The blocking car. */
249     protected Car<Integer> block = null;
250 
251     /** minimum distance. */
252     private DoubleScalar.Rel<LengthUnit> minimumDistance = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
253 
254     /** maximum distance. */
255     DoubleScalar.Rel<LengthUnit> maximumDistance = new DoubleScalar.Rel<LengthUnit>(5000, LengthUnit.METER);
256 
257     /** The Lane containing the simulated Cars. */
258     Lane lane;
259 
260     /** the speed limit. */
261     DoubleScalar.Abs<SpeedUnit> speedLimit = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
262 
263     /** the trajectory plot. */
264     private TrajectoryPlot trajectoryPlot;
265 
266     /** User settable properties */
267     ArrayList<AbstractProperty<?>> properties = null;
268 
269     /** The random number generator used to decide what kind of GTU to generate. */
270     Random randomGenerator = new Random(12345);
271 
272     /**
273      * @param properties
274      */
275     public TrajectoriesModel(ArrayList<AbstractProperty<?>> properties)
276     {
277         this.properties = properties;
278     }
279 
280     /** {@inheritDoc} */
281     @Override
282     public final void constructModel(
283         final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
284         throws SimRuntimeException, RemoteException
285     {
286         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
287         Node from = new Node("From", new Coordinate(getMinimumDistance().getSI(), 0, 0));
288         Node to = new Node("To", new Coordinate(getMaximumDistance().getSI(), 0, 0));
289         LaneType<String> laneType = new LaneType<String>("CarLane");
290         try
291         {
292             this.lane = LaneFactory.makeLane("Lane", from, to, null, laneType, this.simulator);
293         }
294         catch (NamingException | NetworkException exception1)
295         {
296             exception1.printStackTrace();
297         }
298 
299         for (AbstractProperty<?> p : this.properties)
300         {
301             if (p instanceof SelectionProperty)
302             {
303                 SelectionProperty sp = (SelectionProperty) p;
304                 if ("Car following model".equals(sp.getShortName()))
305                 {
306                     String modelName = sp.getValue();
307                     if (modelName.equals("IDM"))
308                     {
309                         this.carFollowingModelCars =
310                             new IDM(new DoubleScalar.Abs<AccelerationUnit>(1, AccelerationUnit.METER_PER_SECOND_2),
311                                 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
312                                 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
313                                     TimeUnit.SECOND), 1d);
314                         this.carFollowingModelTrucks =
315                             new IDM(new DoubleScalar.Abs<AccelerationUnit>(0.5, AccelerationUnit.METER_PER_SECOND_2),
316                                 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
317                                 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
318                                     TimeUnit.SECOND), 1d);
319                     }
320                     else if (modelName.equals("IDM+"))
321                     {
322                         this.carFollowingModelCars =
323                             new IDMPlus(new DoubleScalar.Abs<AccelerationUnit>(1, AccelerationUnit.METER_PER_SECOND_2),
324                                 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
325                                 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
326                                     TimeUnit.SECOND), 1d);
327                         this.carFollowingModelTrucks =
328                             new IDMPlus(new DoubleScalar.Abs<AccelerationUnit>(0.5, AccelerationUnit.METER_PER_SECOND_2),
329                                 new DoubleScalar.Abs<AccelerationUnit>(1.5, AccelerationUnit.METER_PER_SECOND_2),
330                                 new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER), new DoubleScalar.Rel<TimeUnit>(1,
331                                     TimeUnit.SECOND), 1d);
332                     }
333                     else
334                     {
335                         throw new Error("Car following model " + modelName + " not implemented");
336                     }
337                 }
338                 else
339                 {
340                     throw new Error("Unhandled SelectionProperty " + p.getShortName());
341                 }
342             }
343             else if (p instanceof ProbabilityDistributionProperty)
344             {
345                 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
346                 String modelName = p.getShortName();
347                 if (modelName.equals("Traffic composition"))
348                 {
349                     this.carProbability = pdp.getValue()[0];
350                 }
351                 else
352                 {
353                     throw new Error("Unhandled ProbabilityDistributionProperty " + p.getShortName());
354                 }
355             }
356             else
357             {
358                 throw new Error("Unhandled property: " + p);
359             }
360         }
361         // 1500 [vehicles / hour] == 2.4s headway
362         this.headway = new DoubleScalar.Rel<TimeUnit>(3600.0 / 1500.0, TimeUnit.SECOND);
363 
364         try
365         {
366             // Schedule creation of the first car (this will re-schedule itself one headway later, etc.).
367             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND), this, this, "generateCar",
368                 null);
369             // Create a block at t = 5 minutes
370             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(300, TimeUnit.SECOND), this, this, "createBlock",
371                 null);
372             // Remove the block at t = 8 minutes, 20 seconds
373             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(500, TimeUnit.SECOND), this, this, "removeBlock",
374                 null);
375             // Schedule regular updates of the graph
376             for (int t = 1; t <= 1800; t++)
377             {
378                 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, TimeUnit.SECOND), this, this,
379                     "drawGraph", null);
380             }
381         }
382         catch (RemoteException | SimRuntimeException exception)
383         {
384             exception.printStackTrace();
385         }
386     }
387 
388     /**
389      * Set up the block.
390      * @throws RemoteException on communications failure
391      * @throws NamingException on error during adding of animation handler
392      */
393     protected final void createBlock() throws RemoteException, NamingException, SimRuntimeException, NetworkException
394     {
395         DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(4000, LengthUnit.METER);
396         Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
397         initialPositions.put(this.lane, initialPosition);
398         this.block =
399             new Car<Integer>(999999, null, null, initialPositions,
400                 new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR), new DoubleScalar.Rel<LengthUnit>(0.1,
401                     LengthUnit.METER), new DoubleScalar.Rel<LengthUnit>(2, LengthUnit.METER),
402                 new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR), this.simulator);
403         // TODO remove the animation
404     }
405 
406     /**
407      * Remove the block.
408      */
409     protected final void removeBlock()
410     {
411         this.block = null;
412     }
413 
414     /**
415      * Generate cars at a fixed rate (implemented by re-scheduling this method).
416      */
417     protected final void generateCar()
418     {
419         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
420         DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
421         Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
422         initialPositions.put(this.lane, initialPosition);
423         DoubleScalar.Abs<SpeedUnit> initialSpeed = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
424         try
425         {
426             DoubleScalar.Rel<LengthUnit> vehicleLength =
427                 new DoubleScalar.Rel<LengthUnit>(generateTruck ? 15 : 4, LengthUnit.METER);
428             IDMCar car =
429                 new IDMCar(++this.carsCreated, null, this.simulator, generateTruck ? this.carFollowingModelTrucks
430                     : this.carFollowingModelCars, vehicleLength, this.simulator.getSimulatorTime().get(), initialPositions,
431                     initialSpeed);
432             this.cars.add(0, car);
433             // Re-schedule this method after headway seconds
434             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
435         }
436         catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
437         {
438             exception.printStackTrace();
439         }
440     }
441 
442     /** {@inheritDoc} */
443     @Override
444     public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
445         throws RemoteException
446     {
447         return this.simulator;
448     }
449 
450     /** Inner class IDMCar. */
451     protected class IDMCar extends Car<Integer>
452     {
453         /** */
454         private static final long serialVersionUID = 20141030L;
455 
456         /**
457          * Create a new IDMCar.
458          * @param id integer; the id of the new IDMCar
459          * @param gtuType GTUType&lt;String&gt;; the type of the GTU
460          * @param simulator OTSDEVSSimulator; the simulator that runs the new IDMCar
461          * @param carFollowingModel CarFollowingModel; the car following model of the new IDMCar
462          * @param vehicleLength DoubleScalar.Rel&lt;LengthUnit&gt;; the length of the new IDMCar
463          * @param initialTime DoubleScalar.Abs&lt;TimeUnit&gt;; the time of first evaluation of the new IDMCar
464          * @param initialLongitudinalPositions Map&lt;Lane, DoubleScalar.Rel&lt;LengthUnit&gt;&gt;; the initial lane positions
465          *            of the new IDMCar
466          * @param initialSpeed DoubleScalar.Abs&lt;SpeedUnit&gt;; the initial speed of the new IDMCar
467          * @throws NamingException on ???
468          * @throws RemoteException on communication failure
469          */
470         public IDMCar(final int id, GTUType<String> gtuType, final OTSDEVSSimulatorInterface simulator,
471             final GTUFollowingModel carFollowingModel, DoubleScalar.Rel<LengthUnit> vehicleLength,
472             final DoubleScalar.Abs<TimeUnit> initialTime,
473             final Map<Lane, DoubleScalar.Rel<LengthUnit>> initialLongitudinalPositions,
474             final DoubleScalar.Abs<SpeedUnit> initialSpeed) throws RemoteException, NamingException, SimRuntimeException,
475             NetworkException
476         {
477             super(id, gtuType, carFollowingModel, initialLongitudinalPositions, initialSpeed, vehicleLength,
478                 new DoubleScalar.Rel<LengthUnit>(1.8, LengthUnit.METER), new DoubleScalar.Abs<SpeedUnit>(200,
479                     SpeedUnit.KM_PER_HOUR), simulator);
480             try
481             {
482                 simulator.scheduleEventAbs(simulator.getSimulatorTime(), this, this, "move", null);
483             }
484             catch (SimRuntimeException exception)
485             {
486                 exception.printStackTrace();
487             }
488         }
489 
490         /**
491          * @throws RemoteException on communication failure
492          * @throws NetworkException when the network is inconsistent
493          * @throws SimRuntimeException on ???
494          */
495         protected final void move() throws RemoteException, NetworkException, SimRuntimeException
496         {
497             Lane currentLane = positions(getFront()).keySet().iterator().next();
498             // System.out.println("move " + getId());
499             if (position(currentLane, getFront()).getSI() > getMaximumDistance().getSI())
500             {
501                 TrajectoriesModel.this.cars.remove(this);
502                 return;
503             }
504             Collection<Car<Integer>> leaders = new ArrayList<Car<Integer>>();
505             // FIXME: there should be a much easier way to obtain the leader; we should not have to maintain our own
506             // list
507             int carIndex = TrajectoriesModel.this.cars.indexOf(this);
508             if (carIndex < TrajectoriesModel.this.cars.size() - 1)
509             {
510                 leaders.add(TrajectoriesModel.this.cars.get(carIndex + 1));
511             }
512             GTUFollowingModelResult cfmr =
513                 getGTUFollowingModel().computeAcceleration(this, leaders, TrajectoriesModel.this.speedLimit);
514             if (null != TrajectoriesModel.this.block)
515             {
516                 leaders.clear();
517                 leaders.add(TrajectoriesModel.this.block);
518                 if (position(currentLane, getFront()).getSI() > 3850 && position(currentLane, getFront()).getSI() < 4000
519                     && getId() == 57 && getNextEvaluationTime().getSI() > 312)
520                 {
521                     System.out.println("Pas op; vehicle " + this);
522                 }
523                 GTUFollowingModelResult blockCFMR =
524                     getGTUFollowingModel().computeAcceleration(this, leaders, TrajectoriesModel.this.speedLimit);
525                 if (blockCFMR.getAcceleration().getSI() < cfmr.getAcceleration().getSI()
526                     && blockCFMR.getAcceleration().getSI() >= -5)
527                 {
528                     cfmr = blockCFMR;
529                 }
530             }
531             if (cfmr.getAcceleration().getSI() < -0.1)
532             {
533                 // System.out.println("Deceleration: " + cfmr.getAcceleration());
534             }
535             setState(cfmr);
536 
537             // Add the movement of this Car to the contour plots
538             addToTrajectoryPlot(this);
539             getSimulator().scheduleEventRel(new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), this, this, "move", null);
540         }
541 
542     }
543 
544     /**
545      * @param idmCar IDMCar
546      * @throws NetworkException when car not in lane
547      * @throws RemoteException when communication fails
548      */
549     final void addToTrajectoryPlot(final IDMCar idmCar) throws NetworkException, RemoteException
550     {
551         this.trajectoryPlot.addData(idmCar);
552     }
553 
554     /**
555      * Notify the contour plots that the underlying data has changed.
556      */
557     protected final void drawGraph()
558     {
559         this.trajectoryPlot.reGraph();
560     }
561 
562     /**
563      * @return minimum distance of the simulation
564      */
565     public final DoubleScalar.Rel<LengthUnit> getMinimumDistance()
566     {
567         return this.minimumDistance;
568     }
569 
570     /**
571      * @return maximum distance of the simulation
572      */
573     public final DoubleScalar.Rel<LengthUnit> getMaximumDistance()
574     {
575         return this.maximumDistance;
576     }
577 
578     /**
579      * @param trajectoryPlot TrajectoryPlot
580      */
581     public final void setTrajectoryPlot(final TrajectoryPlot trajectoryPlot)
582     {
583         this.trajectoryPlot = trajectoryPlot;
584     }
585 
586 }