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