View Javadoc
1   package org.opentrafficsim.road.car;
2   
3   import java.lang.reflect.Constructor;
4   import java.lang.reflect.InvocationTargetException;
5   import java.util.LinkedHashMap;
6   import java.util.Map;
7   
8   import javax.naming.NamingException;
9   
10  import nl.tudelft.simulation.dsol.SimRuntimeException;
11  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
12  import nl.tudelft.simulation.language.reflection.ClassUtil;
13  
14  import org.opentrafficsim.core.dsol.OTSAnimatorInterface;
15  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
16  import org.opentrafficsim.core.gtu.GTUException;
17  import org.opentrafficsim.core.gtu.GTUType;
18  import org.opentrafficsim.core.gtu.RelativePosition;
19  import org.opentrafficsim.core.gtu.RelativePosition.TYPE;
20  import org.opentrafficsim.core.gtu.animation.GTUColorer;
21  import org.opentrafficsim.core.network.NetworkException;
22  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
23  import org.opentrafficsim.road.gtu.following.GTUFollowingModel;
24  import org.opentrafficsim.road.gtu.lane.AbstractLaneBasedIndividualGTU;
25  import org.opentrafficsim.road.gtu.lane.changing.LaneChangeModel;
26  import org.opentrafficsim.road.network.lane.Lane;
27  import org.opentrafficsim.road.network.route.LaneBasedRouteGenerator;
28  import org.opentrafficsim.road.network.route.LaneBasedRouteNavigator;
29  
30  /**
31   * Augments the AbstractLaneBasedIndividualGTU with a LaneBasedIndividualCarBuilder and animation support
32   * <p>
33   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
34   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
35   * <p>
36   * @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
37   *          initial version Oct 22, 2014 <br>
38   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
39   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
40   */
41  public class LaneBasedIndividualCar extends AbstractLaneBasedIndividualGTU
42  {
43      /** */
44      private static final long serialVersionUID = 20141025L;
45  
46      /** animation. */
47      private Renderable2D animation;
48  
49      /** Sensing positions. */
50      private final Map<RelativePosition.TYPE, RelativePosition> relativePositions = new LinkedHashMap<>();
51  
52      /**
53       * @param id ID; the id of the GTU
54       * @param gtuType GTUType; the type of GTU, e.g. TruckType, CarType, BusType
55       * @param gtuFollowingModel GTUFollowingModel; the following model, including a reference to the simulator
56       * @param laneChangeModel LaneChangeModel; the lane change model
57       * @param initialLongitudinalPositions Map&lt;Lane, DoubleScalar.Rel&lt;LengthUnit&gt;&gt;; the initial positions of the car
58       *            on one or more lanes
59       * @param initialSpeed DoubleScalar.Abs&lt;SpeedUnit&gt;; the initial speed of the car on the lane
60       * @param length DoubleScalar.Rel&lt;LengthUnit&gt;; the maximum length of the GTU (parallel with driving direction)
61       * @param width DoubleScalar.Rel&lt;LengthUnit&gt;; the maximum width of the GTU (perpendicular to driving direction)
62       * @param maximumVelocity DoubleScalar.Abs&lt;SpeedUnit&gt;;the maximum speed of the GTU (in the driving direction)
63       * @param routeNavigator Route; the route that the GTU will follow
64       * @param simulator OTSDEVSSimulatorInterface; the simulator
65       * @throws NamingException if an error occurs when adding the animation handler
66       * @throws NetworkException when the GTU cannot be placed on the given lane
67       * @throws SimRuntimeException when the move method cannot be scheduled
68       * @throws GTUException when a parameter is invalid
69       */
70      @SuppressWarnings("checkstyle:parameternumber")
71      public LaneBasedIndividualCar(final String id, final GTUType gtuType, final GTUFollowingModel gtuFollowingModel,
72          final LaneChangeModel laneChangeModel, final Map<Lane, Length.Rel> initialLongitudinalPositions,
73          final Speed.Abs initialSpeed, final Length.Rel length, final Length.Rel width, final Speed.Abs maximumVelocity,
74          final LaneBasedRouteNavigator routeNavigator, final OTSDEVSSimulatorInterface simulator)
75          throws NamingException, NetworkException, SimRuntimeException, GTUException
76      {
77          this(id, gtuType, gtuFollowingModel, laneChangeModel, initialLongitudinalPositions, initialSpeed, length,
78              width, maximumVelocity, routeNavigator, simulator, DefaultCarAnimation.class, null);
79      }
80  
81      /**
82       * Construct a new LaneBasedIndividualCar.
83       * @param id ID; the id of the GTU
84       * @param gtuType GTUTYpe; the type of GTU, e.g. TruckType, CarType, BusType
85       * @param gtuFollowingModel GTUFollowingModel; the following model, including a reference to the simulator
86       * @param laneChangeModel LaneChangeModel; the lane change model
87       * @param initialLongitudinalPositions Map&lt;Lane, DoubleScalar.Rel&lt;LengthUnit&gt;&gt;; the initial positions of the car
88       *            on one or more lanes
89       * @param initialSpeed DoubleScalar.Abs&lt;SpeedUnit&gt;; the initial speed of the car on the lane
90       * @param length DoubleScalar.Rel&lt;LengthUnit&gt;; the maximum length of the GTU (parallel with driving direction)
91       * @param width DoubleScalar.Rel&lt;LengthUnit&gt;; the maximum width of the GTU (perpendicular to driving direction)
92       * @param maximumVelocity DoubleScalar.Abs&lt;SpeedUnit&gt;;the maximum speed of the GTU (in the driving direction)
93       * @param routeNavigator Route the route that the GTU will follow
94       * @param simulator OTSDEVSSimulatorInterface; the simulator
95       * @param animationClass Class&lt;? extends Renderable2D&gt;; the class for animation or null if no animation
96       * @param gtuColorer GTUColorer; the GTUColorer that will be linked from the animation to determine the color (may be null
97       *            in which case a default will be used)
98       * @throws NamingException if an error occurs when adding the animation handler
99       * @throws NetworkException when the GTU cannot be placed on the given lane
100      * @throws SimRuntimeException when the move method cannot be scheduled
101      * @throws GTUException when a parameter is invalid
102      */
103     @SuppressWarnings("checkstyle:parameternumber")
104     public LaneBasedIndividualCar(final String id, final GTUType gtuType, final GTUFollowingModel gtuFollowingModel,
105         final LaneChangeModel laneChangeModel, final Map<Lane, Length.Rel> initialLongitudinalPositions,
106         final Speed.Abs initialSpeed, final Length.Rel length, final Length.Rel width, final Speed.Abs maximumVelocity,
107         final LaneBasedRouteNavigator routeNavigator, final OTSDEVSSimulatorInterface simulator,
108         final Class<? extends Renderable2D> animationClass, final GTUColorer gtuColorer) throws NamingException,
109         NetworkException, SimRuntimeException, GTUException
110     {
111         super(id, gtuType, gtuFollowingModel, laneChangeModel, initialLongitudinalPositions, initialSpeed, length,
112             width, maximumVelocity, routeNavigator, simulator);
113 
114         // sensor positions.
115         // We take the rear position of the Car to be the reference point. So the front is the length
116         // of the Car away from the reference point in the positive (driving) X-direction.
117         Length.Rel zero = new Length.Rel(0.0d, METER);
118         Length.Rel dx = new Length.Rel(getLength().getSI(), METER);
119         this.relativePositions
120             .put(RelativePosition.FRONT, new RelativePosition(dx, zero, zero, RelativePosition.FRONT));
121         this.relativePositions
122             .put(RelativePosition.REAR, new RelativePosition(zero, zero, zero, RelativePosition.REAR));
123         this.relativePositions.put(RelativePosition.REFERENCE, RelativePosition.REFERENCE_POSITION);
124 
125         // animation
126         if (simulator instanceof OTSAnimatorInterface && animationClass != null)
127         {
128             try
129             {
130                 Constructor<?> constructor;
131 
132                 if (null == gtuColorer)
133                 {
134                     constructor = ClassUtil.resolveConstructor(animationClass, new Object[]{this, simulator});
135                     this.animation = (Renderable2D) constructor.newInstance(this, simulator);
136                 }
137                 else
138                 {
139                     constructor =
140                         ClassUtil.resolveConstructor(animationClass, new Object[]{this, simulator, gtuColorer});
141                     this.animation = (Renderable2D) constructor.newInstance(this, simulator, gtuColorer);
142                 }
143             }
144             catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException
145                 | IllegalArgumentException | InvocationTargetException exception)
146             {
147                 throw new NetworkException("Could not instantiate car animation of type " + animationClass.getName(),
148                     exception);
149             }
150         }
151     }
152 
153     /*
154      * REMOVE START PrintWriter pwsimloc; PrintWriter pwthreadloc; OTSDEVSSimulatorInterface simulator; protected void simloc()
155      * { try { Map<Lane, Length.Rel> posmap = positions(getFront()); Lane lane = posmap.keySet().iterator().next();
156      * pwsimloc.write(getSimulator().getSimulatorTime().getTime().getSI() + "\t" + lane.toString() + "\t" +
157      * posmap.get(lane).getSI() + "\n"); pwsimloc.flush(); simulator.scheduleEventRel(new Time.Rel(0.1, SECOND), this, this,
158      * "simloc", null); } catch (RemoteException | NetworkException | SimRuntimeException e) { e.printStackTrace(); } }
159      * protected class ClockLocThread extends Thread {
160      * @Override public void run() { while (true) { try { Thread.sleep(100); Map<Lane, Length.Rel> posmap =
161      * positions(getFront()); Lane lane = posmap.keySet().iterator().next();
162      * pwthreadloc.write(getSimulator().getSimulatorTime().getTime().getSI() + "\t" + lane.toString() + "\t" +
163      * posmap.get(lane).getSI() + "\n"); pwthreadloc.flush(); } catch (RemoteException | NetworkException | InterruptedException
164      * e) { e.printStackTrace(); } } } } /* REMOVE END
165      */
166 
167     /** {@inheritDoc} */
168     @Override
169     @SuppressWarnings("checkstyle:designforextension")
170     public RelativePosition getFront()
171     {
172         return this.relativePositions.get(RelativePosition.FRONT);
173     }
174 
175     /** {@inheritDoc} */
176     @Override
177     @SuppressWarnings("checkstyle:designforextension")
178     public RelativePosition getRear()
179     {
180         return this.relativePositions.get(RelativePosition.REAR);
181     }
182 
183     /** {@inheritDoc} */
184     @Override
185     public final Map<TYPE, RelativePosition> getRelativePositions()
186     {
187         return this.relativePositions;
188     }
189 
190     /** {@inheritDoc} */
191     @Override
192     public final void destroy()
193     {
194         if (this.animation != null)
195         {
196             try
197             {
198                 this.animation.destroy();
199                 this.animation = null;
200             }
201             catch (Exception e)
202             {
203                 System.err.println("Car: " + this.getId());
204                 e.printStackTrace();
205             }
206         }
207         super.destroy();
208     }
209 
210     /** {@inheritDoc} */
211     public final String toString()
212     {
213         Map<Lane, Length.Rel> frontPositions;
214         try
215         {
216             frontPositions = positions(getFront());
217         }
218         catch (NetworkException exception)
219         {
220             return String.format("Car %s [FRONTPOSITIONS EXCEPTION]", getId());
221         }
222         if (frontPositions.size() == 0)
223         {
224             return String.format("Car %s [NOT ON A LANE]", getId());
225         }
226         Lane frontLane = frontPositions.keySet().iterator().next();
227         return String.format("Car %s front: %s[%s]", getId(), frontLane, frontPositions.get(frontLane));
228     }
229 
230     /**
231      * Build an individual car and use easy setter methods to instantiate the car. Typical use looks like:
232      * 
233      * <pre>
234      * LaneBasedIndividualCar&lt;String&gt; car = new LaneBasedIndividualCarBuilder&lt;String&gt;().setId("Car:"+nr)
235      *    .setLength(new DoubleScalar.Rel&lt;LengthUnit&gt;(4.0, METER))....build(); 
236      *    
237      * or
238      * 
239      * LaneBasedIndividualCarBuilder&lt;String&gt; carBuilder = new LaneBasedIndividualCarBuilder&lt;String&gt;();
240      * carBuilder.setId("Car:"+nr);
241      * carBuilder.setLength(new DoubleScalar.Rel&lt;LengthUnit&gt;(4.0, METER));
242      * carBuilder.setWidth(new DoubleScalar.Rel&lt;LengthUnit&gt;(1.8, METER));
243      * ...
244      * LaneBasedIndividualCar&lt;String&gt; car = carBuilder.build();
245      * </pre>
246      * <p>
247      * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. <br>
248      * All rights reserved. <br>
249      * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
250      * <p>
251      * @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
252      *          initial Feb 3, 2015 <br>
253      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
254      */
255     @SuppressWarnings("checkstyle:hiddenfield")
256     public static class LaneBasedIndividualCarBuilder
257     {
258         /** The id of the GTU. */
259         private String id = null;
260 
261         /** The type of GTU, e.g. TruckType, CarType, BusType. */
262         private GTUType gtuType = null;
263 
264         /** The initial positions of the car on one or more lanes. */
265         private Map<Lane, Length.Rel> initialLongitudinalPositions = null;;
266 
267         /** The initial speed of the car on the lane. */
268         private Speed.Abs initialSpeed = null;
269 
270         /** CarFollowingModel used by this Car. */
271         private GTUFollowingModel gtuFollowingModel = null;
272 
273         /** The lane change model. */
274         private LaneChangeModel laneChangeModel = null;
275 
276         /** The length of the GTU (parallel with driving direction). */
277         private Length.Rel length = null;
278 
279         /** The width of the GTU (perpendicular to driving direction). */
280         private Length.Rel width = null;
281 
282         /** The maximum speed of the GTU (in the driving direction). */
283         private Speed.Abs maximumVelocity = null;
284 
285         /** The simulator. */
286         private OTSDEVSSimulatorInterface simulator = null;
287 
288         /** Animation. */
289         private Class<? extends Renderable2D> animationClass = null;
290 
291         /** GTUColorer. */
292         private GTUColorer gtuColorer = null;
293 
294         /** Cached Route. */
295         private LaneBasedRouteGenerator routeGenerator = null;
296 
297         /**
298          * @param id set id
299          * @return the class itself for chaining the setters
300          */
301         public final LaneBasedIndividualCarBuilder setId(final String id)
302         {
303             this.id = id;
304             return this;
305         }
306 
307         /**
308          * @param gtuType set gtuType
309          * @return the class itself for chaining the setters
310          */
311         public final LaneBasedIndividualCarBuilder setGtuType(final GTUType gtuType)
312         {
313             this.gtuType = gtuType;
314             return this;
315         }
316 
317         /**
318          * @param gtuFollowingModel GTUFollowingModel; the GTU following model used by the built cars
319          * @return the class itself for chaining the setters
320          */
321         public final LaneBasedIndividualCarBuilder setGTUFollowingModel(final GTUFollowingModel gtuFollowingModel)
322         {
323             this.gtuFollowingModel = gtuFollowingModel;
324             return this;
325         }
326 
327         /**
328          * @param laneChangeModel AbstractLaneChangeModel; the lane change model
329          * @return the class itself for chaining the setters
330          */
331         public final LaneBasedIndividualCarBuilder setLaneChangeModel(final LaneChangeModel laneChangeModel)
332         {
333             this.laneChangeModel = laneChangeModel;
334             return this;
335         }
336 
337         /**
338          * @param initialLongitudinalPositions set initialLongitudinalPositions
339          * @return the class itself for chaining the setters
340          */
341         public final LaneBasedIndividualCarBuilder setInitialLongitudinalPositions(
342             final Map<Lane, Length.Rel> initialLongitudinalPositions)
343         {
344             this.initialLongitudinalPositions = initialLongitudinalPositions;
345             return this;
346         }
347 
348         /**
349          * @param initialSpeed set initialSpeed
350          * @return the class itself for chaining the setters
351          */
352         public final LaneBasedIndividualCarBuilder setInitialSpeed(final Speed.Abs initialSpeed)
353         {
354             this.initialSpeed = initialSpeed;
355             return this;
356         }
357 
358         /**
359          * @param length set length
360          * @return the class itself for chaining the setters
361          */
362         public final LaneBasedIndividualCarBuilder setLength(final Length.Rel length)
363         {
364             this.length = length;
365             return this;
366         }
367 
368         /**
369          * @param width set width
370          * @return the class itself for chaining the setters
371          */
372         public final LaneBasedIndividualCarBuilder setWidth(final Length.Rel width)
373         {
374             this.width = width;
375             return this;
376         }
377 
378         /**
379          * @param maximumVelocity set maximumVelocity
380          * @return the class itself for chaining the setters
381          */
382         public final LaneBasedIndividualCarBuilder setMaximumVelocity(final Speed.Abs maximumVelocity)
383         {
384             this.maximumVelocity = maximumVelocity;
385             return this;
386         }
387 
388         /**
389          * @param simulator set simulator
390          * @return the class itself for chaining the setters
391          */
392         public final LaneBasedIndividualCarBuilder setSimulator(final OTSDEVSSimulatorInterface simulator)
393         {
394             this.simulator = simulator;
395             return this;
396         }
397 
398         /**
399          * @param animationClass set animation class
400          * @return the class itself for chaining the setters
401          */
402         public final LaneBasedIndividualCarBuilder
403             setAnimationClass(final Class<? extends Renderable2D> animationClass)
404         {
405             this.animationClass = animationClass;
406             return this;
407         }
408 
409         /**
410          * @param routeGenerator set route generator.
411          * @return the class itself for chaining the setters
412          */
413         public final LaneBasedIndividualCarBuilder setRouteGenerator(final LaneBasedRouteGenerator routeGenerator)
414         {
415             this.routeGenerator = routeGenerator;
416             return this;
417         }
418 
419         /**
420          * @return id.
421          */
422         public final String getId()
423         {
424             return this.id;
425         }
426 
427         /**
428          * @return route generator.
429          */
430         public final LaneBasedRouteGenerator getRouteGenerator()
431         {
432             return this.routeGenerator;
433         }
434 
435         /**
436          * @return gtuType.
437          */
438         public final GTUType getGtuType()
439         {
440             return this.gtuType;
441         }
442 
443         /**
444          * @return initialLongitudinalPositions.
445          */
446         public final Map<Lane, Length.Rel> getInitialLongitudinalPositions()
447         {
448             return this.initialLongitudinalPositions;
449         }
450 
451         /**
452          * @return initialSpeed.
453          */
454         public final Speed.Abs getInitialSpeed()
455         {
456             return this.initialSpeed;
457         }
458 
459         /**
460          * @return gtuFollowingModel.
461          */
462         public final GTUFollowingModel getGtuFollowingModel()
463         {
464             return this.gtuFollowingModel;
465         }
466 
467         /**
468          * @return laneChangeModel.
469          */
470         public final LaneChangeModel getLaneChangeModel()
471         {
472             return this.laneChangeModel;
473         }
474 
475         /**
476          * @return length.
477          */
478         public final Length.Rel getLength()
479         {
480             return this.length;
481         }
482 
483         /**
484          * @return width.
485          */
486         public final Length.Rel getWidth()
487         {
488             return this.width;
489         }
490 
491         /**
492          * @return maximumVelocity.
493          */
494         public final Speed.Abs getMaximumVelocity()
495         {
496             return this.maximumVelocity;
497         }
498 
499         /**
500          * @return simulator.
501          */
502         public final OTSDEVSSimulatorInterface getSimulator()
503         {
504             return this.simulator;
505         }
506 
507         /**
508          * @return animationClass.
509          */
510         public final Class<? extends Renderable2D> getAnimationClass()
511         {
512             return this.animationClass;
513         }
514 
515         /**
516          * @return gtuColorer.
517          */
518         public final GTUColorer getGtuColorer()
519         {
520             return this.gtuColorer;
521         }
522 
523         /**
524          * @param gtuColorer set gtuColorer.
525          */
526         public final void setGtuColorer(final GTUColorer gtuColorer)
527         {
528             this.gtuColorer = gtuColorer;
529         }
530 
531         /**
532          * Build one LaneBasedIndividualCar.
533          * @return the built Car with the set properties
534          * @throws Exception when not all required values have been set
535          */
536         public final LaneBasedIndividualCar build() throws Exception
537         {
538             if (null == this.id || null == this.gtuType || null == this.gtuFollowingModel
539                 || null == this.laneChangeModel || null == this.initialLongitudinalPositions
540                 || null == this.initialSpeed || null == this.length || null == this.width
541                 || null == this.maximumVelocity || null == this.routeGenerator || null == this.simulator)
542             {
543                 // TODO Should throw a more specific Exception type
544                 throw new GTUException("factory settings incomplete");
545             }
546             LaneBasedIndividualCar gtu =
547                 new LaneBasedIndividualCar(this.id, this.gtuType, this.gtuFollowingModel, this.laneChangeModel,
548                     this.initialLongitudinalPositions, this.initialSpeed, this.length, this.width,
549                     this.maximumVelocity, this.routeGenerator.generateRouteNavigator(), this.simulator,
550                     this.animationClass, this.gtuColorer);
551             // System.out.println("Generated GTU " + gtu + " at t=" + this.simulator.getSimulatorTime());
552             return gtu;
553 
554         }
555 
556     }
557 
558 }