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