AbstractGTUGeneratorOld.java

  1. package org.opentrafficsim.road.gtu.generator;

  2. import java.io.Serializable;
  3. import java.rmi.RemoteException;
  4. import java.util.ArrayList;
  5. import java.util.LinkedHashMap;
  6. import java.util.LinkedHashSet;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;

  10. import javax.media.j3d.BoundingBox;
  11. import javax.media.j3d.Bounds;
  12. import javax.vecmath.Point3d;

  13. import org.djunits.unit.DurationUnit;
  14. import org.djunits.unit.LengthUnit;
  15. import org.djunits.unit.SpeedUnit;
  16. import org.djunits.value.vdouble.scalar.Acceleration;
  17. import org.djunits.value.vdouble.scalar.Duration;
  18. import org.djunits.value.vdouble.scalar.Length;
  19. import org.djunits.value.vdouble.scalar.Speed;
  20. import org.djunits.value.vdouble.scalar.Time;
  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.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.network.Network;
  30. import org.opentrafficsim.core.network.NetworkException;
  31. import org.opentrafficsim.core.network.route.Route;
  32. import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
  33. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  34. import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
  35. import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU.LaneBasedIndividualCarBuilder;
  36. import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
  37. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayDistance;
  38. import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
  39. import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
  40. import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
  41. import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
  42. import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
  43. import org.opentrafficsim.road.network.OTSRoadNetwork;
  44. import org.opentrafficsim.road.network.lane.DirectedLanePosition;
  45. import org.opentrafficsim.road.network.lane.Lane;

  46. import nl.tudelft.simulation.dsol.SimRuntimeException;
  47. import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
  48. import nl.tudelft.simulation.language.d3.DirectedPoint;

  49. /**
  50.  * Common code for LaneBasedGTU generators that may have to postpone putting a GTU on the road due to congestion growing into
  51.  * the generator. <br>
  52.  * Generally, these generators will discover that there is not enough room AFTER having decided what kind (particular length) of
  53.  * GTU will be constructed next. When this happens, the generator must remember the properties of the GTU, but postpone actual
  54.  * generation until there is enough room.
  55.  * <p>
  56.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  57.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  58.  * <p>
  59.  * @version $Revision: 1401 $, $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, by $Author: averbraeck $,
  60.  *          initial version Feb 2, 2015 <br>
  61.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  62.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  63.  */
  64. public abstract class AbstractGTUGeneratorOld extends EventProducer implements Serializable, GtuGeneratorQueue
  65. {
  66.     /** */
  67.     private static final long serialVersionUID = 20150202L;

  68.     /** The generator name. Will be used for generated GTUs as Name:# where # is the id of the GTU when ID is a String. */
  69.     private final String name;

  70.     /** The type of GTU to generate. */
  71.     private final GTUType gtuType;

  72.     /** The GTU class to instantiate. */
  73.     private final Class<?> gtuClass;

  74.     /** Distribution of the initial speed of the GTU. */
  75.     private final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist;

  76.     /** Distribution of the interarrival time. */
  77.     private final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist;

  78.     /** Generated number of GTUs. */
  79.     private long generatedGTUs = 0;

  80.     /** Maximum number of GTUs to generate. */
  81.     private final long maxGTUs;

  82.     /** Start time of generation (delayed start). */
  83.     private final Time startTime;

  84.     /** End time of generation. */
  85.     private final Time endTime;

  86.     /** Lane to generate the GTU on -- at the end for now. */
  87.     private final Lane lane;

  88.     /** Position on the lane, relative to the design line of the link. */
  89.     private final Length position;

  90.     /** The direction in which the GTU has to be generated; DIR_PLUS or DIR_MINUS. */
  91.     private final GTUDirectionality direction;

  92.     /** The lane-based strategical planner factory to use. */
  93.     private final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory;

  94.     /** Route generator. */
  95.     private final Generator<Route> routeGenerator;

  96.     /** The network. */
  97.     private final OTSRoadNetwork network;

  98.     /** Car builder list. */
  99.     private List<LaneBasedIndividualCarBuilder> carBuilderList = new ArrayList<>();

  100.     /** Number of generated GTUs. */
  101.     @SuppressWarnings("checkstyle:visibilitymodifier")
  102.     protected long numberGTUs = 0;

  103.     /** Bounds for animation. */
  104.     private final Bounds bounds;

  105.     /**
  106.      * @param name String; the name of the generator
  107.      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator to schedule the start of the generation
  108.      * @param gtuType GTUType; the type of GTU to generate
  109.      * @param gtuClass Class&lt;?&gt;; the GTU class to instantiate
  110.      * @param initialSpeedDist ContinuousDistDoubleScalar.Rel&lt;Speed,SpeedUnit&gt;; distribution of the initial speed of the
  111.      *            GTU
  112.      * @param interarrivelTimeDist ContinuousDistDoubleScalar.Rel&lt;Duration,DurationUnit&gt;; distribution of the interarrival
  113.      *            time
  114.      * @param maxGTUs long; maximum number of GTUs to generate
  115.      * @param startTime Time; start time of generation (delayed start)
  116.      * @param endTime Time; end time of generation
  117.      * @param lane Lane; the lane to generate the GTU on
  118.      * @param position Length; position on the lane, relative to the design line of the link
  119.      * @param direction GTUDirectionality; the direction on the lane in which the GTU has to be generated (DIR_PLUS, or
  120.      *            DIR_MINUS)
  121.      * @param strategicalPlannerFactory LaneBasedStrategicalPlannerFactory&lt;? extends LaneBasedStrategicalPlanner&gt;; the
  122.      *            lane-based strategical planner factory to use
  123.      * @param routeGenerator Generator&lt;Route&gt;; route generator
  124.      * @param network OTSRoadNetwork; the network to register the generated GTUs into
  125.      * @throws SimRuntimeException when simulation scheduling fails
  126.      */
  127.     @SuppressWarnings("checkstyle:parameternumber")
  128.     public AbstractGTUGeneratorOld(final String name, final DEVSSimulatorInterface.TimeDoubleUnit simulator,
  129.             final GTUType gtuType, final Class<?> gtuClass,
  130.             final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> initialSpeedDist,
  131.             final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> interarrivelTimeDist, final long maxGTUs,
  132.             final Time startTime, final Time endTime, final Lane lane, final Length position, final GTUDirectionality direction,
  133.             final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> strategicalPlannerFactory,
  134.             final Generator<Route> routeGenerator, final OTSRoadNetwork network) throws SimRuntimeException
  135.     {
  136.         super();
  137.         this.name = name;
  138.         this.gtuType = gtuType;
  139.         this.gtuClass = gtuClass;
  140.         this.initialSpeedDist = initialSpeedDist;
  141.         this.interarrivelTimeDist = interarrivelTimeDist;
  142.         this.maxGTUs = maxGTUs;
  143.         this.startTime = startTime;
  144.         this.endTime = endTime;
  145.         this.lane = lane;
  146.         this.position = position;
  147.         this.direction = direction;
  148.         this.strategicalPlannerFactory = strategicalPlannerFactory;
  149.         this.routeGenerator = routeGenerator;
  150.         this.network = network;
  151.         DirectedPoint p;
  152.         try
  153.         {
  154.             p = this.getLocation();
  155.             this.bounds = new BoundingBox(new Point3d(p.x - 1, p.y - 1, 0.0), new Point3d(p.x + 1, p.y + 1, 0.0));
  156.         }
  157.         catch (RemoteException exception)
  158.         {
  159.             throw new RuntimeException("Bounds for generator cannot be determined.");
  160.         }
  161.         simulator.scheduleEventAbs(startTime, this, this, "generate", null);

  162.         // notify the potential animation of the existence of a GTUGenerator
  163.         fireEvent(Network.GENERATOR_ADD_EVENT, name);
  164.         fireEvent(Network.ANIMATION_GENERATOR_ADD_EVENT, this);
  165.     }

  166.     /**
  167.      * Generate a GTU.
  168.      * @throws Exception when something in the generation fails.
  169.      */
  170.     protected final void generate() throws Exception
  171.     {
  172.         // check if we are after the end time
  173.         if (getSimulator().getSimulatorTime().gt(this.endTime))
  174.         {
  175.             return;
  176.         }

  177.         // check if we have generated sufficient GTUs
  178.         if (this.generatedGTUs >= this.maxGTUs)
  179.         {
  180.             return;
  181.         }

  182.         // create a unique id
  183.         this.numberGTUs++;
  184.         String id = this.name + ":" + this.numberGTUs;

  185.         // create the GTU
  186.         if (LaneBasedIndividualGTU.class.isAssignableFrom(getGtuClass()))
  187.         {
  188.             LaneBasedIndividualCarBuilder carBuilder = new LaneBasedIndividualCarBuilder();
  189.             carBuilder.setId(id);
  190.             carBuilder.setGtuType(getGtuType());
  191.             Length carLength = getLengthDist().draw();
  192.             carBuilder.setLength(carLength);
  193.             carBuilder.setFront(carLength.times(0.75));
  194.             carBuilder.setWidth(getWidthDist().draw());
  195.             carBuilder.setMaximumSpeed(getMaximumSpeedDist().draw());
  196.             carBuilder.setInitialSpeed(getInitialSpeedDist().draw());
  197.             carBuilder.setSimulator(getSimulator());
  198.             Set<DirectedLanePosition> initialLongitudinalPositions = new LinkedHashSet<>(1);
  199.             initialLongitudinalPositions.add(new DirectedLanePosition(this.lane, this.position, this.direction));
  200.             carBuilder.setInitialLongitudinalPositions(initialLongitudinalPositions);
  201.             carBuilder.setNetwork(this.network);
  202.             carBuilder.setMaximumAcceleration(Acceleration.instantiateSI(3.0));
  203.             carBuilder.setMaximumDeceleration(Acceleration.instantiateSI(-8.0));
  204.             this.generatedGTUs++;

  205.             if (enoughSpace(carBuilder))
  206.             {
  207.                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
  208.             }
  209.             else
  210.             {
  211.                 // put the car in the queue and take it from there -- if the headway is enough, build the car.
  212.                 this.carBuilderList.add(carBuilder);
  213.                 // System.out.println("GTUGenerator - backlog = " + this.carBuilderList.size());
  214.                 if (this.carBuilderList.size() == 1)
  215.                 {
  216.                     // first entry in list - start the watch thread
  217.                     getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList",
  218.                             null);
  219.                 }
  220.             }
  221.         }
  222.         else
  223.         {
  224.             throw new GTUException("GTU class " + getGtuClass().getName() + ": cannot instantiate, no builder.");
  225.         }

  226.         // reschedule next arrival
  227.         Time nextTime = getSimulator().getSimulatorTime().plus(this.interarrivelTimeDist.draw());
  228.         if (nextTime.le(this.endTime))
  229.         {
  230.             getSimulator().scheduleEventAbs(nextTime, this, this, "generate", null);
  231.         }
  232.     }

  233.     /**
  234.      * 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
  235.      * generated safely.
  236.      * @param carBuilder LaneBasedIndividualCarBuilder; the car to be generated
  237.      * @return true if car can be safely built, false otherwise.
  238.      * @throws NetworkException when the speed limit of the lane is not known
  239.      * @throws GTUException if GTU does not have a position on the lane where it is registered
  240.      */
  241.     protected final boolean enoughSpace(final LaneBasedIndividualCarBuilder carBuilder) throws NetworkException, GTUException
  242.     {
  243.         DirectedLanePosition directedLanePosition = carBuilder.getInitialLongitudinalPositions().iterator().next();
  244.         Lane generatorLane = directedLanePosition.getLane();
  245.         double genPosSI = directedLanePosition.getPosition().getSI();
  246.         // GTUDirectionality direction = directedLanePosition.getGtuDirection();
  247.         // XXX different from this.direction?
  248.         double lengthSI = generatorLane.getLength().getSI();
  249.         double frontNew = (genPosSI + carBuilder.getLength().getSI()) / lengthSI;
  250.         double rearNew = genPosSI / lengthSI;

  251.         // test for overlap with other GTUs
  252.         for (LaneBasedGTU gtu : generatorLane.getGtuList())
  253.         {
  254.             double frontGTU = gtu.fractionalPosition(generatorLane, gtu.getFront());
  255.             double rearGTU = gtu.fractionalPosition(generatorLane, gtu.getRear());
  256.             if ((frontNew >= rearGTU && frontNew <= frontGTU) || (rearNew >= rearGTU && rearNew <= frontGTU)
  257.                     || (frontGTU >= rearNew && frontGTU <= frontNew) || (rearGTU >= rearNew && rearGTU <= frontNew))
  258.             {
  259.                 // System.out.println(getSimulator().getSimulatorTime() + ", generator overlap with GTU " + gtu);
  260.                 return false;
  261.             }
  262.         }

  263.         // test for sufficient headway
  264.         GTUFollowingModelOld followingModel = new IDMPlusOld();
  265.         // carBuilder.getStrategicalPlanner().getBehavioralCharacteristics().getGTUFollowingModel();

  266.         Headway headway = headway(new Length(250.0, LengthUnit.METER), generatorLane);
  267.         Length minimumHeadway = new Length(0.0, LengthUnit.METER);
  268.         if (headway.getObjectType().isGtu())
  269.         {
  270.             minimumHeadway = followingModel.minimumHeadway(carBuilder.getInitialSpeed(), headway.getSpeed(),
  271.                     new Length(1.0, LengthUnit.CENTIMETER), new Length(250.0, LengthUnit.METER),
  272.                     generatorLane.getSpeedLimit(carBuilder.getGtuType()), carBuilder.getMaximumSpeed());
  273.             // WS: changed mininumHeadway to headway.getDistance()
  274.             double acc = followingModel.computeAcceleration(carBuilder.getInitialSpeed(), carBuilder.getMaximumSpeed(),
  275.                     headway.getSpeed(), headway.getDistance(), carBuilder.getMaximumSpeed()).getSI();
  276.             if (acc < 0)
  277.             {
  278.                 // System.err.println(getSimulator().getSimulatorTime() + ", generator headway for GTU " + headway.getId()
  279.                 // + ", distance " + headway.getDistance().si + " m, max " + minimumHeadway + ", has to brake with a="
  280.                 // + acc + " m/s^2");
  281.                 return false;
  282.             }
  283.         }

  284.         // System.out.println(getSimulator().getSimulatorTime() + ", generator headway for GTU " + headwayGTU.getOtherGTU()
  285.         // + ", distance " + headwayGTU.getDistance().si + " m, max " + minimumHeadway);
  286.         return headway.getDistance().ge(minimumHeadway);
  287.     }

  288.     /**
  289.      * Calculate the minimum headway, possibly on subsequent lanes, in DIR_PLUS direction.
  290.      * @param theLane Lane; the lane where we are looking right now
  291.      * @param lanePositionSI double; from which position on this lane do we start measuring? This is the current position of the
  292.      *            GTU when we measure in the lane where the original GTU is positioned, and 0.0 for each subsequent lane
  293.      * @param cumDistanceSI double; the distance we have already covered searching on previous lanes
  294.      * @param maxDistanceSI the maximum distance to look for in SI units; stays the same in subsequent calls
  295.      * @param when Time; the current or future time for which to calculate the headway
  296.      * @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
  297.      *         no other GTU could not be found within maxDistanceSI meters
  298.      * @throws GTUException when there is a problem with the geometry of the network
  299.      */
  300.     private Headway headwayRecursiveForwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
  301.             final double maxDistanceSI, final Time when) throws GTUException
  302.     {
  303.         // TODO: THIS METHOD IS ALSO IN PERCEPTION -- DON'T DUPLICATE; ALSO, THIS VERSION IS WRONG.
  304.         LaneBasedGTU otherGTU = theLane.getGtuAhead(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
  305.                 RelativePosition.REAR, when);
  306.         if (otherGTU != null)
  307.         {
  308.             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getRear(), when).getSI() - lanePositionSI;
  309.             if (distanceM > 0 && distanceM <= maxDistanceSI)
  310.             {
  311.                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
  312.                         otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
  313.             }
  314.             return new HeadwayDistance(Double.MAX_VALUE);
  315.         }

  316.         // Continue search on successor lanes.
  317.         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
  318.         {
  319.             // is there a successor link?
  320.             if (theLane.nextLanes(this.gtuType).size() > 0)
  321.             {
  322.                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
  323.                 for (Lane nextLane : theLane.nextLanes(this.gtuType).keySet())
  324.                 {
  325.                     // TODO Only follow links on the Route if there is a "real" Route
  326.                     // if (routeNavigator.getRoute() == null || routeNavigator.getRoute().size() == 0 /* XXXXX STUB dummy route
  327.                     // */
  328.                     // || routeNavigator.getRoute().containsLink((Link) theLane.getParentLink()))
  329.                     {
  330.                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
  331.                         Headway closest = headwayRecursiveForwardSI(nextLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
  332.                         if (closest.getDistance().si < maxDistanceSI
  333.                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
  334.                         {
  335.                             foundMaxGTUDistanceSI = closest;
  336.                         }
  337.                     }
  338.                 }
  339.                 return foundMaxGTUDistanceSI;
  340.             }
  341.         }

  342.         // No other GTU was not on one of the current lanes or their successors.
  343.         return new HeadwayDistance(Double.MAX_VALUE);
  344.     }

  345.     /**
  346.      * Calculate the minimum headway, possibly on subsequent lanes, in DIR_MINUS direction.
  347.      * @param theLane Lane; the lane where we are looking right now
  348.      * @param lanePositionSI double; from which position on this lane do we start measuring? This is the current position of the
  349.      *            GTU when we measure in the lane where the original GTU is positioned, and 0.0 for each subsequent lane
  350.      * @param cumDistanceSI double; the distance we have already covered searching on previous lanes
  351.      * @param maxDistanceSI the maximum distance to look for in SI units; stays the same in subsequent calls
  352.      * @param when Time; the current or future time for which to calculate the headway
  353.      * @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
  354.      *         no other GTU could not be found within maxDistanceSI meters
  355.      * @throws GTUException when there is a problem with the geometry of the network
  356.      */
  357.     private Headway headwayRecursiveBackwardSI(final Lane theLane, final double lanePositionSI, final double cumDistanceSI,
  358.             final double maxDistanceSI, final Time when) throws GTUException
  359.     {
  360.         // TODO: THIS METHOD IS ALSO IN PERCEPTION -- DON'T DUPLICATE; ALSO, THIS VERSION IS WRONG.
  361.         LaneBasedGTU otherGTU = theLane.getGtuBehind(new Length(lanePositionSI, LengthUnit.METER), GTUDirectionality.DIR_PLUS,
  362.                 RelativePosition.FRONT, when);
  363.         if (otherGTU != null)
  364.         {
  365.             double distanceM = cumDistanceSI + otherGTU.position(theLane, otherGTU.getFront(), when).getSI() - lanePositionSI;
  366.             if (distanceM > 0 && distanceM <= maxDistanceSI)
  367.             {
  368.                 return new HeadwayGTUSimple(otherGTU.getId(), otherGTU.getGTUType(), new Length(distanceM, LengthUnit.SI),
  369.                         otherGTU.getLength(), otherGTU.getWidth(), otherGTU.getSpeed(), otherGTU.getAcceleration(), null);
  370.             }
  371.             return new HeadwayDistance(Double.MAX_VALUE);
  372.         }

  373.         // Continue search on all predecessor lanes.
  374.         if (cumDistanceSI + theLane.getLength().getSI() - lanePositionSI < maxDistanceSI)
  375.         {
  376.             // is there a predecessor link?
  377.             if (theLane.prevLanes(this.gtuType).size() > 0)
  378.             {
  379.                 Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
  380.                 for (Lane prevLane : theLane.prevLanes(this.gtuType).keySet())
  381.                 {
  382.                     // TODO Only follow links on the Route if there is a "real" Route
  383.                     // if (routeNavigator.getRoute() == null || routeNavigator.getRoute().size() == 0 /* XXXXX STUB dummy route
  384.                     // */
  385.                     // || routeNavigator.getRoute().containsLink((Link) theLane.getParentLink()))
  386.                     {
  387.                         double traveledDistanceSI = cumDistanceSI + theLane.getLength().getSI() - lanePositionSI;
  388.                         Headway closest = headwayRecursiveBackwardSI(prevLane, 0.0, traveledDistanceSI, maxDistanceSI, when);
  389.                         if (closest.getDistance().si < maxDistanceSI
  390.                                 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
  391.                         {
  392.                             foundMaxGTUDistanceSI = closest;
  393.                         }
  394.                     }
  395.                 }
  396.                 return foundMaxGTUDistanceSI;
  397.             }
  398.         }

  399.         // No other GTU was not on one of the current lanes or their successors.
  400.         return new HeadwayDistance(Double.MAX_VALUE);
  401.     }

  402.     /**
  403.      * Find the first GTU starting on the specified lane following the specified route.
  404.      * @param maxDistanceSI double; the maximum distance to look for in SI units
  405.      * @param generatorLane Lane; the lane on which the the search for a leader starts
  406.      * @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
  407.      *         distance of Double.MAX_VALUE meters when no other GTU could not be found within maxDistanceSI meters
  408.      * @throws GTUException when there is a problem with the geometry of the network
  409.      */
  410.     private Headway headwayGTUSIForward(final double maxDistanceSI, final Lane generatorLane) throws GTUException
  411.     {
  412.         Time when = getSimulator().getSimulatorTime();
  413.         Headway foundMaxGTUDistanceSI = new HeadwayDistance(Double.MAX_VALUE);
  414.         // search for the closest GTU on all current lanes we are registered on.
  415.         Headway closest;
  416.         if (this.direction.equals(GTUDirectionality.DIR_PLUS))
  417.         {
  418.             closest = headwayRecursiveForwardSI(this.lane, 0.0, 0.0, maxDistanceSI, when);
  419.         }
  420.         else
  421.         {
  422.             closest = headwayRecursiveBackwardSI(this.lane, generatorLane.getLength().getSI(), 0.0, maxDistanceSI, when);
  423.         }
  424.         if (closest.getDistance().si < maxDistanceSI && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
  425.         {
  426.             foundMaxGTUDistanceSI = closest;
  427.         }
  428.         return foundMaxGTUDistanceSI;
  429.     }

  430.     /**
  431.      * Check the available headway for GTU that is about to be constructed.
  432.      * @param maxDistance Length; the maximum distance to look for a leader
  433.      * @param generatorLane Lane; the lane on which the GTU is generated
  434.      * @return HeadwayGTU; the available headway and the GTU at that headway
  435.      * @throws GTUException on network inconsistency
  436.      */
  437.     public final Headway headway(final Length maxDistance, final Lane generatorLane) throws GTUException
  438.     {
  439.         return headwayGTUSIForward(maxDistance.getSI(), generatorLane);
  440.     }

  441.     /**
  442.      * Check if car can be generated.
  443.      * @throws Exception on any problem
  444.      */
  445.     protected final void checkCarBuilderList() throws Exception
  446.     {
  447.         if (!this.carBuilderList.isEmpty())
  448.         {
  449.             LaneBasedIndividualCarBuilder carBuilder = this.carBuilderList.get(0);
  450.             if (enoughSpace(carBuilder))
  451.             {
  452.                 this.carBuilderList.remove(0);
  453.                 carBuilder.build(this.strategicalPlannerFactory, this.routeGenerator.draw(), null, null);
  454.             }
  455.         }

  456.         // only reschedule if list not empty
  457.         if (!this.carBuilderList.isEmpty())
  458.         {
  459.             getSimulator().scheduleEventRel(new Duration(0.1, DurationUnit.SECOND), this, this, "checkCarBuilderList", null);
  460.         }
  461.     }

  462.     /** @return simulator. */
  463.     public abstract OTSSimulatorInterface getSimulator();

  464.     /** @return lengthDist. */
  465.     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getLengthDist();

  466.     /** @return widthDist. */
  467.     public abstract ContinuousDistDoubleScalar.Rel<Length, LengthUnit> getWidthDist();

  468.     /** @return maximumSpeedDist. */
  469.     public abstract ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getMaximumSpeedDist();

  470.     /**
  471.      * @return name.
  472.      */
  473.     public final String getName()
  474.     {
  475.         return this.name;
  476.     }

  477.     /**
  478.      * @return gtuType.
  479.      */
  480.     public final GTUType getGtuType()
  481.     {
  482.         return this.gtuType;
  483.     }

  484.     /**
  485.      * @return gtuClass.
  486.      */
  487.     public final Class<?> getGtuClass()
  488.     {
  489.         return this.gtuClass;
  490.     }

  491.     /**
  492.      * @return initialSpeedDist.
  493.      */
  494.     public final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> getInitialSpeedDist()
  495.     {
  496.         return this.initialSpeedDist;
  497.     }

  498.     /**
  499.      * @return interarrivelTimeDist.
  500.      */
  501.     public final ContinuousDistDoubleScalar.Rel<Duration, DurationUnit> getInterarrivelTimeDist()
  502.     {
  503.         return this.interarrivelTimeDist;
  504.     }

  505.     /**
  506.      * @return maxGTUs.
  507.      */
  508.     public final long getMaxGTUs()
  509.     {
  510.         return this.maxGTUs;
  511.     }

  512.     /**
  513.      * @return startTime.
  514.      */
  515.     public final Time getStartTime()
  516.     {
  517.         return this.startTime;
  518.     }

  519.     /**
  520.      * @return endTime.
  521.      */
  522.     public final Time getEndTime()
  523.     {
  524.         return this.endTime;
  525.     }

  526.     /**
  527.      * @return strategicalPlanner
  528.      */
  529.     public final LaneBasedStrategicalPlannerFactory<? extends LaneBasedStrategicalPlanner> getStrategicalPlannerFactory()
  530.     {
  531.         return this.strategicalPlannerFactory;
  532.     }

  533.     /** {@inheritDoc} */
  534.     @Override
  535.     public DirectedPoint getLocation() throws RemoteException
  536.     {
  537.         try
  538.         {
  539.             return this.lane.getCenterLine().getLocation(this.position);
  540.         }
  541.         catch (OTSGeometryException exception)
  542.         {
  543.             return this.lane.getLocation();
  544.         }
  545.     }

  546.     /** {@inheritDoc} */
  547.     @Override
  548.     public Bounds getBounds() throws RemoteException
  549.     {
  550.         return this.bounds;
  551.     }

  552.     /** {@inheritDoc} */
  553.     @Override
  554.     public Map<DirectedPoint, Integer> getQueueLengths()
  555.     {
  556.         Map<DirectedPoint, Integer> map = new LinkedHashMap<>();
  557.         try
  558.         {
  559.             map.put(getLocation(), this.carBuilderList.size());
  560.         }
  561.         catch (RemoteException exception)
  562.         {
  563.             throw new RuntimeException("Locartion for generator queue cannot be determined.");
  564.         }
  565.         return map;
  566.     }

  567. }