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-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 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 if 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),
139                 "Could not find suitable lane at split after lane %s in %s of link %s for GTU %s.", this.lane.getId(),
140                 this.direction, this.lane.getParentLink().getId(), gtu.getId());
141     }
142 
143     /**
144      * Returns a set of {@code LaneDirection}'s that can be followed considering the route.
145      * @param gtu LaneBasedGTU; GTU
146      * @return set of {@code LaneDirection}'s that can be followed considering the route
147      */
148     public Set<LaneDirection> getNextForRoute(final LaneBasedGTU gtu)
149     {
150         ImmutableMap<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
151         if (next.isEmpty())
152         {
153             return null;
154         }
155         LinkDirection ld;
156         try
157         {
158             ld = gtu.getStrategicalPlanner().nextLinkDirection(this.lane.getParentLink(), this.direction, gtu.getGTUType());
159         }
160         catch (NetworkException exception)
161         {
162             throw new RuntimeException("Strategical planner experiences exception on network.", exception);
163         }
164         Set<LaneDirection> out = new LinkedHashSet<>();
165         for (Lane l : next.keySet())
166         {
167             GTUDirectionality dir = next.get(l);
168             if (l.getParentLink().equals(ld.getLink()) && dir.equals(ld.getDirection()))
169             {
170                 out.add(new LaneDirection(l, dir));
171             }
172         }
173 //        if (out.size() == 0)
174 //        {
175 //            gtu.getSimulator().getLogger().always().warn(
176 //                    "Could not find a next segment for GTU \"{}\" on lane {}, on route {}; LinkDirection is {}, {}",
177 //                    gtu.getId(), this.lane, next.keySet(), ld.getLink().getId(), ld.getDirection());
178 //            gtu.getSimulator().getLogger().always().warn(gtu.getStrategicalPlanner().getRoute());
179 //            for (Lane l : next.keySet())
180 //            {
181 //                GTUDirectionality dir = next.get(l);
182 //                gtu.getSimulator().getLogger().always().info("examining l={}, dir={}", l, dir);
183 //                if (!l.getParentLink().equals(ld.getLink()))
184 //                {
185 //                    gtu.getSimulator().getLogger().always()
186 //                            .info("not including lane {} with direction {} because \"parent link does not match\"", l, dir);
187 //                }
188 //                if (!dir.equals(ld.getDirection()))
189 //                {
190 //                    gtu.getSimulator().getLogger().always()
191 //                            .info("not including lane {} with direction {} because direction does not match", l, dir);
192 //                }
193 //            }
194 //        }
195         return out;
196     }
197 
198     /**
199      * Returns the length of the lane.
200      * @return Length; length of the lane
201      */
202     public Length getLength()
203     {
204         return this.lane.getLength();
205     }
206 
207     /**
208      * Returns a directed point at the given fraction, in the direction of travel (not center line).
209      * @param fraction double; fractional position
210      * @return directed point at the given fraction, in the direction of travel
211      * @throws OTSGeometryException in case the fractional position is not correct
212      */
213     public DirectedPoint getLocationFraction(final double fraction) throws OTSGeometryException
214     {
215         DirectedPoint p = this.lane.getCenterLine().getLocationFraction(fraction);
216         if (this.direction.isMinus())
217         {
218             p.setRotZ(p.getRotZ() + Math.PI);
219         }
220         return p;
221     }
222 
223     /**
224      * Returns the adjacent lane and direction.
225      * @param gtu LaneBasedGTU; gtu
226      * @param laneChangeDirection LateralDirectionality; lane change direction
227      * @return LaneDirection; adjacent lane and direction, {@code null} if none
228      */
229     public final LaneDirection getAdjacentLaneDirection(final LateralDirectionality laneChangeDirection, final LaneBasedGTU gtu)
230     {
231         Set<Lane> adjLanes = this.lane.accessibleAdjacentLanesLegal(laneChangeDirection, gtu.getGTUType(), this.direction);
232         if (!adjLanes.isEmpty())
233         {
234             return new LaneDirection(adjLanes.iterator().next(), this.direction);
235         }
236         return null;
237     }
238 
239     /** {@inheritDoc} */
240     @Override
241     public final String toString()
242     {
243         return "[" + this.lane + (this.direction.isPlus() ? " +]" : " -]");
244     }
245 
246     /** {@inheritDoc} */
247     @Override
248     public final int hashCode()
249     {
250         final int prime = 31;
251         int result = 1;
252         result = prime * result + ((this.direction == null) ? 0 : this.direction.hashCode());
253         result = prime * result + ((this.lane == null) ? 0 : this.lane.hashCode());
254         return result;
255     }
256 
257     /** {@inheritDoc} */
258     @Override
259     public final boolean equals(final Object obj)
260     {
261         if (this == obj)
262         {
263             return true;
264         }
265         if (obj == null)
266         {
267             return false;
268         }
269         if (getClass() != obj.getClass())
270         {
271             return false;
272         }
273         LaneDirection../../../org/opentrafficsim/road/network/lane/LaneDirection.html#LaneDirection">LaneDirection other = (LaneDirection) obj;
274         if (this.direction != other.direction)
275         {
276             return false;
277         }
278         if (this.lane == null)
279         {
280             if (other.lane != null)
281             {
282                 return false;
283             }
284         }
285         else if (!this.lane.equals(other.lane))
286         {
287             return false;
288         }
289         return true;
290     }
291 
292 }