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.Collection;
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.Map;
14 import java.util.Random;
15
16 import javax.naming.NamingException;
17 import javax.swing.JScrollPane;
18 import javax.swing.SwingUtilities;
19
20 import nl.tudelft.simulation.dsol.SimRuntimeException;
21 import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
22 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
23 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
24
25 import org.opentrafficsim.car.Car;
26 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
27 import org.opentrafficsim.core.dsol.OTSModelInterface;
28 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29 import org.opentrafficsim.core.gtu.GTUType;
30 import org.opentrafficsim.core.gtu.following.GTUFollowingModel;
31 import org.opentrafficsim.core.gtu.following.GTUFollowingModel.GTUFollowingModelResult;
32 import org.opentrafficsim.core.gtu.following.IDM;
33 import org.opentrafficsim.core.gtu.following.IDMPlus;
34 import org.opentrafficsim.core.network.NetworkException;
35 import org.opentrafficsim.core.network.factory.LaneFactory;
36 import org.opentrafficsim.core.network.factory.Node;
37 import org.opentrafficsim.core.network.lane.Lane;
38 import org.opentrafficsim.core.network.lane.LaneType;
39 import org.opentrafficsim.core.unit.AccelerationUnit;
40 import org.opentrafficsim.core.unit.LengthUnit;
41 import org.opentrafficsim.core.unit.SpeedUnit;
42 import org.opentrafficsim.core.unit.TimeUnit;
43 import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
44 import org.opentrafficsim.graphs.AccelerationContourPlot;
45 import org.opentrafficsim.graphs.ContourPlot;
46 import org.opentrafficsim.graphs.DensityContourPlot;
47 import org.opentrafficsim.graphs.FlowContourPlot;
48 import org.opentrafficsim.graphs.LaneBasedGTUSampler;
49 import org.opentrafficsim.graphs.SpeedContourPlot;
50 import org.opentrafficsim.graphs.TrajectoryPlot;
51 import org.opentrafficsim.simulationengine.AbstractProperty;
52 import org.opentrafficsim.simulationengine.BooleanProperty;
53 import org.opentrafficsim.simulationengine.CompoundProperty;
54 import org.opentrafficsim.simulationengine.ControlPanel;
55 import org.opentrafficsim.simulationengine.IDMPropertySet;
56 import org.opentrafficsim.simulationengine.ProbabilityDistributionProperty;
57 import org.opentrafficsim.simulationengine.PropertyException;
58 import org.opentrafficsim.simulationengine.SelectionProperty;
59 import org.opentrafficsim.simulationengine.SimpleSimulator;
60 import org.opentrafficsim.simulationengine.SimulatorFrame;
61 import org.opentrafficsim.simulationengine.WrappableSimulation;
62
63 import com.vividsolutions.jts.geom.Coordinate;
64
65
66
67
68
69
70
71
72
73
74 public class Straight implements WrappableSimulation
75 {
76
77 private ArrayList<AbstractProperty<?>> properties = new ArrayList<AbstractProperty<?>>();
78
79
80 public Straight()
81 {
82 ArrayList<AbstractProperty<?>> outputProperties = new ArrayList<AbstractProperty<?>>();
83 outputProperties.add(new BooleanProperty("Density", "Density contour plot", true, false, 0));
84 outputProperties.add(new BooleanProperty("Flow", "Flow contour plot", true, false, 1));
85 outputProperties.add(new BooleanProperty("Speed", "Speed contour plot", true, false, 2));
86 outputProperties.add(new BooleanProperty("Acceleration", "Acceleration contour plot", true, false, 3));
87 outputProperties.add(new BooleanProperty("Trajectories", "Trajectory (time/distance) diagram", true, false, 4));
88 this.properties.add(new CompoundProperty("Output", "Select the graphical output", outputProperties, true, 1000));
89 }
90
91
92
93
94
95
96
97 public static void main(final String[] args) throws RemoteException, SimRuntimeException
98 {
99 SwingUtilities.invokeLater(new Runnable()
100 {
101 @Override
102 public void run()
103 {
104 try
105 {
106 Straight straight = new Straight();
107 ArrayList<AbstractProperty<?>> localProperties = straight.getProperties();
108 try
109 {
110 localProperties.add(new ProbabilityDistributionProperty("Traffic composition",
111 "<html>Mix of passenger cars and trucks</html>", new String[] {"passenger car", "truck"},
112 new Double[] {0.8, 0.2}, false, 10));
113 }
114 catch (PropertyException exception)
115 {
116 exception.printStackTrace();
117 }
118 localProperties.add(new SelectionProperty("Car following model",
119 "<html>The car following model determines "
120 + "the acceleration that a vehicle will make taking into account "
121 + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
122 + "curvature of the road) capabilities of the vehicle and personality "
123 + "of the driver.</html>", new String[] {"IDM", "IDM+"}, 1, false, 1));
124 localProperties.add(IDMPropertySet.makeIDMPropertySet("Car", new DoubleScalar.Abs<AccelerationUnit>(1.0,
125 AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Abs<AccelerationUnit>(1.5,
126 AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<LengthUnit>(2.0, LengthUnit.METER),
127 new DoubleScalar.Rel<TimeUnit>(1.0, TimeUnit.SECOND), 2));
128 localProperties.add(IDMPropertySet.makeIDMPropertySet("Truck", new DoubleScalar.Abs<AccelerationUnit>(
129 0.5, AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Abs<AccelerationUnit>(1.25,
130 AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<LengthUnit>(2.0, LengthUnit.METER),
131 new DoubleScalar.Rel<TimeUnit>(1.0, TimeUnit.SECOND), 3));
132 new SimulatorFrame("Contour Plots animation", straight.buildSimulator(localProperties).getPanel());
133 }
134 catch (RemoteException | SimRuntimeException exception)
135 {
136 exception.printStackTrace();
137 }
138 }
139 });
140 }
141
142
143
144
145
146
147
148
149 public final SimpleSimulator buildSimulator(final ArrayList<AbstractProperty<?>> userModifiedProperties)
150 throws SimRuntimeException, RemoteException
151 {
152 StraightModel model = new StraightModel(userModifiedProperties);
153 SimpleSimulator result =
154 new SimpleSimulator(new OTSSimTimeDouble(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND)),
155 new DoubleScalar.Rel<TimeUnit>(0.0, TimeUnit.SECOND),
156 new DoubleScalar.Rel<TimeUnit>(1800.0, TimeUnit.SECOND), model, new Rectangle2D.Double(0, -100, 5000, 200));
157 new ControlPanel(result);
158
159
160 String helpSource = "/" + StraightModel.class.getPackage().getName().replace('.', '/') + "/IDMPlus.html";
161 URL page = StraightModel.class.getResource(helpSource);
162 if (page != null)
163 {
164 try
165 {
166 HTMLPanel htmlPanel = new HTMLPanel(page);
167 result.getPanel().getTabbedPane().addTab("info", new JScrollPane(htmlPanel));
168 }
169 catch (IOException exception)
170 {
171 exception.printStackTrace();
172 }
173 }
174
175
176 AbstractProperty<?> output = new CompoundProperty("", "", this.properties, false, 0).findByShortName("Output");
177 if (null == output)
178 {
179 throw new Error("Cannot find output properties");
180 }
181 ArrayList<BooleanProperty> graphs = new ArrayList<BooleanProperty>();
182 if (output instanceof CompoundProperty)
183 {
184 CompoundProperty outputProperties = (CompoundProperty) output;
185 for (AbstractProperty<?> ap : outputProperties.getValue())
186 {
187 if (ap instanceof BooleanProperty)
188 {
189 BooleanProperty bp = (BooleanProperty) ap;
190 if (bp.getValue())
191 {
192 graphs.add(bp);
193 }
194 }
195 }
196 }
197 else
198 {
199 throw new Error("output properties should be compound");
200 }
201 int graphCount = graphs.size();
202 int columns = (int) Math.ceil(Math.sqrt(graphCount));
203 int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
204 TablePanel charts = new TablePanel(columns, rows);
205 result.getPanel().getTabbedPane().addTab("statistics", charts);
206
207 for (int i = 0; i < graphCount; i++)
208 {
209 String graphName = graphs.get(i).getShortName();
210 Container container = null;
211 LaneBasedGTUSampler graph;
212 if (graphName.contains("Trajectories"))
213 {
214 TrajectoryPlot tp =
215 new TrajectoryPlot("TrajectoryPlot", new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), model
216 .getMinimumDistance(), model.getMaximumDistance());
217 tp.setTitle("Trajectory Graph");
218 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
219 graph = tp;
220 container = tp.getContentPane();
221 }
222 else
223 {
224 ContourPlot cp;
225 if (graphName.contains("Density"))
226 {
227 cp = new DensityContourPlot("DensityPlot", model.getMinimumDistance(), model.getMaximumDistance());
228 cp.setTitle("Density Contour Graph");
229 }
230 else if (graphName.contains("Speed"))
231 {
232 cp = new SpeedContourPlot("SpeedPlot", model.getMinimumDistance(), model.getMaximumDistance());
233 cp.setTitle("Speed Contour Graph");
234 }
235 else if (graphName.contains("Flow"))
236 {
237 cp = new FlowContourPlot("FlowPlot", model.getMinimumDistance(), model.getMaximumDistance());
238 cp.setTitle("Flow Contour Graph");
239 }
240 else if (graphName.contains("Acceleration"))
241 {
242 cp =
243 new AccelerationContourPlot("AccelerationPlot", model.getMinimumDistance(), model
244 .getMaximumDistance());
245 cp.setTitle("Acceleration Contour Graph");
246 }
247 else
248 {
249 throw new Error("Unhandled type of contourplot: " + graphName);
250 }
251 graph = cp;
252 container = cp.getContentPane();
253 }
254
255 charts.setCell(container, i % columns, i / columns);
256 model.getPlots().add(graph);
257 }
258 return result;
259 }
260
261
262 @Override
263 public final String shortName()
264 {
265 return "Straight lane";
266 }
267
268
269 @Override
270 public final String description()
271 {
272 return "<html><h1>Simulation of a straight one-lane road with opening bridge</H1>"
273 + "Simulation of a single lane road of 5 km length. Vehicles are generated at a constant rate of "
274 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at "
275 + "time 420s. This blockade simulates a bridge opening.<br/>"
276 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br />"
277 + "Selected trajectory and contour plots are generated during the simulation.</html>";
278 }
279
280
281 @Override
282 public final ArrayList<AbstractProperty<?>> getProperties()
283 {
284 return new ArrayList<AbstractProperty<?>>(this.properties);
285 }
286
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 class StraightModel implements OTSModelInterface
310 {
311
312 private static final long serialVersionUID = 20140815L;
313
314
315 private OTSDEVSSimulatorInterface simulator;
316
317
318 private DoubleScalar.Rel<TimeUnit> headway;
319
320
321 private int carsCreated = 0;
322
323
324 private GTUFollowingModel carFollowingModelCars;
325
326
327 private GTUFollowingModel carFollowingModelTrucks;
328
329
330 private double carProbability;
331
332
333 private ArrayList<Car<Integer>> cars = new ArrayList<Car<Integer>>();
334
335
336 private Car<Integer> block = null;
337
338
339 private DoubleScalar.Rel<LengthUnit> minimumDistance = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
340
341
342 private DoubleScalar.Rel<LengthUnit> maximumDistance = new DoubleScalar.Rel<LengthUnit>(5000, LengthUnit.METER);
343
344
345 private Lane lane;
346
347
348 private DoubleScalar.Abs<SpeedUnit> speedLimit = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
349
350
351 private ArrayList<LaneBasedGTUSampler> plots = new ArrayList<LaneBasedGTUSampler>();
352
353
354 private ArrayList<AbstractProperty<?>> properties = null;
355
356
357 private Random randomGenerator = new Random(12345);
358
359
360
361
362 public StraightModel(final ArrayList<AbstractProperty<?>> properties)
363 {
364 this.properties = properties;
365 }
366
367
368 @Override
369 public final void constructModel(
370 final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
371 throws SimRuntimeException, RemoteException
372 {
373 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
374 Node from = new Node("From", new Coordinate(getMinimumDistance().getSI(), 0, 0));
375 Node to = new Node("To", new Coordinate(getMaximumDistance().getSI(), 0, 0));
376 try
377 {
378 LaneType<String> laneType = new LaneType<String>("CarLane");
379 this.lane = LaneFactory.makeLane("Lane", from, to, null, laneType, this.simulator);
380 String carFollowingModelName = null;
381 CompoundProperty propertyContainer = new CompoundProperty("", "", this.properties, false, 0);
382 AbstractProperty<?> cfmp = propertyContainer.findByShortName("Car following model");
383 if (null == cfmp)
384 {
385 throw new Error("Cannot find \"Car following model\" property");
386 }
387 if (cfmp instanceof SelectionProperty)
388 {
389 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
390 }
391 else
392 {
393 throw new Error("\"Car following model\" property has wrong type");
394 }
395 Iterator<AbstractProperty<ArrayList<AbstractProperty<?>>>> iterator =
396 new CompoundProperty("", "", this.properties, false, 0).iterator();
397 while (iterator.hasNext())
398 {
399 AbstractProperty<?> ap = iterator.next();
400 if (ap instanceof SelectionProperty)
401 {
402 SelectionProperty sp = (SelectionProperty) ap;
403 if ("Car following model".equals(sp.getShortName()))
404 {
405 if ("Car following model".equals(sp.getShortName()))
406 {
407 carFollowingModelName = sp.getValue();
408 }
409 }
410 }
411 else if (ap instanceof ProbabilityDistributionProperty)
412 {
413 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
414 String modelName = ap.getShortName();
415 if (modelName.equals("Traffic composition"))
416 {
417 this.carProbability = pdp.getValue()[0];
418 }
419 }
420 else if (ap instanceof CompoundProperty)
421 {
422 CompoundProperty cp = (CompoundProperty) ap;
423 if (ap.getShortName().equals("Output"))
424 {
425 continue;
426 }
427 if (ap.getShortName().contains("IDM"))
428 {
429 DoubleScalar.Abs<AccelerationUnit> a = IDMPropertySet.getA(cp);
430 DoubleScalar.Abs<AccelerationUnit> b = IDMPropertySet.getB(cp);
431 DoubleScalar.Rel<LengthUnit> s0 = IDMPropertySet.getS0(cp);
432 DoubleScalar.Rel<TimeUnit> tSafe = IDMPropertySet.getTSafe(cp);
433 GTUFollowingModel gtuFollowingModel = null;
434 if (carFollowingModelName.equals("IDM"))
435 {
436 gtuFollowingModel = new IDM(a, b, s0, tSafe, 1.0);
437 }
438 else if (carFollowingModelName.equals("IDM+"))
439 {
440 gtuFollowingModel = new IDMPlus(a, b, s0, tSafe, 1.0);
441 }
442 else
443 {
444 throw new Error("Unknown gtu following model: " + carFollowingModelName);
445 }
446 if (ap.getShortName().contains(" Car "))
447 {
448 this.carFollowingModelCars = gtuFollowingModel;
449 }
450 else if (ap.getShortName().contains(" Truck "))
451 {
452 this.carFollowingModelTrucks = gtuFollowingModel;
453 }
454 else
455 {
456 throw new Error("Cannot determine gtu type for " + ap.getShortName());
457 }
458
459
460
461
462
463 }
464 }
465 }
466
467 this.headway = new DoubleScalar.Rel<TimeUnit>(3600.0 / 1500.0, TimeUnit.SECOND);
468
469 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND), this, this, "generateCar",
470 null);
471
472 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(300, TimeUnit.SECOND), this, this, "createBlock",
473 null);
474
475 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(420, TimeUnit.SECOND), this, this, "removeBlock",
476 null);
477
478 for (int t = 1; t <= 1800; t++)
479 {
480 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, TimeUnit.SECOND), this, this,
481 "drawGraphs", null);
482 }
483 }
484 catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
485 {
486 exception.printStackTrace();
487 }
488 }
489
490
491
492
493
494
495
496 protected final void addToContourPlots(final Car<?> car) throws RemoteException, NetworkException
497 {
498 for (LaneBasedGTUSampler plot : this.plots)
499 {
500 plot.addData(car);
501 }
502 }
503
504
505
506
507 protected final void drawGraphs()
508 {
509 for (LaneBasedGTUSampler plot : this.plots)
510 {
511 plot.reGraph();
512 }
513 }
514
515
516
517
518
519 protected final void createBlock() throws RemoteException
520 {
521 DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(4000, LengthUnit.METER);
522 Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
523 initialPositions.put(this.lane, initialPosition);
524 try
525 {
526 this.block =
527 new IDMCar(999999, null, this.simulator, this.carFollowingModelCars, new DoubleScalar.Rel<LengthUnit>(4,
528 LengthUnit.METER), this.simulator.getSimulatorTime().get(), initialPositions,
529 new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR));
530 }
531 catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
532 {
533 exception.printStackTrace();
534 }
535 }
536
537
538
539
540 protected final void removeBlock()
541 {
542 this.block = null;
543 }
544
545
546
547
548 protected final void generateCar()
549 {
550 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
551 DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
552 DoubleScalar.Abs<SpeedUnit> initialSpeed = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
553 Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
554 initialPositions.put(this.lane, initialPosition);
555 try
556 {
557 DoubleScalar.Rel<LengthUnit> vehicleLength =
558 new DoubleScalar.Rel<LengthUnit>(generateTruck ? 15 : 4, LengthUnit.METER);
559 IDMCar car =
560 new IDMCar(++this.carsCreated, null, this.simulator, generateTruck ? this.carFollowingModelTrucks
561 : this.carFollowingModelCars, vehicleLength, this.simulator.getSimulatorTime().get(), initialPositions,
562 initialSpeed);
563 this.cars.add(0, car);
564 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
565 }
566 catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
567 {
568 exception.printStackTrace();
569 }
570 }
571
572
573 @Override
574 public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
575 throws RemoteException
576 {
577 return this.simulator;
578 }
579
580
581
582
583 public final ArrayList<LaneBasedGTUSampler> getPlots()
584 {
585 return this.plots;
586 }
587
588
589
590
591 public final DoubleScalar.Rel<LengthUnit> getMinimumDistance()
592 {
593 return this.minimumDistance;
594 }
595
596
597
598
599 public final DoubleScalar.Rel<LengthUnit> getMaximumDistance()
600 {
601 return this.maximumDistance;
602 }
603
604
605 protected class IDMCar extends Car<Integer>
606 {
607
608 private static final long serialVersionUID = 20141030L;
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626 @SuppressWarnings("checkstyle:parameternumber")
627 public IDMCar(final int id, final GTUType<String> gtuType, final OTSDEVSSimulatorInterface simulator,
628 final GTUFollowingModel carFollowingModel, final DoubleScalar.Rel<LengthUnit> vehicleLength,
629 final DoubleScalar.Abs<TimeUnit> initialTime,
630 final Map<Lane, DoubleScalar.Rel<LengthUnit>> initialLongitudinalPositions,
631 final DoubleScalar.Abs<SpeedUnit> initialSpeed) throws RemoteException, NamingException, NetworkException,
632 SimRuntimeException
633 {
634 super(id, gtuType, carFollowingModel, initialLongitudinalPositions, initialSpeed, vehicleLength,
635 new DoubleScalar.Rel<LengthUnit>(1.8, LengthUnit.METER), new DoubleScalar.Abs<SpeedUnit>(200,
636 SpeedUnit.KM_PER_HOUR), simulator);
637 try
638 {
639 simulator.scheduleEventAbs(simulator.getSimulatorTime(), this, this, "move", null);
640 }
641 catch (SimRuntimeException exception)
642 {
643 exception.printStackTrace();
644 }
645 }
646
647
648
649
650
651
652
653 protected final void move() throws RemoteException, NamingException, NetworkException, SimRuntimeException
654 {
655
656 if (this == StraightModel.this.block)
657 {
658 return;
659 }
660 if (position(StraightModel.this.lane, getFront()).getSI() > getMaximumDistance().getSI())
661 {
662 StraightModel.this.cars.remove(this);
663 return;
664 }
665 Collection<Car<Integer>> leaders = new ArrayList<Car<Integer>>();
666
667
668 int carIndex = StraightModel.this.cars.indexOf(this);
669 if (carIndex < StraightModel.this.cars.size() - 1)
670 {
671 leaders.add(StraightModel.this.cars.get(carIndex + 1));
672 }
673 GTUFollowingModelResult cfmr =
674 getGTUFollowingModel().computeAcceleration(this, leaders, StraightModel.this.speedLimit);
675 if (null != StraightModel.this.block)
676 {
677 leaders.clear();
678 leaders.add(StraightModel.this.block);
679 GTUFollowingModelResult blockCFMR =
680 getGTUFollowingModel().computeAcceleration(this, leaders, StraightModel.this.speedLimit);
681 if (blockCFMR.getAcceleration().getSI() < cfmr.getAcceleration().getSI()
682 && blockCFMR.getAcceleration().getSI() >= -5)
683 {
684 cfmr = blockCFMR;
685 }
686 }
687 setState(cfmr);
688
689 addToContourPlots(this);
690
691 getSimulator().scheduleEventRel(new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), this, this, "move", null);
692 }
693 }
694 }