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