View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.io.Serializable;
4   
5   import org.djutils.exceptions.Throw;
6   import org.opentrafficsim.core.network.LateralDirectionality;
7   
8   /**
9    * Defines a lane relative to the current lane.
10   * <p>
11   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
12   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
13   * <p>
14   * @version $Revision$, $LastChangedDate$, by $Author$, initial version May 2, 2016 <br>
15   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
16   */
17  public class RelativeLane implements Comparable<RelativeLane>, Serializable
18  {
19  
20      /** */
21      private static final long serialVersionUID = 20160502L;
22  
23      /** Second left lane. */
24      public static final RelativeLane SECOND_LEFT = new RelativeLane(LateralDirectionality.LEFT, 2);
25  
26      /** Left lane. */
27      public static final RelativeLane LEFT = new RelativeLane(LateralDirectionality.LEFT, 1);
28  
29      /** Current lane. */
30      public static final RelativeLane CURRENT = new RelativeLane(LateralDirectionality.NONE, 0);
31  
32      /** right lane. */
33      public static final RelativeLane RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 1);
34  
35      /** Second right lane. */
36      public static final RelativeLane SECOND_RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 2);
37  
38      /** Lateral direction. */
39      private final LateralDirectionality lat;
40  
41      /** Number of lanes to lateral direction. */
42      private final int numLanes;
43  
44      /** Rank, for sorting. Is equal to number of lanes, but negative for left lanes. */
45      private final int rank;
46  
47      /**
48       * Constructor.
49       * @param lat LateralDirectionality; lateral direction (use {@code null} for the current lane)
50       * @param numLanes int; number of lanes in the lateral direction (not important for the current lane)
51       * @throws IllegalArgumentException if numLanes is not at least 1, except if {@code lat == null} (current lane)
52       * @throws IllegalArgumentException if numLanes is not 0 if {@code lat == null} (current lane)
53       */
54      public RelativeLane(final LateralDirectionality lat, final int numLanes)
55      {
56          Throw.whenNull(lat, "Lateral directionality may not be null.");
57          Throw.when(lat.isNone() && numLanes != 0, IllegalArgumentException.class,
58                  "Number of lanes must be zero if the lateral directionality is NONE.");
59          Throw.when(numLanes < 0, IllegalArgumentException.class,
60                  "Relative lane with %d lanes in %s direction is not allowed, use values > 0.", numLanes, lat);
61          this.lat = lat;
62          this.numLanes = numLanes;
63          this.rank = lat.isLeft() ? -numLanes : numLanes;
64      }
65  
66      /**
67       * Returns the lateral direction.
68       * @return lat lateral direction
69       */
70      public final LateralDirectionality getLateralDirectionality()
71      {
72          return this.lat;
73      }
74  
75      /**
76       * Returns the number of lanes in the lateral direction.
77       * @return number of lanes in the lateral direction
78       */
79      public final int getNumLanes()
80      {
81          return this.numLanes;
82      }
83  
84      /**
85       * Returns whether the second left lane is referred to.
86       * @return whether the second left lane is referred to
87       */
88      public final boolean isSecondLeft()
89      {
90          return this.equals(SECOND_LEFT);
91      }
92  
93      /**
94       * Returns whether the left lane is referred to.
95       * @return whether the left lane is referred to
96       */
97      public final boolean isLeft()
98      {
99          return this.equals(LEFT);
100     }
101 
102     /**
103      * Returns whether the current lane is referred to.
104      * @return whether the current lane is referred to
105      */
106     public final boolean isCurrent()
107     {
108         return this.equals(CURRENT);
109     }
110 
111     /**
112      * Returns whether the right lane is referred to.
113      * @return whether the right lane is referred to
114      */
115     public final boolean isRight()
116     {
117         return this.equals(RIGHT);
118     }
119 
120     /**
121      * Returns whether the second right lane is referred to.
122      * @return whether the second right lane is referred to
123      */
124     public final boolean isSecondRight()
125     {
126         return this.equals(SECOND_RIGHT);
127     }
128 
129     /**
130      * Returns the left hand relative lane of this relative lane.
131      * @return left hand relative lane of this relative lane.
132      */
133     public final RelativeLane getLeft()
134     {
135         return this.add(LEFT);
136     }
137 
138     /**
139      * Returns the right hand relative lane of this relative lane.
140      * @return right hand relative lane of this relative lane.
141      */
142     public final RelativeLane getRight()
143     {
144         return this.add(RIGHT);
145     }
146 
147     /**
148      * Returns the relative lane relative to this lane, for example "the left lane" of "the 3rd right lane" is "the 2nd right
149      * lane".
150      * @param relativeLane RelativeLane; relative lane to get of this lane
151      * @return relative lane relative to this lane
152      */
153     public final RelativeLane add(final RelativeLane relativeLane)
154     {
155         int rankSum = this.rank + relativeLane.rank;
156         if (rankSum < 0)
157         {
158             return new RelativeLane(LateralDirectionality.LEFT, -rankSum);
159         }
160         if (rankSum > 0)
161         {
162             return new RelativeLane(LateralDirectionality.RIGHT, rankSum);
163         }
164         return CURRENT;
165     }
166 
167     /** {@inheritDoc} */
168     @Override
169     public int hashCode()
170     {
171         final int prime = 31;
172         int result = 1;
173         result = prime * result + this.rank;
174         return result;
175     }
176 
177     /** {@inheritDoc} */
178     @Override
179     public boolean equals(final Object obj)
180     {
181         if (this == obj)
182         {
183             return true;
184         }
185         if (obj == null)
186         {
187             return false;
188         }
189         if (getClass() != obj.getClass())
190         {
191             return false;
192         }
193         RelativeLane other = (RelativeLane) obj;
194         if (this.rank != other.rank) // relative lane us uniquely defined by the rank
195         {
196             return false;
197         }
198         return true;
199     }
200 
201     /** {@inheritDoc} */
202     @Override
203     public final String toString()
204     {
205         if (this.equals(CURRENT))
206         {
207             return "RelativeLane [CURRENT]";
208         }
209         return new StringBuilder("RelativeLane [").append(this.lat).append(", ").append(this.numLanes).append("]").toString();
210     }
211 
212     /** {@inheritDoc} */
213     @Override
214     public final int compareTo(final RelativeLane rel)
215     {
216         return this.rank - rel.rank;
217     }
218 
219 }