1 package org.opentrafficsim.animation;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.Iterator;
7 import java.util.LinkedHashMap;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12
13 import org.djunits.value.vdouble.scalar.Length;
14 import org.djunits.value.vdouble.scalar.Speed;
15 import org.djutils.exceptions.Throw;
16 import org.opentrafficsim.core.network.Link;
17 import org.opentrafficsim.core.network.LinkPosition;
18 import org.opentrafficsim.core.network.NetworkException;
19 import org.opentrafficsim.draw.graphs.GraphCrossSection;
20 import org.opentrafficsim.draw.graphs.GraphPath;
21 import org.opentrafficsim.draw.graphs.GraphPath.Section;
22 import org.opentrafficsim.road.network.lane.CrossSectionLink;
23 import org.opentrafficsim.road.network.lane.Lane;
24 import org.opentrafficsim.road.network.lane.LanePosition;
25 import org.opentrafficsim.road.network.lane.Shoulder;
26 import org.opentrafficsim.road.network.sampling.LaneDataRoad;
27
28
29
30
31
32
33
34
35
36
37
38 public final class GraphLaneUtil
39 {
40
41
42
43
44 private GraphLaneUtil()
45 {
46
47 }
48
49
50
51
52
53
54
55
56 public static GraphPath<LaneDataRoad> createPath(final String name, final Lane first) throws NetworkException
57 {
58 return createPath(name, first, null);
59 }
60
61
62
63
64
65
66
67
68
69 public static GraphPath<LaneDataRoad> createPath(final String name, final Lane first, final Lane last)
70 throws NetworkException
71 {
72 Throw.whenNull(name, "Name may not be null.");
73 Throw.whenNull(first, "First may not be null.");
74 List<Section<LaneDataRoad>> sections = new ArrayList<>();
75 Set<Lane> set = new LinkedHashSet<>();
76 Lane lane = first;
77 do
78 {
79 LaneDataRoad laneData = new LaneDataRoad(lane);
80 List<LaneDataRoad> list = new ArrayList<>();
81 list.add(laneData);
82 Speed speed = lane.getLowestSpeedLimit();
83 Length length = lane.getLength();
84 sections.add(new Section<>(length, speed, list));
85 set.add(lane);
86 Set<Lane> nextLaneSet = lane.nextLanes(null);
87 if (nextLaneSet.size() == 1 && !(nextLaneSet.iterator().next() instanceof Shoulder))
88 {
89 lane = nextLaneSet.iterator().next();
90 }
91 }
92 while (lane != null && !set.contains(lane) && !lane.equals(last));
93 return new GraphPath<>(name, sections);
94 }
95
96
97
98
99
100
101
102
103
104 public static GraphPath<LaneDataRoad> createPath(final List<String> names, final List<Lane> first) throws NetworkException
105 {
106 return createPath(names, first, Collections.emptyList());
107 }
108
109
110
111
112
113
114
115
116
117
118
119 public static GraphPath<LaneDataRoad> createPath(final List<String> names, final List<Lane> first, final List<Lane> last)
120 throws NetworkException
121 {
122 Throw.whenNull(names, "Names may not be null.");
123 Throw.whenNull(first, "First may not be null.");
124 Throw.when(names.size() != first.size(), IllegalArgumentException.class, "Size of 'names' and 'first' must be equal.");
125 List<Section<LaneDataRoad>> sections = new ArrayList<>();
126 Set<Lane> seenLanes = new LinkedHashSet<>();
127 List<Lane> currentLanes = first;
128 while (currentLanes != null && Collections.disjoint(seenLanes, currentLanes) && Collections.disjoint(seenLanes, last))
129 {
130
131 List<LaneDataRoad> sectionLanes = new ArrayList<>();
132 Speed sectionSpeed = null;
133 for (Lane lane : currentLanes)
134 {
135 if (lane == null)
136 {
137 sectionLanes.add(null);
138 }
139 else
140 {
141 sectionSpeed = sectionSpeed == null ? lane.getLowestSpeedLimit()
142 : Speed.min(sectionSpeed, lane.getLowestSpeedLimit());
143 sectionLanes.add(new LaneDataRoad(lane));
144 seenLanes.add(lane);
145 }
146 }
147 Lane firstCurrentLane = currentLanes.stream().filter((l) -> l != null).findFirst().get();
148 Length sectionLength = firstCurrentLane.getLength();
149 sections.add(new Section<>(sectionLength, sectionSpeed, sectionLanes));
150
151
152 Map<Link, List<Lane>> nextLinks = new LinkedHashMap<>();
153 Link link = firstCurrentLane.getLink();
154 for (Link nextLink : link.getEndNode().getLinks())
155 {
156 if (!link.equals(nextLink))
157 {
158 List<Lane> nextLanes = new ArrayList<>();
159 for (Lane currentLane : currentLanes)
160 {
161 Set<Lane> nextLanesOfLane = currentLane.nextLanes(null);
162 int n = 0;
163 for (Lane nextLane : nextLanesOfLane)
164 {
165 if (nextLane.getLink().equals(nextLink))
166 {
167 n++;
168 nextLanes.add(nextLane);
169 }
170 }
171 if (n > 1)
172 {
173
174 nextLanes.clear();
175 break;
176 }
177 else if (n == 0)
178 {
179 nextLanes.add(null);
180 }
181 }
182 if (nextLanes.size() == currentLanes.size())
183 {
184 nextLinks.put(nextLink, nextLanes);
185 }
186 }
187 }
188
189 if (nextLinks.size() > 1)
190 {
191 Iterator<List<Lane>> it = nextLinks.values().iterator();
192 while (it.hasNext())
193 {
194 if (it.next().contains(null))
195 {
196 it.remove();
197 }
198 }
199 }
200 if (nextLinks.size() == 1)
201 {
202 currentLanes = nextLinks.values().iterator().next();
203 }
204 else
205 {
206 currentLanes = null;
207 }
208 }
209 return new GraphPath<>(names, sections);
210 }
211
212
213
214
215
216
217
218
219 public static GraphPath<LaneDataRoad> createSingleLanePath(final String name, final Lane lane) throws NetworkException
220 {
221 List<LaneDataRoad> lanes = new ArrayList<>();
222 lanes.add(new LaneDataRoad(lane));
223 List<Section<LaneDataRoad>> sections = new ArrayList<>();
224 Speed speed = lane.getLowestSpeedLimit();
225 sections.add(new Section<>(lane.getLength(), speed, lanes));
226 return new GraphPath<>(name, sections);
227 }
228
229
230
231
232
233
234
235
236 public static GraphCrossSection<LaneDataRoad> createCrossSection(final String name, final LanePosition lanePosition)
237 throws NetworkException
238 {
239 Throw.whenNull(name, "Name may not be null.");
240 Throw.whenNull(lanePosition, "Lane position may not be null.");
241 List<LaneDataRoad> list = new ArrayList<>();
242 List<String> names = new ArrayList<>();
243 List<Length> positions = new ArrayList<>();
244 names.add(name);
245 positions.add(lanePosition.position());
246 list.add(new LaneDataRoad(lanePosition.lane()));
247 Speed speed = lanePosition.lane().getLowestSpeedLimit();
248 return createCrossSection(names, list, positions, speed);
249 }
250
251
252
253
254
255
256
257
258 public static GraphCrossSection<LaneDataRoad> createCrossSection(final List<String> names, final LinkPosition linkPosition)
259 throws NetworkException
260 {
261 Throw.whenNull(names, "Names may not be null.");
262 Throw.whenNull(linkPosition, "Link position may not be null.");
263 Throw.when(!(linkPosition.link() instanceof CrossSectionLink), IllegalArgumentException.class,
264 "The link is not a CrossEctionLink.");
265 List<Lane> lanes = ((CrossSectionLink) linkPosition.link()).getLanes();
266 Throw.when(names.size() != lanes.size(), IllegalArgumentException.class,
267 "Size of 'names' not equal to the number of lanes.");
268 Collections.sort(lanes, new Comparator<Lane>()
269 {
270
271 @Override
272 public int compare(final Lane o1, final Lane o2)
273 {
274 return o1.getOffsetAtBegin().compareTo(o2.getOffsetAtEnd());
275 }
276
277 });
278 List<LaneDataRoad> list = new ArrayList<>();
279 List<Length> positions = new ArrayList<>();
280 Speed speed = null;
281 for (Lane lane : lanes)
282 {
283 speed = speed == null ? lane.getLowestSpeedLimit() : Speed.min(speed, lane.getLowestSpeedLimit());
284 list.add(new LaneDataRoad(lane));
285 positions.add(lane.getLength().times(linkPosition.fractionalLongitudinalPosition()));
286 }
287 return createCrossSection(names, list, positions, speed);
288 }
289
290
291
292
293
294
295
296
297
298 public static GraphCrossSection<LaneDataRoad> createCrossSection(final List<String> names, final List<LaneDataRoad> lanes,
299 final List<Length> positions, final Speed speed)
300 {
301 Section<LaneDataRoad> section = new Section<>(lanes.get(0).getLength(), speed, lanes);
302 return new GraphCrossSection<>(names, section, positions);
303 }
304
305 }