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