View Javadoc
1   package org.opentrafficsim.road.network.lane;
2   
3   import java.io.Serializable;
4   import java.util.LinkedHashSet;
5   import java.util.Set;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djutils.exceptions.Try;
9   import org.djutils.immutablecollections.ImmutableMap;
10  import org.opentrafficsim.core.geometry.OTSGeometryException;
11  import org.opentrafficsim.core.gtu.GTUDirectionality;
12  import org.opentrafficsim.core.network.LateralDirectionality;
13  import org.opentrafficsim.core.network.LinkDirection;
14  import org.opentrafficsim.core.network.NetworkException;
15  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
16  
17  import nl.tudelft.simulation.language.d3.DirectedPoint;
18  
19  /**
20   * Combines a Lane with its GTUDirectionality.
21   * <p>
22   * Copyright (c) 2013-2019 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 Mar 30, 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   */
30  public class LaneDirection implements Serializable
31  {
32      /** */
33      private static final long serialVersionUID = 20160330L;
34  
35      /** The lane. */
36      private final Lane lane;
37  
38      /** The GTU direction to drive on this lane. */
39      private final GTUDirectionality direction;
40  
41      /**
42       * @param lane Lane; the lane
43       * @param direction GTUDirectionality; the direction to drive on this lane
44       */
45      public LaneDirection(final Lane lane, final GTUDirectionality direction)
46      {
47          super();
48          this.lane = lane;
49          this.direction = direction;
50      }
51  
52      /**
53       * @return the lane
54       */
55      public final Lane getLane()
56      {
57          return this.lane;
58      }
59  
60      /**
61       * @return the direction to drive on this lane
62       */
63      public final GTUDirectionality getDirection()
64      {
65          return this.direction;
66      }
67  
68      /**
69       * Returns the covered distance driven to the given fractional position.
70       * @param fraction double; fractional position
71       * @return Length; covered distance driven to the given fractional position
72       */
73      public final Length coveredDistance(final double fraction)
74      {
75          if (this.direction.isPlus())
76          {
77              return getLane().getLength().times(fraction);
78          }
79          return getLane().getLength().times(1.0 - fraction);
80      }
81  
82      /**
83       * Returns the remaining distance to be driven from the given fractional position.
84       * @param fraction double; fractional position
85       * @return Length; remaining distance to be driven from the given fractional position
86       */
87      public final Length remainingDistance(final double fraction)
88      {
89          if (this.direction.isPlus())
90          {
91              return getLane().getLength().times(1.0 - fraction);
92          }
93          return getLane().getLength().times(fraction);
94      }
95  
96      /**
97       * Returns the fraction along the design line for having covered the given distance.
98       * @param distance Length; covered distance
99       * @return double; fraction along the design line for having covered the given distance
100      */
101     public final double fractionAtCoveredDistance(final Length distance)
102     {
103         double f = this.lane.fraction(distance);
104         if (this.getDirection().isMinus())
105         {
106             f = 1.0 - f;
107         }
108         return f;
109     }
110 
111     /**
112      * Returns the next lane and direction.
113      * @param gtu LaneBasedGTU; gtu
114      * @return LaneDirection; next lane and direction, {@code null} if none
115      */
116     public final LaneDirection getNextLaneDirection(final LaneBasedGTU gtu)
117     {
118         ImmutableMap<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
119         if (next.isEmpty())
120         {
121             return null;
122         }
123         // ask strategical planner
124         Set<LaneDirection> set = getNextForRoute(gtu);
125         if (set.size() == 1)
126         {
127             return set.iterator().next();
128         }
129         // check of the GTU is registered on any
130         for (LaneDirection l : set)
131         {
132             if (l.getLane().getGtuList().contains(gtu))
133             {
134                 return l;
135             }
136         }
137         // ask tactical planner
138         return Try.assign(() -> gtu.getTacticalPlanner().chooseLaneAtSplit(this, set), "Missing parameter.");
139     }
140 
141     /**
142      * Returns a set of {@code LaneDirection}'s that can be followed considering the route.
143      * @param gtu LaneBasedGTU; GTU
144      * @return set of {@code LaneDirection}'s that can be followed considering the route
145      */
146     public Set<LaneDirection> getNextForRoute(final LaneBasedGTU gtu)
147     {
148         ImmutableMap<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
149         if (next.isEmpty())
150         {
151             return null;
152         }
153         LinkDirection ld;
154         try
155         {
156             ld = gtu.getStrategicalPlanner().nextLinkDirection(this.lane.getParentLink(), this.direction, gtu.getGTUType());
157         }
158         catch (NetworkException exception)
159         {
160             throw new RuntimeException("Strategical planner experiences exception on network.", exception);
161         }
162         Set<LaneDirection> out = new LinkedHashSet<>();
163         for (Lane l : next.keySet())
164         {
165             GTUDirectionality dir = next.get(l);
166             if (l.getParentLink().equals(ld.getLink()) && dir.equals(ld.getDirection()))
167             {
168                 out.add(new LaneDirection(l, dir));
169             }
170         }
171         return out;
172     }
173 
174     /**
175      * Returns the length of the lane.
176      * @return Length; length of the lane
177      */
178     public Length getLength()
179     {
180         return this.lane.getLength();
181     }
182 
183     /**
184      * Returns a directed point at the given fraction, in the direction of travel (not center line).
185      * @param fraction double; fractional position
186      * @return directed point at the given fraction, in the direction of travel
187      * @throws OTSGeometryException in case the fractional position is not correct
188      */
189     public DirectedPoint getLocationFraction(final double fraction) throws OTSGeometryException
190     {
191         DirectedPoint p = this.lane.getCenterLine().getLocationFraction(fraction);
192         if (this.direction.isMinus())
193         {
194             p.setRotZ(p.getRotZ() + Math.PI);
195         }
196         return p;
197     }
198 
199     /**
200      * Returns the adjacent lane and direction.
201      * @param gtu LaneBasedGTU; gtu
202      * @param laneChangeDirection LateralDirectionality; lane change direction
203      * @return LaneDirection; adjacent lane and direction, {@code null} if none
204      */
205     public final LaneDirection getAdjacentLaneDirection(final LateralDirectionality laneChangeDirection, final LaneBasedGTU gtu)
206     {
207         Set<Lane> adjLanes = this.lane.accessibleAdjacentLanesLegal(laneChangeDirection, gtu.getGTUType(), this.direction);
208         if (!adjLanes.isEmpty())
209         {
210             return new LaneDirection(adjLanes.iterator().next(), this.direction);
211         }
212         return null;
213     }
214 
215     /** {@inheritDoc} */
216     @Override
217     public final String toString()
218     {
219         return "[" + this.lane + (this.direction.isPlus() ? " +]" : " -]");
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     public final int hashCode()
225     {
226         final int prime = 31;
227         int result = 1;
228         result = prime * result + ((this.direction == null) ? 0 : this.direction.hashCode());
229         result = prime * result + ((this.lane == null) ? 0 : this.lane.hashCode());
230         return result;
231     }
232 
233     /** {@inheritDoc} */
234     @Override
235     public final boolean equals(final Object obj)
236     {
237         if (this == obj)
238         {
239             return true;
240         }
241         if (obj == null)
242         {
243             return false;
244         }
245         if (getClass() != obj.getClass())
246         {
247             return false;
248         }
249         LaneDirection../../../org/opentrafficsim/road/network/lane/LaneDirection.html#LaneDirection">LaneDirection other = (LaneDirection) obj;
250         if (this.direction != other.direction)
251         {
252             return false;
253         }
254         if (this.lane == null)
255         {
256             if (other.lane != null)
257             {
258                 return false;
259             }
260         }
261         else if (!this.lane.equals(other.lane))
262         {
263             return false;
264         }
265         return true;
266     }
267 
268 }