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.         this.name = name;
  137.         this.gtuType = gtuType;
  138.         this.gtuClass = gtuClass;
  139.         this.initialSpeedDist = initialSpeedDist;
  140.         this.interarrivelTimeDist = interarrivelTimeDist;
  141.         this.maxGTUs = maxGTUs;
  142.         this.startTime = startTime;
  143.         this.endTime = endTime;
  144.         this.lane = lane;
  145.         this.position = position;
  146.         this.direction = direction;
  147.         this.strategicalPlannerFactory = strategicalPlannerFactory;
  148.         this.routeGenerator = routeGenerator;
  149.         this.network = network;
  150.         DirectedPoint p;
  151.         try
  152.         {
  153.             p = this.getLocation();
  154.             this.bounds = new BoundingBox(new Point3d(p.x - 1, p.y - 1, 0.0), new Point3d(p.x + 1, p.y + 1, 0.0));
  155.         }
  156.         catch (RemoteException exception)
  157.         {
  158.             throw new RuntimeException("Bounds for generator cannot be determined.");
  159.         }
  160.         simulator.scheduleEventAbs(startTime, this, this, "generate", null);

  161.         // notify the potential animation of the existence of a GTUGenerator
  162.         fireTimedEvent(Network.GENERATOR_ADD_EVENT, name, simulator.getSimulatorTime());
  163.         fireTimedEvent(Network.ANIMATION_GENERATOR_ADD_EVENT, this, simulator.getSimulatorTime());
  164.     }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  566. }