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 }