1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.io.Serializable;
4
5 import org.djunits.value.vdouble.scalar.Length;
6 import org.opentrafficsim.core.gtu.RelativePosition;
7 import org.opentrafficsim.core.network.LateralDirectionality;
8
9 import nl.tudelft.simulation.language.Throw;
10
11 /**
12 * Contains information by which drivers know when they need to leave a lane in order to be able to stay on the infrastructure
13 * and follow their route.
14 * <p>
15 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
16 * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
17 * <p>
18 * @version $Revision$, $LastChangedDate$, by $Author$, initial version May 2, 2016 <br>
19 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
20 */
21 public class InfrastructureLaneChangeInfo implements Comparable<InfrastructureLaneChangeInfo>, Serializable
22 {
23
24 /** */
25 private static final long serialVersionUID = 20160811L;
26
27 /** Required number of lane changes. */
28 private final int requiredNumberOfLaneChanges;
29
30 /** Record who's end defines the remaining distances. */
31 private final LaneStructureRecord record;
32
33 /** Available length after the start (reference on start). */
34 private final Length afterStartLength;
35
36 /** Whether the need to change lane comes from a dead-end. */
37 private boolean deadEnd;
38
39 /** Lateral directionality of required lane changes. */
40 private final LateralDirectionality lat;
41
42 /**
43 * Constructor for subclasses.
44 * @param requiredNumberOfLaneChanges required number of lane changes
45 * @param deadEnd whether the need to change lane comes from a dead-end
46 */
47 protected InfrastructureLaneChangeInfo(final int requiredNumberOfLaneChanges, final boolean deadEnd)
48 {
49 this.requiredNumberOfLaneChanges = requiredNumberOfLaneChanges;
50 this.record = null;
51 this.deadEnd = deadEnd;
52 this.afterStartLength = null;
53 this.lat = LateralDirectionality.NONE;
54 }
55
56 /**
57 * Constructor.
58 * @param requiredNumberOfLaneChanges required number of lane changes
59 * @param record record who's end defines the remaining distance
60 * @param relativePosition critical relative position (i.e. nose when driving forward)
61 * @param deadEnd whether the need to change lane comes from a dead-end
62 * @param lat LateralDirectionality; lateral directionality of required lane changes
63 * @throws IllegalArgumentException if required number of lane changes or remaining distance is negative
64 * @throws NullPointerException if remaining distance is null
65 */
66 public InfrastructureLaneChangeInfo(final int requiredNumberOfLaneChanges, final LaneStructureRecord record,
67 final RelativePosition relativePosition, final boolean deadEnd, final LateralDirectionality lat)
68 {
69 Throw.when(requiredNumberOfLaneChanges < 0, IllegalArgumentException.class,
70 "Required number of lane changes may not be negative.");
71 Throw.whenNull(lat, "Lateral directionality may not be null.");
72 Throw.when(requiredNumberOfLaneChanges != 0 && lat.equals(LateralDirectionality.NONE), IllegalArgumentException.class,
73 "Lateral directionality may not be NONE for non-zero lane changes.");
74 Throw.whenNull(record, "Record may not be null.");
75 this.requiredNumberOfLaneChanges = requiredNumberOfLaneChanges;
76 this.record = record;
77 this.afterStartLength = this.record.getLane().getLength().minus(relativePosition.getDx());
78 this.deadEnd = deadEnd;
79 this.lat = lat;
80 }
81
82 /**
83 * @return requiredNumberOfLaneChanges required number of lane changes.
84 */
85 public final int getRequiredNumberOfLaneChanges()
86 {
87 return this.requiredNumberOfLaneChanges;
88 }
89
90 /**
91 * @return remainingDistance remaining distance to perform required lane changes.
92 */
93 public Length getRemainingDistance()
94 {
95 return this.record.getStartDistance().plus(this.afterStartLength);
96 }
97
98 /**
99 * @return whether this reason to change lane is due to a dead-end.
100 */
101 public final boolean isDeadEnd()
102 {
103 return this.deadEnd;
104 }
105
106 /**
107 * Sets whether this reason to change lane is due to a dead-end.
108 * @param deadEnd whether the need to change lane comes from a dead-end
109 */
110 public final void setDeadEnd(final boolean deadEnd)
111 {
112 this.deadEnd = deadEnd;
113 }
114
115 /**
116 * Returns the lateral directionality of the required lane changes.
117 * @return LateralDirectionality; lateral directionality of the required lane changes
118 */
119 public final LateralDirectionality getLateralDirectionality()
120 {
121 return this.lat;
122 }
123
124 /** {@inheritDoc} */
125 @SuppressWarnings("checkstyle:designforextension")
126 @Override
127 public String toString()
128 {
129 return "InfrastructureLaneChangeInfo [requiredNumberOfLaneChanges=" + this.requiredNumberOfLaneChanges
130 + ", remainingDistance=" + getRemainingDistance() + "]";
131 }
132
133 /** {@inheritDoc} */
134 @Override
135 public final int compareTo(final InfrastructureLaneChangeInfo infrastructureLaneChangeInfo)
136 {
137 return this.getRemainingDistance().compareTo(infrastructureLaneChangeInfo.getRemainingDistance());
138 }
139
140 /**
141 * Returns lane change info for one lane towards the left.
142 * @param rec record who's end defines the remaining distance
143 * @param rel critical relative position (i.e. nose when driving forward)
144 * @param dead whether the need to change lane comes from a dead-end
145 * @return InfrastructureLaneChangeInfo; lane change info for one lane towards the left
146 */
147 public final InfrastructureLaneChangeInfo left(final LaneStructureRecord rec, final RelativePosition rel,
148 final boolean dead)
149 {
150 return new InfrastructureLaneChangeInfo(this.requiredNumberOfLaneChanges + 1, rec, rel, dead,
151 LateralDirectionality.LEFT);
152 }
153
154 /**
155 * Returns lane change info for one lane towards the right.
156 * @param rec record who's end defines the remaining distance
157 * @param rel critical relative position (i.e. nose when driving forward)
158 * @param dead whether the need to change lane comes from a dead-end
159 * @return InfrastructureLaneChangeInfo; lane change info for one lane towards the right
160 */
161 public final InfrastructureLaneChangeInfo right(final LaneStructureRecord rec, final RelativePosition rel,
162 final boolean dead)
163 {
164 return new InfrastructureLaneChangeInfo(this.requiredNumberOfLaneChanges + 1, rec, rel, dead,
165 LateralDirectionality.RIGHT);
166 }
167
168 /**
169 * Returns an instance for the case the entire lane is inaccessible.
170 * @param deadEnd dead end
171 * @return instance for the case the entire lane is inaccessible
172 */
173 public static InfrastructureLaneChangeInfo fromInaccessibleLane(final boolean deadEnd)
174 {
175 return new InfrastructureLaneChangeInfoInaccessibleLane(deadEnd);
176 }
177
178 /**
179 * Extension which sets the distance to 0 always, used for fully inaccessible lanes regarding the route.
180 * <p>
181 * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
182 * <br>
183 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
184 * <p>
185 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 feb. 2018 <br>
186 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
187 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
188 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
189 */
190 private static class InfrastructureLaneChangeInfoInaccessibleLane extends InfrastructureLaneChangeInfo
191 {
192
193 /** */
194 private static final long serialVersionUID = 20180214L;
195
196 /**
197 * @param deadEnd whether the need to change lane comes from a dead-end
198 */
199 InfrastructureLaneChangeInfoInaccessibleLane(final boolean deadEnd)
200 {
201 super(1, deadEnd);
202 }
203
204 /** {@inheritDoc} */
205 @Override
206 public Length getRemainingDistance()
207 {
208 return Length.ZERO;
209 }
210
211 }
212
213 }