1 package org.opentrafficsim.road.network.lane;
2
3 import java.io.Serializable;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Set;
7
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.opentrafficsim.core.geometry.OTSGeometryException;
10 import org.opentrafficsim.core.gtu.GTUDirectionality;
11 import org.opentrafficsim.core.gtu.Try;
12 import org.opentrafficsim.core.network.LateralDirectionality;
13 import org.opentrafficsim.core.network.LinkDirection;
14 import org.opentrafficsim.core.network.NetworkException;
15 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
16
17 import nl.tudelft.simulation.language.d3.DirectedPoint;
18
19
20
21
22
23
24
25
26
27
28
29 public class LaneDirection implements Serializable
30 {
31
32 private static final long serialVersionUID = 20160330L;
33
34
35 private final Lane lane;
36
37
38 private final GTUDirectionality direction;
39
40
41
42
43
44 public LaneDirection(final Lane lane, final GTUDirectionality direction)
45 {
46 super();
47 this.lane = lane;
48 this.direction = direction;
49 }
50
51
52
53
54 public final Lane getLane()
55 {
56 return this.lane;
57 }
58
59
60
61
62 public final GTUDirectionality getDirection()
63 {
64 return this.direction;
65 }
66
67
68
69
70
71
72 public final Length coveredDistance(final double fraction)
73 {
74 if (this.direction.isPlus())
75 {
76 return getLane().getLength().multiplyBy(fraction);
77 }
78 return getLane().getLength().multiplyBy(1.0 - fraction);
79 }
80
81
82
83
84
85
86 public final Length remainingDistance(final double fraction)
87 {
88 if (this.direction.isPlus())
89 {
90 return getLane().getLength().multiplyBy(1.0 - fraction);
91 }
92 return getLane().getLength().multiplyBy(fraction);
93 }
94
95
96
97
98
99
100 public final double fractionAtCoveredDistance(final Length distance)
101 {
102 double f = this.lane.fraction(distance);
103 if (this.getDirection().isMinus())
104 {
105 f = 1.0 - f;
106 }
107 return f;
108 }
109
110
111
112
113
114
115 public final LaneDirection getNextLaneDirection(final LaneBasedGTU gtu)
116 {
117 Map<Lane, GTUDirectionality> next = this.lane.downstreamLanes(this.direction, gtu.getGTUType());
118 if (next.isEmpty())
119 {
120 return null;
121 }
122
123 LinkDirection ld;
124 try
125 {
126 ld = gtu.getStrategicalPlanner().nextLinkDirection(this.lane.getParentLink(), this.direction, gtu.getGTUType());
127 }
128 catch (NetworkException exception)
129 {
130 throw new RuntimeException("Strategical planner experiences exception on network.", exception);
131 }
132 Set<LaneDirection> out = new HashSet<>();
133 for (Lane l : next.keySet())
134 {
135 GTUDirectionality dir = next.get(l);
136 if (l.getParentLink().equals(ld.getLink()) && dir.equals(ld.getDirection()))
137 {
138 out.add(new LaneDirection(l, dir));
139 }
140 }
141 if (out.isEmpty())
142 {
143 return null;
144 }
145 else if (out.size() == 1)
146 {
147 return out.iterator().next();
148 }
149 else
150 {
151
152 return Try.assign(() -> gtu.getTacticalPlanner().chooseLaneAtSplit(out), "Missing parameter.");
153 }
154 }
155
156
157
158
159
160 public Length getLength()
161 {
162 return this.lane.getLength();
163 }
164
165
166
167
168
169
170
171 public DirectedPoint getLocationFraction(final double fraction) throws OTSGeometryException
172 {
173 DirectedPoint p = this.lane.getCenterLine().getLocationFraction(fraction);
174 if (this.direction.isMinus())
175 {
176 p.setRotZ(p.getRotZ() + Math.PI);
177 }
178 return p;
179 }
180
181
182
183
184
185
186
187 public final LaneDirection getAdjacentLaneDirection(final LateralDirectionality laneChangeDirection, final LaneBasedGTU gtu)
188 {
189 Set<Lane> adjLanes = this.lane.accessibleAdjacentLanesLegal(laneChangeDirection, gtu.getGTUType(), this.direction);
190 if (!adjLanes.isEmpty())
191 {
192 return new LaneDirection(adjLanes.iterator().next(), this.direction);
193 }
194 return null;
195 }
196
197
198 @Override
199 public final String toString()
200 {
201 return "[" + this.lane + (this.direction.isPlus() ? " +]" : " -]");
202 }
203
204
205 @Override
206 public final int hashCode()
207 {
208 final int prime = 31;
209 int result = 1;
210 result = prime * result + ((this.direction == null) ? 0 : this.direction.hashCode());
211 result = prime * result + ((this.lane == null) ? 0 : this.lane.hashCode());
212 return result;
213 }
214
215
216 @Override
217 public final boolean equals(final Object obj)
218 {
219 if (this == obj)
220 {
221 return true;
222 }
223 if (obj == null)
224 {
225 return false;
226 }
227 if (getClass() != obj.getClass())
228 {
229 return false;
230 }
231 LaneDirection other = (LaneDirection) obj;
232 if (this.direction != other.direction)
233 {
234 return false;
235 }
236 if (this.lane == null)
237 {
238 if (other.lane != null)
239 {
240 return false;
241 }
242 }
243 else if (!this.lane.equals(other.lane))
244 {
245 return false;
246 }
247 return true;
248 }
249
250 }