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