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-2022 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      /**
39       * Rank, summarizes both the lateral directionality and the number of lanes. Is zero for CURRENT, otherwise equal to number
40       * of lanes for RIGHT, negative number of lanes for LEFT.
41       */
42      private final int rank;
43  
44      /**
45       * Private constructor.
46       * @param rank int; the rank
47       */
48      private RelativeLane(final int rank)
49      {
50          this.rank = rank;
51      }
52  
53      /**
54       * Constructor.
55       * @param lat LateralDirectionality; lateral direction (use {@code null} for the current lane)
56       * @param numLanes int; number of lanes in the lateral direction (not important for the current lane)
57       * @throws IllegalArgumentException if numLanes is not at least 1, except if {@code lat == null} (current lane)
58       * @throws IllegalArgumentException if numLanes is not 0 if {@code lat == null} (current lane)
59       */
60      public RelativeLane(final LateralDirectionality lat, final int numLanes)
61      {
62          Throw.whenNull(lat, "Lateral directionality may not be null.");
63          Throw.when(lat.isNone() && numLanes != 0, IllegalArgumentException.class,
64                  "Number of lanes must be zero if the lateral directionality is NONE.");
65          Throw.when((!lat.isNone()) && numLanes <= 0, IllegalArgumentException.class,
66                  "Relative lane with %d lanes in %s direction is not allowed, use values > 0.", numLanes, lat);
67          this.rank = lat.isLeft() ? -numLanes : numLanes;
68      }
69  
70      /**
71       * Returns the lateral direction.
72       * @return LateralDirectionality; the lateral direction
73       */
74      public final LateralDirectionality getLateralDirectionality()
75      {
76          // return this.lat;
77          return this.rank == 0 ? LateralDirectionality.NONE
78                  : this.rank < 0 ? LateralDirectionality.LEFT : LateralDirectionality.RIGHT;
79      }
80  
81      /**
82       * Returns the number of lanes in the lateral direction.
83       * @return int; number of lanes in the lateral direction
84       */
85      public final int getNumLanes()
86      {
87          return Math.abs(this.rank);
88      }
89  
90      /**
91       * Returns whether the second left lane is referred to.
92       * @return whether the second left lane is referred to
93       */
94      public final boolean isSecondLeft()
95      {
96          return this.equals(SECOND_LEFT);
97      }
98  
99      /**
100      * Returns whether the left lane is referred to.
101      * @return whether the left lane is referred to
102      */
103     public final boolean isLeft()
104     {
105         return this.equals(LEFT);
106     }
107 
108     /**
109      * Returns whether the current lane is referred to.
110      * @return whether the current lane is referred to
111      */
112     public final boolean isCurrent()
113     {
114         return this.equals(CURRENT);
115     }
116 
117     /**
118      * Returns whether the right lane is referred to.
119      * @return whether the right lane is referred to
120      */
121     public final boolean isRight()
122     {
123         return this.equals(RIGHT);
124     }
125 
126     /**
127      * Returns whether the second right lane is referred to.
128      * @return whether the second right lane is referred to
129      */
130     public final boolean isSecondRight()
131     {
132         return this.equals(SECOND_RIGHT);
133     }
134 
135     /**
136      * Returns the left hand relative lane of this relative lane.
137      * @return left hand relative lane of this relative lane.
138      */
139     public final RelativeLane getLeft()
140     {
141         return this.add(LEFT);
142     }
143 
144     /**
145      * Returns the right hand relative lane of this relative lane.
146      * @return right hand relative lane of this relative lane.
147      */
148     public final RelativeLane getRight()
149     {
150         return this.add(RIGHT);
151     }
152 
153     /**
154      * Returns the relative lane relative to this lane, for example "the left lane" of "the 3rd right lane" is "the 2nd right
155      * lane".
156      * @param relativeLane RelativeLane; relative lane to get of this lane
157      * @return relative lane relative to this lane
158      */
159     public final RelativeLane add(final RelativeLane relativeLane)
160     {
161         return new RelativeLane(this.rank + relativeLane.rank);
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public int hashCode()
167     {
168         final int prime = 31;
169         int result = 1;
170         result = prime * result + this.rank;
171         return result;
172     }
173 
174     /** {@inheritDoc} */
175     @Override
176     public boolean equals(final Object obj)
177     {
178         if (this == obj)
179         {
180             return true;
181         }
182         if (obj == null)
183         {
184             return false;
185         }
186         if (getClass() != obj.getClass())
187         {
188             return false;
189         }
190         RelativeLane other = (RelativeLane) obj;
191         if (this.rank != other.rank) // relative lane is uniquely defined by the rank
192         {
193             return false;
194         }
195         return true;
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public final String toString()
201     {
202         if (this.equals(CURRENT))
203         {
204             return "RelativeLane [CURRENT]";
205         }
206         return new StringBuilder("RelativeLane [").append(getLateralDirectionality()).append(", ").append(getNumLanes())
207                 .append("]").toString();
208     }
209 
210     /** {@inheritDoc} */
211     @Override
212     public final int compareTo(final RelativeLane rel)
213     {
214         return this.rank - rel.rank;
215     }
216 
217 }