View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import org.djutils.exceptions.Throw;
4   import org.opentrafficsim.core.network.LateralDirectionality;
5   
6   /**
7    * Defines a lane relative to the current lane.
8    * <p>
9    * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
10   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
11   * </p>
12   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
13   */
14  public class RelativeLane implements Comparable<RelativeLane>
15  {
16  
17      /** Second left lane. */
18      public static final RelativeLane SECOND_LEFT = new RelativeLane(LateralDirectionality.LEFT, 2);
19  
20      /** Left lane. */
21      public static final RelativeLane LEFT = new RelativeLane(LateralDirectionality.LEFT, 1);
22  
23      /** Current lane. */
24      public static final RelativeLane CURRENT = new RelativeLane(LateralDirectionality.NONE, 0);
25  
26      /** right lane. */
27      public static final RelativeLane RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 1);
28  
29      /** Second right lane. */
30      public static final RelativeLane SECOND_RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 2);
31  
32      /**
33       * Rank, summarizes both the lateral directionality and the number of lanes. Is zero for CURRENT, otherwise equal to number
34       * of lanes for RIGHT, negative number of lanes for LEFT.
35       */
36      private final int rank;
37  
38      /**
39       * Private constructor.
40       * @param rank the rank
41       */
42      private RelativeLane(final int rank)
43      {
44          this.rank = rank;
45      }
46  
47      /**
48       * Constructor.
49       * @param lat lateral direction (use {@code null} for the current lane)
50       * @param numLanes 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((!lat.isNone()) && numLanes <= 0, IllegalArgumentException.class,
60                  "Relative lane with %d lanes in %s direction is not allowed, use values > 0.", numLanes, lat);
61          this.rank = lat.isLeft() ? -numLanes : numLanes;
62      }
63  
64      /**
65       * Returns the lateral direction.
66       * @return the lateral direction
67       */
68      public final LateralDirectionality getLateralDirectionality()
69      {
70          // return this.lat;
71          return this.rank == 0 ? LateralDirectionality.NONE
72                  : this.rank < 0 ? LateralDirectionality.LEFT : LateralDirectionality.RIGHT;
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 Math.abs(this.rank);
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 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         return new RelativeLane(this.rank + relativeLane.rank);
156     }
157 
158     @Override
159     public int hashCode()
160     {
161         final int prime = 31;
162         int result = 1;
163         result = prime * result + this.rank;
164         return result;
165     }
166 
167     @Override
168     public boolean equals(final Object obj)
169     {
170         if (this == obj)
171         {
172             return true;
173         }
174         if (obj == null)
175         {
176             return false;
177         }
178         if (getClass() != obj.getClass())
179         {
180             return false;
181         }
182         RelativeLane other = (RelativeLane) obj;
183         if (this.rank != other.rank) // relative lane is uniquely defined by the rank
184         {
185             return false;
186         }
187         return true;
188     }
189 
190     @Override
191     public final String toString()
192     {
193         if (this.equals(CURRENT))
194         {
195             return "RelativeLane [CURRENT]";
196         }
197         return new StringBuilder("RelativeLane [").append(getLateralDirectionality()).append(", ").append(getNumLanes())
198                 .append("]").toString();
199     }
200 
201     @Override
202     public final int compareTo(final RelativeLane rel)
203     {
204         return this.rank - rel.rank;
205     }
206 
207 }