View Javadoc
1   package org.opentrafficsim.road.gtu.generator;
2   
3   import java.io.Serializable;
4   import java.rmi.RemoteException;
5   import java.util.ArrayList;
6   import java.util.HashMap;
7   import java.util.LinkedHashSet;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Set;
11  
12  import javax.media.j3d.BoundingBox;
13  import javax.media.j3d.Bounds;
14  import javax.vecmath.Point3d;
15  
16  import org.djunits.unit.DurationUnit;
17  import org.djunits.unit.LengthUnit;
18  import org.djunits.unit.SpeedUnit;
19  import org.djunits.value.vdouble.scalar.Acceleration;
20  import org.djunits.value.vdouble.scalar.Duration;
21  import org.djunits.value.vdouble.scalar.Length;
22  import org.djunits.value.vdouble.scalar.Speed;
23  import org.djunits.value.vdouble.scalar.Time;
24  import org.opentrafficsim.core.distributions.Generator;
25  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
26  import org.opentrafficsim.core.geometry.OTSGeometryException;
27  import org.opentrafficsim.core.gtu.GTUDirectionality;
28  import org.opentrafficsim.core.gtu.GTUException;
29  import org.opentrafficsim.core.gtu.GTUType;
30  import org.opentrafficsim.core.gtu.RelativePosition;
31  import org.opentrafficsim.core.network.Network;
32  import org.opentrafficsim.core.network.NetworkException;
33  import org.opentrafficsim.core.network.route.Route;
34  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
35  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
36  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
37  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU.LaneBasedIndividualCarBuilder;
38  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
39  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayDistance;
40  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
41  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
42  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
43  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
44  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
45  import org.opentrafficsim.road.network.OTSRoadNetwork;
46  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
47  import org.opentrafficsim.road.network.lane.Lane;
48  
49  import nl.tudelft.simulation.dsol.SimRuntimeException;
50  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
51  import nl.tudelft.simulation.event.EventProducer;
52  import nl.tudelft.simulation.language.d3.DirectedPoint;
53  
54  /**
55   * Common code for LaneBasedGTU generators that may have to postpone putting a GTU on the road due to congestion growing into
56   * the generator. <br>
57   * Generally, these generators will discover that there is not enough room AFTER having decided what kind (particular length) of
58   * GTU will be constructed next. When this happens, the generator must remember the properties of the GTU, but postpone actual
59   * generation until there is enough room.
60   * <p>
61   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
62   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
63   * <p>
64   * @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
65   *          initial version Feb 2, 2015 <br>
66   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
67   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
68   */
69  public abstract class AbstractGTUGeneratorOld extends EventProducer implements Serializable, GtuGeneratorQueue
70  {
71      /** */
72      private static final long serialVersionUID = 20150202L;
73  
74      /** The generator name. Will be used for generated GTUs as Name:# where # is the id of the GTU when ID is a String. */
75      private final String name;
76  
77      /** The type of GTU to generate. */
78      private final GTUType gtuType;
79  
80      /** The GTU class to instantiate. */
81      private final Class<?> gtuClass;
82  
83      /** Distribution of the initial speed of the GTU. */
84      private final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist;
85  
86      /** Distribution of the interarrival time. */
87      private final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist;
88  
89      /** Generated number of GTUs. */
90      private long generatedGTUs = 0;
91  
92      /** Maximum number of GTUs to generate. */
93      private final long maxGTUs;
94  
95      /** Start time of generation (delayed start). */
96      private final Time startTime;
97  
98      /** End time of generation. */
99      private final Time endTime;
100 
101     /** Lane to generate the GTU on -- at the end for now. */
102     private final Lane lane;
103 
104     /** Position on the lane, relative to the design line of the link. */
105     private final Length position;
106 
107     /** The direction in which the GTU has to be generated; DIR_PLUS or DIR_MINUS. */
108     private final GTUDirectionality direction;
109 
110     /** The lane-based strategical planner factory to use. */
111     private final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory;
112 
113     /** Route generator. */
114     private final Generator<Route> routeGenerator;
115 
116     /** The network. */
117     private final OTSRoadNetwork network;
118 
119     /** Car builder list. */
120     private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();
121 
122     /** Number of generated GTUs. */
123     @SuppressWarnings("checkstyle:visibilitymodifier")
124     protected long numberGTUs = 0;
125 
126     /** Bounds for animation. */
127     private final Bounds bounds;
128 
129     /**
130      * @param name String; the name of the generator
131      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator to schedule the start of the generation
132      * @param gtuType GTUType; the type of GTU to generate
133      * @param gtuClass Class&lt;?&gt;; the GTU class to instantiate
134      * @param initialSpeedDist ContinuousDistDoubleScalar.Rel&lt;Speed,SpeedUnit&gt;; distribution of the initial speed of the
135      *            GTU
136      * @param interarrivelTimeDist ContinuousDistDoubleScalar.Rel&lt;Duration,DurationUnit&gt;; distribution of the interarrival
137      *            time
138      * @param maxGTUs long; maximum number of GTUs to generate
139      * @param startTime Time; start time of generation (delayed start)
140      * @param endTime Time; end time of generation
141      * @param lane Lane; the lane to generate the GTU on
142      * @param position Length; position on the lane, relative to the design line of the link
143      * @param direction GTUDirectionality; the direction on the lane in which the GTU has to be generated (DIR_PLUS, or
144      *            DIR_MINUS)
145      * @param strategicalPlannerFactory LaneBasedStrategicalPlannerFactory&lt;? extends LaneBasedStrategicalPlanner&gt;; the
146      *            lane-based strategical planner factory to use
147      * @param routeGenerator Generator&lt;Route&gt;; route generator
148      * @param network OTSRoadNetwork; the network to register the generated GTUs into
149      * @throws SimRuntimeException when simulation scheduling fails
150      */
151     @SuppressWarnings("checkstyle:parameternumber")
152     public AbstractGTUGeneratorOld(final String name, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
153             final GTUType gtuType, final Class<?> gtuClass,
154             final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist,
155             final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist, final long maxGTUs,
156             final Time startTime, final Time endTime, final Lane lane, final Length position, final GTUDirectionality direction,
157             final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory,
158             final Generator<Route> routeGenerator, final OTSRoadNetwork network) throws SimRuntimeException
159     {
160         super();
161         this.name = name;
162         this.gtuType = gtuType;
163         this.gtuClass = gtuClass;
164         this.initialSpeedDist = initialSpeedDist;
165         this.interarrivelTimeDist = interarrivelTimeDist;
166         this.maxGTUs = maxGTUs;
167         this.startTime = startTime;
168         this.endTime = endTime;
169         this.lane = lane;
170         this.position = position;
171         this.direction = direction;
172         this.strategicalPlannerFactory = strategicalPlannerFactory;
173         this.routeGenerator = routeGenerator;
174         this.network = network;
175         DirectedPoint p;
176         try
177         {
178             p = this.getLocation();
179             this.bounds = new BoundingBox(new Point3d(p.x - 1, p.y - 1, 0.0), new Point3d(p.x + 1, p.y + 1, 0.0));
180         }
181         catch (RemoteException exception)
182         {
183             throw new RuntimeException("Bounds for generator cannot be determined.");
184         }
185         simulator.scheduleEventAbs(startTime, this, this, "generate", null);
186 
187         // notify the potential animation of the existence of a GTUGenerator
188         fireEvent(Network.GENERATOR_ADD_EVENT, name);
189         fireEvent(Network.ANIMATION_GENERATOR_ADD_EVENT, this);
190     }
191 
192     /**
193      * Generate a GTU.
194      * @throws Exception when something in the generation fails.
195      */
196     protected final void generate() throws Exception
197     {
198         // check if we are after the end time
199         if (getSimulator().getSimulatorTime().gt(this.endTime))
200         {
201             return;
202         }
203 
204         // check if we have generated sufficient GTUs
205         if (this.generatedGTUs >= this.maxGTUs)
206         {
207             return;
208         }
209 
210         // create a unique id
211         this.numberGTUs++;
212         String id = this.name + ":" + this.numberGTUs;
213 
214         // create the GTU
215         if (LaneBasedIndividualGTU.class.isAssignableFrom(getGtuClass()))
216         {
217             LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
218             carBuilder.setId(id);
219             carBuilder.setGtuType(getGtuType());
220             Length carLength = getLengthDist().draw();
221             carBuilder.setLength(carLength);
222             carBuilder.setFront(carLength.multiplyBy(0.75));
223             carBuilder.setWidth(getWidthDist().draw());
224             carBuilder.setMaximumSpeed(getMaximumSpeedDist().draw());
225             carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
226             carBuilder.setSimulator(getSimulator());
227             Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
228             initialLongitudinalPositions.add(new DirectedLanePosition(this.lane, this.position, this.direction));
229             carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
230             carBuilder.setNetwork(this.network);
231             carBuilder.setMaximumAcceleration(Acceleration.createSI(3.0));
232             carBuilder.setMaximumDeceleration(Acceleration.createSI(-8.0));
233             this.generatedGTUs++;
234 
235             if (enoughSpace(carBuilder))
236             {
237                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
238             }
239             else
240             {
241                 // put the car in the queue and take it from there -- if the headway is enough, build the car.
242                 this.carBuilderList.add(carBuilder);
243                 // System.out.println("GTUGenerator - backlog = " + this.carBuilderList.size());
244                 if (this.carBuilderList.size() == 1)
245                 {
246                     // first entry in list - start the watch thread
247                     getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList",
248                             null);
249                 }
250             }
251         }
252         else
253         {
254             throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
255         }
256 
257         // reschedule next arrival
258         Time nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
259         if (nextTime.le(this.endTime))
260         {
261             getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
262         }
263     }
264 
265     /**
266      * Check if the car to be built is not overlapping with another GTU on the same lane, and if it has enough headway to be
267      * generated safely.
268      * @param carBuilder LaneBasedIndividualCarBuilder; the car to be generated
269      * @return true if car can be safely built, false otherwise.
270      * @throws NetworkException when the speed limit of the lane is not known
271      * @throws GTUException if GTU does not have a position on the lane where it is registered
272      */
273     protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException, GTUException
274     {
275         DirectedLanePosition directedLanePosition = carBuilder.getInitialLongitudinalPositions().iterator().next();
276         Lane generatorLane = directedLanePosition.getLane();
277         double genPosSI = directedLanePosition.getPosition().getSI();
278         // GTUDirectionality direction = directedLanePosition.getGtuDirection();
279         // XXX different from this.direction?
280         double lengthSI = generatorLane.getLength().getSI();
281         double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
282         double rearNew = genPosSI / lengthSI;
283 
284         // test for overlap with other GTUs
285         for (LaneBasedGTU gtu : generatorLane.getGtuList())
286         {
287             double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
288             double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
289             if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
290                     || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
291             {
292                 // System.out.println(getSimulator().getSimulatorTime() + ", generator overlap with GTU " + gtu);
293                 return false;
294             }
295         }
296 
297         // test for sufficient headway
298         GTUFollowingModelOld followingModel = new IDMPlusOld();
299         // carBuilder.getStrategicalPlanner().getBehavioralCharacteristics().getGTUFollowingModel();
300 
301         Headway headway = headway(new Length(250.0, LengthUnit.METER), generatorLane);
302         Length minimumHeadway = new Length(0.0, LengthUnit.METER);
303         if (headway.getObjectType().isGtu())
304         {
305             minimumHeadway = followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headway.getSpeed(),
306                     new Length(1.0, LengthUnit.CENTIMETER), new Length(250.0, LengthUnit.METER),
307                     generatorLane.getSpeedLimit(carBuilder.getGtuType()), carBuilder.getMaximumSpeed());
308             // WS: changed mininumHeadway to headway.getDistance()
309             double acc = followingModel.computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumSpeed(),
310                     headway.getSpeed(), headway.getDistance(), carBuilder.getMaximumSpeed()).getSI();
311             if (acc < 0)
312             {
313                 // System.err.println(getSimulator().getSimulatorTime() + ", generator headway for GTU " + headway.getId()
314                 // + ", distance " + headway.getDistance().si + " m, max " + minimumHeadway + ", has to brake with a="
315                 // + acc + " m/s^2");
316                 return false;
317             }
318         }
319 
320         // System.out.println(getSimulator().getSimulatorTime() + ", generator headway for GTU " + headwayGTU.getOtherGTU()
321         // + ", distance " + headwayGTU.getDistance().si + " m, max " + minimumHeadway);
322         return headway.getDistance().ge(minimumHeadway);
323     }
324 
325     /**
326      * Calculate the minimum headway, possibly on subsequent lanes, in DIR_PLUS direction.
327      * @param theLane Lane; the lane where we are looking right now
328      * @param lanePositionSI double; from which position on this lane do we start measuring? This is the current position of the
329      *            GTU when we measure in the lane where the original GTU is positioned, and 0.0 for each subsequent lane
330      * @param cumDistanceSI double; the distance we have already covered searching on previous lanes
331      * @param maxDistanceSI the maximum distance to look for in SI units; stays the same in subsequent calls
332      * @param when Time; the current or future time for which to calculate the headway
333      * @return the headway in SI units when we have found the GTU, or a null GTU with a distance of Double.MAX_VALUE meters when
334      *         no other GTU could not be found within maxDistanceSI meters
335      * @throws GTUException when there is a problem with the geometry of the network
336      */
337     private Headway headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
338             final double maxDistanceSI, final Time when) throws GTUException
339     {
340         // TODO: THIS METHOD IS ALSO IN PERCEPTION -- DON'T DUPLICATE; ALSO, THIS VERSION IS WRONG.
341         LaneBasedGTU otherGTU = theLane.getGtuAhead(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
342                 RelativePosition.REAR, when);
343         if (otherGTU != null)
344         {
345             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
346             if (distanceM > 0 && distanceM <= maxDistanceSI)
347             {
348                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
349                         otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
350             }
351             return new HeadwayDistance(Double.MAX_VALUE);
352         }
353 
354         // Continue search on successor lanes.
355         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
356         {
357             // is there a successor link?
358             if (theLane.nextLanes(this.gtuType).size() > 0)
359             {
360                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
361                 for (Lane nextLane : theLane.nextLanes(this.gtuType).keySet())
362                 {
363                     // TODO Only follow links on the Route if there is a "real" Route
364                     // if (routeNavigator.getRoute() == null || routeNavigator.getRoute().size() == 0 /* XXXXX STUB dummy route
365                     // */
366                     // || routeNavigator.getRoute().containsLink((Link) theLane.getParentLink()))
367                     {
368                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
369                         Headway closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
370                         if (closest.getDistance().si < maxDistanceSI
371                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
372                         {
373                             foundMaxGTUDistanceSI = closest;
374                         }
375                     }
376                 }
377                 return foundMaxGTUDistanceSI;
378             }
379         }
380 
381         // No other GTU was not on one of the current lanes or their successors.
382         return new HeadwayDistance(Double.MAX_VALUE);
383     }
384 
385     /**
386      * Calculate the minimum headway, possibly on subsequent lanes, in DIR_MINUS direction.
387      * @param theLane Lane; the lane where we are looking right now
388      * @param lanePositionSI double; from which position on this lane do we start measuring? This is the current position of the
389      *            GTU when we measure in the lane where the original GTU is positioned, and 0.0 for each subsequent lane
390      * @param cumDistanceSI double; the distance we have already covered searching on previous lanes
391      * @param maxDistanceSI the maximum distance to look for in SI units; stays the same in subsequent calls
392      * @param when Time; the current or future time for which to calculate the headway
393      * @return the headway in SI units when we have found the GTU, or a null GTU with a distance of Double.MAX_VALUE meters when
394      *         no other GTU could not be found within maxDistanceSI meters
395      * @throws GTUException when there is a problem with the geometry of the network
396      */
397     private Headway headwayRecursiveBackwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
398             final double maxDistanceSI, final Time when) throws GTUException
399     {
400         // TODO: THIS METHOD IS ALSO IN PERCEPTION -- DON'T DUPLICATE; ALSO, THIS VERSION IS WRONG.
401         LaneBasedGTU otherGTU = theLane.getGtuBehind(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
402                 RelativePosition.FRONT, when);
403         if (otherGTU != null)
404         {
405             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getFront(), when).getSI() - lanePositionSI;
406             if (distanceM > 0 && distanceM <= maxDistanceSI)
407             {
408                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
409                         otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
410             }
411             return new HeadwayDistance(Double.MAX_VALUE);
412         }
413 
414         // Continue search on all predecessor lanes.
415         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
416         {
417             // is there a predecessor link?
418             if (theLane.prevLanes(this.gtuType).size() > 0)
419             {
420                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
421                 for (Lane prevLane : theLane.prevLanes(this.gtuType).keySet())
422                 {
423                     // TODO Only follow links on the Route if there is a "real" Route
424                     // if (routeNavigator.getRoute() == null || routeNavigator.getRoute().size() == 0 /* XXXXX STUB dummy route
425                     // */
426                     // || routeNavigator.getRoute().containsLink((Link) theLane.getParentLink()))
427                     {
428                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
429                         Headway closest = headwayRecursiveBackwardSI(prevLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
430                         if (closest.getDistance().si < maxDistanceSI
431                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
432                         {
433                             foundMaxGTUDistanceSI = closest;
434                         }
435                     }
436                 }
437                 return foundMaxGTUDistanceSI;
438             }
439         }
440 
441         // No other GTU was not on one of the current lanes or their successors.
442         return new HeadwayDistance(Double.MAX_VALUE);
443     }
444 
445     /**
446      * Find the first GTU starting on the specified lane following the specified route.
447      * @param maxDistanceSI double; the maximum distance to look for in SI units
448      * @param generatorLane Lane; the lane on which the the search for a leader starts
449      * @return the nearest GTU and the net headway to this GTU in SI units when we have found the GTU, or a null GTU with a
450      *         distance of Double.MAX_VALUE meters when no other GTU could not be found within maxDistanceSI meters
451      * @throws GTUException when there is a problem with the geometry of the network
452      */
453     private Headway headwayGTUSIForward(final double maxDistanceSI, final Lane generatorLane) throws GTUException
454     {
455         Time when = getSimulator().getSimulatorTime();
456         Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
457         // search for the closest GTU on all current lanes we are registered on.
458         Headway closest;
459         if (this.direction.equals(GTUDirectionality.DIR_PLUS))
460         {
461             closest = headwayRecursiveForwardSI(this.lane, 0.0, 0.0, maxDistanceSI, when);
462         }
463         else
464         {
465             closest = headwayRecursiveBackwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when);
466         }
467         if (closest.getDistance().si < maxDistanceSI && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
468         {
469             foundMaxGTUDistanceSI = closest;
470         }
471         return foundMaxGTUDistanceSI;
472     }
473 
474     /**
475      * Check the available headway for GTU that is about to be constructed.
476      * @param maxDistance Length; the maximum distance to look for a leader
477      * @param generatorLane Lane; the lane on which the GTU is generated
478      * @return HeadwayGTU; the available headway and the GTU at that headway
479      * @throws GTUException on network inconsistency
480      */
481     public final Headway headway(final Length maxDistance, final Lane generatorLane) throws GTUException
482     {
483         return headwayGTUSIForward(maxDistance.getSI(), generatorLane);
484     }
485 
486     /**
487      * Check if car can be generated.
488      * @throws Exception on any problem
489      */
490     protected final void checkCarBuilderList() throws Exception
491     {
492         if (!this.carBuilderList.isEmpty())
493         {
494             LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
495             if (enoughSpace(carBuilder))
496             {
497                 this.carBuilderList.remove(0);
498                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
499             }
500         }
501 
502         // only reschedule if list not empty
503         if (!this.carBuilderList.isEmpty())
504         {
505             getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList", null);
506         }
507     }
508 
509     /** @return simulator. */
510     public abstract OTSSimulatorInterface getSimulator();
511 
512     /** @return lengthDist. */
513     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getLengthDist();
514 
515     /** @return widthDist. */
516     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getWidthDist();
517 
518     /** @return maximumSpeedDist. */
519     public abstract ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getMaximumSpeedDist();
520 
521     /**
522      * @return name.
523      */
524     public final String getName()
525     {
526         return this.name;
527     }
528 
529     /**
530      * @return gtuType.
531      */
532     public final GTUType getGtuType()
533     {
534         return this.gtuType;
535     }
536 
537     /**
538      * @return gtuClass.
539      */
540     public final Class<?> getGtuClass()
541     {
542         return this.gtuClass;
543     }
544 
545     /**
546      * @return initialSpeedDist.
547      */
548     public final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getInitialSpeedDist()
549     {
550         return this.initialSpeedDist;
551     }
552 
553     /**
554      * @return interarrivelTimeDist.
555      */
556     public final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> getInterarrivelTimeDist()
557     {
558         return this.interarrivelTimeDist;
559     }
560 
561     /**
562      * @return maxGTUs.
563      */
564     public final long getMaxGTUs()
565     {
566         return this.maxGTUs;
567     }
568 
569     /**
570      * @return startTime.
571      */
572     public final Time getStartTime()
573     {
574         return this.startTime;
575     }
576 
577     /**
578      * @return endTime.
579      */
580     public final Time getEndTime()
581     {
582         return this.endTime;
583     }
584 
585     /**
586      * @return strategicalPlanner
587      */
588     public final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> getStrategicalPlannerFactory()
589     {
590         return this.strategicalPlannerFactory;
591     }
592 
593     /** {@inheritDoc} */
594     @Override
595     public DirectedPoint getLocation() throws RemoteException
596     {
597         try
598         {
599             return this.lane.getCenterLine().getLocation(this.position);
600         }
601         catch (OTSGeometryException exception)
602         {
603             return this.lane.getLocation();
604         }
605     }
606 
607     /** {@inheritDoc} */
608     @Override
609     public Bounds getBounds() throws RemoteException
610     {
611         return this.bounds;
612     }
613 
614     /** {@inheritDoc} */
615     @Override
616     public Map<DirectedPoint, Integer> getQueueLengths()
617     {
618         Map<DirectedPoint, Integer> map = new HashMap<>();
619         try
620         {
621             map.put(getLocation(), this.carBuilderList.size());
622         }
623         catch (RemoteException exception)
624         {
625             throw new RuntimeException("Locartion for generator queue cannot be determined.");
626         }
627         return map;
628     }
629 
630 }