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  
11  
12  
13  
14  
15  
16  
17  
18  public class RelativeLane implements Comparable<RelativeLane>, Serializable
19  {
20  
21      
22      private static final long serialVersionUID = 20160502L;
23  
24      
25      public static final RelativeLane SECOND_LEFT = new RelativeLane(LateralDirectionality.LEFT, 2);
26  
27      
28      public static final RelativeLane LEFT = new RelativeLane(LateralDirectionality.LEFT, 1);
29  
30      
31      public static final RelativeLane CURRENT = new RelativeLane(LateralDirectionality.NONE, 0);
32  
33      
34      public static final RelativeLane RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 1);
35  
36      
37      public static final RelativeLane SECOND_RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 2);
38  
39      
40      private final LateralDirectionality lat;
41  
42      
43      private final int numLanes;
44  
45      
46  
47  
48  
49  
50  
51  
52      public RelativeLane(final LateralDirectionality lat, final int numLanes)
53      {
54          Throw.whenNull(lat, "Lateral directionality may not be null.");
55          Throw.when(lat.equals(LateralDirectionality.NONE) && numLanes != 0, IllegalArgumentException.class,
56                  "Number of lanes must be zero if the lateral directionality is NONE.");
57          Throw.when(numLanes < 0, IllegalArgumentException.class,
58              "Relative lane with %d lanes in %s direction is not allowed, use values > 0.", numLanes, lat);
59          this.lat = lat;
60          this.numLanes = numLanes;
61      }
62  
63      
64  
65  
66  
67      public final LateralDirectionality getLateralDirectionality()
68      {
69          return this.lat;
70      }
71  
72      
73  
74  
75  
76      public final int getNumLanes()
77      {
78          return this.numLanes;
79      }
80  
81      
82  
83  
84  
85      public final boolean isSecondLeft()
86      {
87          return this.equals(SECOND_LEFT);
88      }
89  
90      
91  
92  
93  
94      public final boolean isLeft()
95      {
96          return this.equals(LEFT);
97      }
98  
99      
100 
101 
102 
103     public final boolean isCurrent()
104     {
105         return this.equals(CURRENT);
106     }
107 
108     
109 
110 
111 
112     public final boolean isRight()
113     {
114         return this.equals(RIGHT);
115     }
116 
117     
118 
119 
120 
121     public final boolean isSecondRight()
122     {
123         return this.equals(SECOND_RIGHT);
124     }
125 
126     
127 
128 
129 
130     public final RelativeLane getLeft()
131     {
132         return this.add(LEFT);
133     }
134 
135     
136 
137 
138 
139     public final RelativeLane getRight()
140     {
141         return this.add(RIGHT);
142     }
143 
144     
145 
146 
147 
148 
149 
150     public final RelativeLane add(final RelativeLane relativeLane)
151     {
152         int nThis = this.lat.isNone() ? 0 : this.lat.isLeft() ? -this.numLanes : this.numLanes;
153         int nOther =
154             relativeLane.lat.isNone() ? 0 : relativeLane.lat.isLeft() ? -relativeLane.numLanes : relativeLane.numLanes;
155         int nSum = nThis + nOther;
156         if (nSum < 0)
157         {
158             return new RelativeLane(LateralDirectionality.LEFT, -nSum);
159         }
160         if (nSum > 0)
161         {
162             return new RelativeLane(LateralDirectionality.RIGHT, nSum);
163         }
164         return CURRENT;
165     }
166 
167     
168     @Override
169     public final int hashCode()
170     {
171         int result = 17;
172         result = 31 * result + (this.lat != null ? this.lat.hashCode() : 0);
173         result = 31 * result + this.numLanes;
174         return result;
175     }
176 
177     
178     @Override
179     public final boolean equals(final Object obj)
180     {
181         if (obj == this)
182         {
183             return true;
184         }
185         if (!(obj instanceof RelativeLane))
186         {
187             return false;
188         }
189         RelativeLane rel = (RelativeLane) obj;
190         if (rel.lat == this.lat && rel.numLanes == this.numLanes)
191         {
192             return true;
193         }
194         return false;
195     }
196 
197     
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(this.lat).append(", ").append(this.numLanes).append("]")
206             .toString();
207     }
208 
209     
210     @Override
211     public final int compareTo(final RelativeLane rel)
212     {
213         int nThis = this.lat.isNone() ? 0 : this.lat.isLeft() ? -this.numLanes : this.numLanes;
214         int nRel = rel.lat.isNone() ? 0 : rel.lat.isLeft() ? -rel.numLanes : rel.numLanes;
215         return nThis - nRel;
216     }
217 
218 }