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