View Javadoc
1   package org.opentrafficsim.road.gtu.lane.tactical;
2   
3   import java.util.Set;
4   
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.plan.tactical.TacticalPlanner;
9   import org.opentrafficsim.core.network.Link;
10  import org.opentrafficsim.core.network.Node;
11  import org.opentrafficsim.core.network.route.Route;
12  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
13  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
14  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
15  import org.opentrafficsim.road.network.lane.LaneDirection;
16  
17  /**
18   * <p>
19   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
21   * </p>
22   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
23   * initial version May 27, 2016 <br>
24   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
25   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
26   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
27   */
28  public interface LaneBasedTacticalPlanner extends TacticalPlanner<LaneBasedGTU, LanePerception>
29  {
30      /**
31       * Returns the car-following model.
32       * @return car following model
33       */
34      CarFollowingModel getCarFollowingModel();
35  
36      /**
37       * Selects a lane from a possible set. This set contains all viable lanes in to which a lanes splits.
38       * @param lanes Set&lt;LaneDirection&gt;; set of lane directions possible
39       * @return LaneDirection; preferred lane direction
40       * @throws ParameterException in case of a missing parameter
41       */
42      default LaneDirection chooseLaneAtSplit(final Set<LaneDirection> lanes) throws ParameterException
43      {
44          Route route = getGtu().getStrategicalPlanner().getRoute();
45          if (route == null)
46          {
47              // select right-most lane
48              LaneDirection rightMost = null;
49              for (LaneDirection lane : lanes)
50              {
51                  rightMost = rightMost == null ? lane : rightMost(rightMost, lane);
52              }
53              return rightMost;
54          }
55          Length maxDistance = Length.NEGATIVE_INFINITY;
56          LaneDirection best = null;
57          for (LaneDirection lane : lanes)
58          {
59              LaneDirection next = lane.getNextLaneDirection(getGtu());
60              if (next != null)
61              {
62                  Length okDistance = okDistance(next, lane.getLength(), route,
63                          getGtu().getParameters().getParameter(ParameterTypes.PERCEPTION));
64                  if (maxDistance.eq(okDistance))
65                  {
66                      best = rightMost(best, lane);
67                  }
68                  else if (okDistance.gt(maxDistance))
69                  {
70                      maxDistance = okDistance;
71                      best = lane;
72                  }
73              }
74          }
75          return best;
76      }
77  
78      /**
79       * Helper method for default chooseLaneAtSplit implementation that returns the distance from this lane onwards where the
80       * route can be followed.
81       * @param lane LaneDirection; lane and direction
82       * @param distance Length; distance so far
83       * @param route Route; route
84       * @param maxDistance Length; max search distance
85       * @return Length; distance from this lane onwards where the route can be followed
86       */
87      // TODO private when we use java 9
88      default Length okDistance(final LaneDirection lane, final Length distance, final Route route, final Length maxDistance)
89      {
90          if (distance.gt(maxDistance))
91          {
92              return maxDistance;
93          }
94          LaneDirection next = lane.getNextLaneDirection(getGtu());
95          if (next == null)
96          {
97              Node endNode = lane.getDirection().isPlus() ? lane.getLane().getParentLink().getEndNode()
98                      : lane.getLane().getParentLink().getStartNode();
99              Set<Link> links = endNode.getLinks().toSet();
100             links.remove(lane.getLane().getParentLink());
101             if (route.contains(endNode) && (links.isEmpty() || links.iterator().next().getLinkType().isConnector()))
102             {
103                 // dead-end link, must be destination
104                 return maxDistance;
105             }
106             // there is no next lane on the route, return the distance to the end of this lane
107             return distance.plus(lane.getLength());
108         }
109         return okDistance(next, distance.plus(lane.getLength()), route, maxDistance);
110     }
111 
112     /**
113      * Returns the right-most of two lanes.
114      * @param lane1 LaneDirection; lane 1
115      * @param lane2 LaneDirection; lane 2
116      * @return LaneDirection; right-most of two lanes
117      */
118     // TODO private when we use java 9
119     default LaneDirection rightMost(final LaneDirection lane1, final LaneDirection lane2)
120     {
121         Length offset1 = lane1.getLane().getDesignLineOffsetAtBegin().plus(lane1.getLane().getDesignLineOffsetAtEnd());
122         offset1 = lane1.getDirection().isPlus() ? offset1 : offset1.neg();
123         Length offset2 = lane2.getLane().getDesignLineOffsetAtBegin().plus(lane2.getLane().getDesignLineOffsetAtEnd());
124         offset2 = lane2.getDirection().isPlus() ? offset2 : offset2.neg();
125         return offset1.lt(offset2) ? lane1 : lane2;
126     }
127 
128 }