LaneBasedTacticalPlanner.java

  1. package org.opentrafficsim.road.gtu.lane.tactical;

  2. import java.util.Collections;
  3. import java.util.Iterator;
  4. import java.util.Set;

  5. import org.djunits.value.vdouble.scalar.Length;
  6. import org.opentrafficsim.base.parameters.ParameterException;
  7. import org.opentrafficsim.base.parameters.ParameterTypes;
  8. import org.opentrafficsim.core.gtu.GTUException;
  9. import org.opentrafficsim.core.gtu.plan.tactical.TacticalPlanner;
  10. import org.opentrafficsim.core.network.LateralDirectionality;
  11. import org.opentrafficsim.core.network.Link;
  12. import org.opentrafficsim.core.network.Node;
  13. import org.opentrafficsim.core.network.route.Route;
  14. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  15. import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
  16. import org.opentrafficsim.road.gtu.lane.plan.operational.LaneBasedOperationalPlan;
  17. import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
  18. import org.opentrafficsim.road.network.lane.Lane;
  19. import org.opentrafficsim.road.network.lane.LaneDirection;

  20. /**
  21.  * <p>
  22.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  23.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  24.  * </p>
  25.  * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
  26.  * initial version May 27, 2016 <br>
  27.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  28.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  29.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  30.  */
  31. public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGTU, LanePerception>
  32. {
  33.     /**
  34.      * Returns the car-following model.
  35.      * @return car following model
  36.      */
  37.     CarFollowingModel getCarFollowingModel();

  38.     /**
  39.      * Selects a lane from a possible set. This set contains all viable lanes in to which a lanes splits.
  40.      * @param from LaneDirection; lane we come from
  41.      * @param lanes Set&lt;LaneDirection&gt;; set of lane directions possible
  42.      * @return LaneDirection; preferred lane direction
  43.      * @throws ParameterException in case of a missing parameter
  44.      */
  45.     default LaneDirection chooseLaneAtSplit(final LaneDirection from, final Set<LaneDirection> lanes) throws ParameterException
  46.     {
  47.         if (getGtu().getOperationalPlan() instanceof LaneBasedOperationalPlan
  48.                 && ((LaneBasedOperationalPlan) getGtu().getOperationalPlan()).isDeviative())
  49.         {
  50.             // take the lane adjacent to lane we are registered on, if any
  51.             LateralDirectionality forceSide = LateralDirectionality.NONE;
  52.             try
  53.             {
  54.                 Set<Lane> leftLanes = from.getLane().accessibleAdjacentLanesPhysical(LateralDirectionality.LEFT,
  55.                         getGtu().getGTUType(), from.getDirection());
  56.                 if (!Collections.disjoint(getGtu().positions(getGtu().getReference()).keySet(), leftLanes))
  57.                 {
  58.                     forceSide = LateralDirectionality.LEFT;
  59.                 }
  60.                 else
  61.                 {
  62.                     Set<Lane> rightLanes = from.getLane().accessibleAdjacentLanesPhysical(LateralDirectionality.RIGHT,
  63.                             getGtu().getGTUType(), from.getDirection());
  64.                     if (!Collections.disjoint(getGtu().positions(getGtu().getReference()).keySet(), rightLanes))
  65.                     {
  66.                         forceSide = LateralDirectionality.RIGHT;
  67.                     }
  68.                 }
  69.             }
  70.             catch (GTUException exception)
  71.             {
  72.                 throw new RuntimeException("Exception obtaining reference position.", exception);
  73.             }
  74.             if (!forceSide.isNone())
  75.             {
  76.                 if (lanes.isEmpty())
  77.                 {
  78.                     // A sink should delete the GTU, or a lane change should end, before reaching the end of the lane
  79.                     return null;
  80.                 }
  81.                 else
  82.                 {
  83.                     Iterator<LaneDirection> iter = lanes.iterator();
  84.                     LaneDirection next = iter.next();
  85.                     while (iter.hasNext())
  86.                     {
  87.                         LaneDirection candidate = iter.next();
  88.                         next = LaneBasedTacticalPlanner.mostOnSide(next, candidate, forceSide);
  89.                     }
  90.                     return next;
  91.                 }
  92.             }
  93.         }
  94.         Route route = getGtu().getStrategicalPlanner().getRoute();
  95.         if (route == null)
  96.         {
  97.             // select right-most lane
  98.             LaneDirection rightMost = null;
  99.             for (LaneDirection lane : lanes)
  100.             {
  101.                 rightMost = rightMost == null ? lane : mostOnSide(rightMost, lane, LateralDirectionality.RIGHT);
  102.             }
  103.             return rightMost;
  104.         }
  105.         Length maxDistance = Length.NEGATIVE_INFINITY;
  106.         LaneDirection best = null;
  107.         for (LaneDirection lane : lanes)
  108.         {
  109.             LaneDirection next = lane.getNextLaneDirection(getGtu());
  110.             if (next != null)
  111.             {
  112.                 Length okDistance = okDistance(next, lane.getLength(), route,
  113.                         getGtu().getParameters().getParameter(ParameterTypes.PERCEPTION));
  114.                 if (maxDistance.eq(okDistance))
  115.                 {
  116.                     best = mostOnSide(best, lane, LateralDirectionality.RIGHT);
  117.                 }
  118.                 else if (okDistance.gt(maxDistance))
  119.                 {
  120.                     maxDistance = okDistance;
  121.                     best = lane;
  122.                 }
  123.             }
  124.         }
  125.         return best;
  126.     }

  127.     /**
  128.      * Helper method for default chooseLaneAtSplit implementation that returns the distance from this lane onwards where the
  129.      * route can be followed.
  130.      * @param lane LaneDirection; lane and direction
  131.      * @param distance Length; distance so far
  132.      * @param route Route; route
  133.      * @param maxDistance Length; max search distance
  134.      * @return Length; distance from this lane onwards where the route can be followed
  135.      */
  136.     // TODO private when we use java 9
  137.     default Length okDistance(final LaneDirection lane, final Length distance, final Route route, final Length maxDistance)
  138.     {
  139.         if (distance.gt(maxDistance))
  140.         {
  141.             return maxDistance;
  142.         }
  143.         LaneDirection next = lane.getNextLaneDirection(getGtu());
  144.         if (next == null)
  145.         {
  146.             Node endNode = lane.getDirection().isPlus() ? lane.getLane().getParentLink().getEndNode()
  147.                     : lane.getLane().getParentLink().getStartNode();
  148.             Set<Link> links = endNode.getLinks().toSet();
  149.             links.remove(lane.getLane().getParentLink());
  150.             if (route.contains(endNode) && (links.isEmpty() || links.iterator().next().getLinkType().isConnector()))
  151.             {
  152.                 // dead-end link, must be destination
  153.                 return maxDistance;
  154.             }
  155.             // there is no next lane on the route, return the distance to the end of this lane
  156.             return distance.plus(lane.getLength());
  157.         }
  158.         return okDistance(next, distance.plus(lane.getLength()), route, maxDistance);
  159.     }

  160.     /**
  161.      * Returns the right-most of two lanes.
  162.      * @param lane1 LaneDirection; lane 1
  163.      * @param lane2 LaneDirection; lane 2
  164.      * @param lat LateralDirectionality; lateral side
  165.      * @return LaneDirection; right-most of two lanes
  166.      */
  167.     static LaneDirection mostOnSide(final LaneDirection lane1, final LaneDirection lane2, final LateralDirectionality lat)
  168.     {
  169.         Length offset1 = lane1.getLane().getDesignLineOffsetAtBegin().plus(lane1.getLane().getDesignLineOffsetAtEnd());
  170.         offset1 = lane1.getDirection().isPlus() ? offset1 : offset1.neg();
  171.         Length offset2 = lane2.getLane().getDesignLineOffsetAtBegin().plus(lane2.getLane().getDesignLineOffsetAtEnd());
  172.         offset2 = lane2.getDirection().isPlus() ? offset2 : offset2.neg();
  173.         if (lat.isLeft())
  174.         {
  175.             return offset1.gt(offset2) ? lane1 : lane2;
  176.         }
  177.         return offset1.gt(offset2) ? lane2 : lane1;
  178.     }

  179. }