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  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  public class LaneDirection implements Serializable
31  {
32      
33      private static final long serialVersionUID = 20160330L;
34  
35      
36      private final Lane lane;
37  
38      
39      private final GTUDirectionality direction;
40  
41      
42  
43  
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  
54  
55      public final Lane getLane()
56      {
57          return this.lane;
58      }
59  
60      
61  
62  
63      public final GTUDirectionality getDirection()
64      {
65          return this.direction;
66      }
67  
68      
69  
70  
71  
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  
84  
85  
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  
98  
99  
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 
113 
114 
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         
124         Set<LaneDirection> set = getNextForRoute(gtu);
125         if (set.size() == 1)
126         {
127             return set.iterator().next();
128         }
129         
130         for (LaneDirection l : set)
131         {
132             if (l.getLane().getGtuList().contains(gtu))
133             {
134                 return l;
135             }
136         }
137         
138         return Try.assign(() -> gtu.getTacticalPlanner().chooseLaneAtSplit(this, set), "Missing parameter.");
139     }
140 
141     
142 
143 
144 
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 
176 
177 
178     public Length getLength()
179     {
180         return this.lane.getLength();
181     }
182 
183     
184 
185 
186 
187 
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 
201 
202 
203 
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     
216     @Override
217     public final String toString()
218     {
219         return "[" + this.lane + (this.direction.isPlus() ? " +]" : " -]");
220     }
221 
222     
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     
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 }