1 package org.opentrafficsim.road.gtu.lane.tactical;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Iterator;
6 import java.util.LinkedHashSet;
7 import java.util.List;
8 import java.util.Set;
9
10 import org.djunits.value.vdouble.scalar.Length;
11 import org.opentrafficsim.base.OtsClassUtil;
12 import org.opentrafficsim.base.parameters.ParameterTypeClass;
13 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
14 import org.opentrafficsim.base.parameters.ParameterTypeLength;
15 import org.opentrafficsim.base.parameters.ParameterTypes;
16 import org.opentrafficsim.core.geometry.OtsGeometryException;
17 import org.opentrafficsim.core.geometry.OtsLine2d;
18 import org.opentrafficsim.core.gtu.GtuException;
19 import org.opentrafficsim.core.network.LateralDirectionality;
20 import org.opentrafficsim.core.network.Link;
21 import org.opentrafficsim.core.network.NetworkException;
22 import org.opentrafficsim.core.network.Node;
23 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
24 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
25 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
26 import org.opentrafficsim.road.gtu.lane.tactical.lmrs.Lmrs;
27 import org.opentrafficsim.road.network.lane.CrossSectionElement;
28 import org.opentrafficsim.road.network.lane.CrossSectionLink;
29 import org.opentrafficsim.road.network.lane.Lane;
30 import org.opentrafficsim.road.network.lane.LanePosition;
31
32
33
34
35
36
37
38
39
40
41
42
43 public abstract class AbstractLaneBasedTacticalPlanner implements LaneBasedTacticalPlanner, Serializable
44 {
45
46
47 public static final ParameterTypeClass<LaneBasedTacticalPlanner> TACTICAL_PLANNER;
48
49 static
50 {
51 Class<LaneBasedTacticalPlanner> type = LaneBasedTacticalPlanner.class;
52 TACTICAL_PLANNER = new ParameterTypeClass<>("tactical planner", "Tactical planner class.",
53 OtsClassUtil.getTypedClass(type), Lmrs.class);
54 }
55
56
57 private static final long serialVersionUID = 20151125L;
58
59
60 protected static final ParameterTypeLength LOOKAHEAD = ParameterTypes.LOOKAHEAD;
61
62
63 protected static final ParameterTypeDuration DT = ParameterTypes.DT;
64
65
66 private CarFollowingModel carFollowingModel;
67
68
69 private final LanePerception lanePerception;
70
71
72 private final LaneBasedGtu gtu;
73
74
75
76
77
78
79
80 public AbstractLaneBasedTacticalPlanner(final CarFollowingModel carFollowingModel, final LaneBasedGtu gtu,
81 final LanePerception lanePerception)
82 {
83 setCarFollowingModel(carFollowingModel);
84 this.gtu = gtu;
85 this.lanePerception = lanePerception;
86 }
87
88
89 @Override
90 public final LaneBasedGtu getGtu()
91 {
92 return this.gtu;
93 }
94
95
96
97
98
99
100
101
102
103
104 public static LanePathInfo buildLanePathInfo(final LaneBasedGtu gtu, final Length maxHeadway)
105 throws GtuException, NetworkException
106 {
107 LanePosition dlp = gtu.getReferencePosition();
108 return buildLanePathInfo(gtu, maxHeadway, dlp.lane(), dlp.position());
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public static LanePathInfo buildLanePathInfo(final LaneBasedGtu gtu, final Length maxHeadway, final Lane startLane,
125 final Length position) throws GtuException, NetworkException
126 {
127 List<Lane> laneListForward = new ArrayList<>();
128 Lane lane = startLane;
129 Length startPosition = position;
130 Lane lastLane = lane;
131 laneListForward.add(lastLane);
132 Length distanceToEndOfLane;
133 OtsLine2d path;
134 distanceToEndOfLane = lane.getLength().minus(position);
135 path = lane.getCenterLine().extract(position, lane.getLength());
136
137 while (distanceToEndOfLane.lt(maxHeadway))
138 {
139 Set<Lane> lanes = lane.nextLanes(gtu.getType());
140 if (lanes.size() == 0)
141 {
142
143 return new LanePathInfo(path, laneListForward, startPosition);
144 }
145 else if (lanes.size() == 1)
146 {
147
148
149 Link link = gtu.getStrategicalPlanner().nextLink(lane.getLink(), gtu.getType());
150 lane = lanes.iterator().next();
151 if (link != null && !lane.getLink().equals(link))
152 {
153
154 return new LanePathInfo(path, laneListForward, startPosition);
155 }
156 }
157 else
158 {
159
160
161 Link link;
162 try
163 {
164 link = gtu.getStrategicalPlanner().nextLink(lane.getLink(), gtu.getType());
165 }
166 catch (NetworkException ne)
167 {
168
169 return new LanePathInfo(path, laneListForward, startPosition);
170 }
171 Link nextLink = link;
172 Lane newLane = null;
173 for (Lane nextLane : lanes)
174 {
175 if (nextLane.getLink().equals(nextLink))
176 {
177 newLane = nextLane;
178 break;
179 }
180 }
181 if (newLane == null)
182 {
183
184
185 return new LanePathInfo(path, laneListForward, startPosition);
186 }
187
188 lane = newLane;
189 }
190
191
192 try
193 {
194 path = concatenateNull(path, lane.getCenterLine());
195
196 }
197 catch (OtsGeometryException exception)
198 {
199 throw new GtuException(exception);
200 }
201
202 laneListForward.add(lastLane);
203 distanceToEndOfLane = distanceToEndOfLane.plus(lastLane.getLength());
204
205 }
206 return new LanePathInfo(path, laneListForward, startPosition);
207 }
208
209
210
211
212
213
214
215
216 public static OtsLine2d concatenateNull(final OtsLine2d path, final OtsLine2d centerLine) throws OtsGeometryException
217 {
218 if (path == null)
219 {
220 return centerLine;
221 }
222 return OtsLine2d.concatenate(Lane.MARGIN.si, path, centerLine);
223 }
224
225
226
227
228
229
230
231
232
233
234
235 public static NextSplitInfo determineNextSplit(final LaneBasedGtu gtu, final Length maxHeadway)
236 throws GtuException, NetworkException
237 {
238 Node nextSplitNode = null;
239 Set<Lane> correctCurrentLanes = new LinkedHashSet<>();
240 LanePosition dlp = gtu.getReferencePosition();
241 Lane referenceLane = dlp.lane();
242 double refFrac = dlp.position().si / referenceLane.getLength().si;
243 Link lastLink = referenceLane.getLink();
244 Length position = dlp.position();
245 Length lengthForward = referenceLane.getLength().minus(position);
246 Node lastNode = referenceLane.getLink().getEndNode();
247
248
249 while (lengthForward.lt(maxHeadway) && nextSplitNode == null)
250 {
251
252 Set<Link> links = lastNode.getLinks().toSet();
253 Iterator<Link> linkIterator = links.iterator();
254 while (linkIterator.hasNext())
255 {
256 Link link = linkIterator.next();
257 if (!link.getType().isCompatible(gtu.getType()) || link.getEndNode().equals(lastNode))
258 {
259 linkIterator.remove();
260 }
261 }
262
263
264 boolean laneChange = false;
265 if (links.size() == 1)
266 {
267 for (CrossSectionElement cse : ((CrossSectionLink) lastLink).getCrossSectionElementList())
268 {
269 if (cse instanceof Lane)
270 {
271 Lane lane = (Lane) cse;
272 if (lane.nextLanes(gtu.getType()).size() == 0)
273 {
274 laneChange = true;
275 }
276 }
277 }
278 }
279
280
281 if (laneChange)
282 {
283 nextSplitNode = lastNode;
284
285
286 for (CrossSectionElement cse : referenceLane.getLink().getCrossSectionElementList())
287 {
288 if (cse instanceof Lane)
289 {
290 Lane l = (Lane) cse;
291 if (noLaneDrop(gtu, maxHeadway, l, l.getLength().times(refFrac)))
292 {
293 correctCurrentLanes.add(l);
294 }
295 }
296 }
297 return new NextSplitInfo(nextSplitNode, correctCurrentLanes);
298 }
299
300
301 if (links.size() > 1)
302 {
303 nextSplitNode = lastNode;
304 Link nextLink = gtu.getStrategicalPlanner().nextLink(lastLink, gtu.getType());
305
306
307 for (CrossSectionElement cse : referenceLane.getLink().getCrossSectionElementList())
308 {
309 if (cse instanceof Lane)
310 {
311 Lane l = (Lane) cse;
312 if (connectsToPath(gtu, maxHeadway, l, l.getLength().times(refFrac), nextLink))
313 {
314 correctCurrentLanes.add(l);
315 }
316 }
317 }
318 if (correctCurrentLanes.size() > 0)
319 {
320 return new NextSplitInfo(nextSplitNode, correctCurrentLanes);
321 }
322
323 Set<Lane> correctLanes = new LinkedHashSet<>();
324 Set<Lane> wrongLanes = new LinkedHashSet<>();
325 for (CrossSectionElement cse : ((CrossSectionLink) lastLink).getCrossSectionElementList())
326 {
327 if (cse instanceof Lane)
328 {
329 Lane l = (Lane) cse;
330 if (connectsToPath(gtu, maxHeadway.plus(l.getLength()), l, Length.ZERO, nextLink))
331 {
332 correctLanes.add(l);
333 }
334 else
335 {
336 wrongLanes.add(l);
337 }
338 }
339 }
340 for (Lane wrongLane : wrongLanes)
341 {
342 for (Lane adjLane : wrongLane.accessibleAdjacentLanesLegal(LateralDirectionality.LEFT, gtu.getType()))
343 {
344 if (correctLanes.contains(adjLane))
345 {
346 return new NextSplitInfo(nextSplitNode, correctCurrentLanes, LateralDirectionality.LEFT);
347 }
348 }
349 for (Lane adjLane : wrongLane.accessibleAdjacentLanesLegal(LateralDirectionality.RIGHT, gtu.getType()))
350 {
351 if (correctLanes.contains(adjLane))
352 {
353 return new NextSplitInfo(nextSplitNode, correctCurrentLanes, LateralDirectionality.RIGHT);
354 }
355 }
356 }
357 return new NextSplitInfo(nextSplitNode, correctCurrentLanes, null);
358 }
359
360 if (links.size() == 0)
361 {
362 return new NextSplitInfo(null, correctCurrentLanes);
363 }
364
365
366 Link link = links.iterator().next();
367
368
369 lastNode = link.getEndNode();
370 lastLink = links.iterator().next();
371 lengthForward = lengthForward.plus(lastLink.getLength());
372 }
373
374 return new NextSplitInfo(null, correctCurrentLanes);
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388
389 protected static boolean connectsToPath(final LaneBasedGtu gtu, final Length maxHeadway, final Lane startLane,
390 final Length startLanePosition, final Link linkAfterSplit) throws GtuException, NetworkException
391 {
392 List<Lane> lanes = buildLanePathInfo(gtu, maxHeadway, startLane, startLanePosition).laneList();
393 for (Lane lane : lanes)
394 {
395 if (lane.getLink().equals(linkAfterSplit))
396 {
397 return true;
398 }
399 }
400 return false;
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414 protected static boolean noLaneDrop(final LaneBasedGtu gtu, final Length maxHeadway, final Lane startLane,
415 final Length startLanePosition) throws GtuException, NetworkException
416 {
417 LanePathInfo lpi = buildLanePathInfo(gtu, maxHeadway, startLane, startLanePosition);
418 if (lpi.path().getLength().lt(maxHeadway))
419 {
420 return false;
421 }
422 return true;
423 }
424
425
426
427
428
429
430
431
432
433 protected static List<Link> buildLinkListForward(final LaneBasedGtu gtu, final Length maxHeadway)
434 throws GtuException, NetworkException
435 {
436 List<Link> linkList = new ArrayList<>();
437 LanePosition dlp = gtu.getReferencePosition();
438 Lane referenceLane = dlp.lane();
439 Link lastLink = referenceLane.getLink();
440 linkList.add(lastLink);
441 Length position = dlp.position();
442 Length lengthForward = referenceLane.getLength().minus(position);
443 Node lastNode = referenceLane.getLink().getEndNode();
444
445
446 while (lengthForward.lt(maxHeadway))
447 {
448
449 Set<Link> links = lastNode.getLinks().toSet();
450 Iterator<Link> linkIterator = links.iterator();
451 while (linkIterator.hasNext())
452 {
453 Link link = linkIterator.next();
454 if (link.equals(lastLink) || !link.getType().isCompatible(gtu.getType()))
455 {
456 linkIterator.remove();
457 }
458 }
459 if (links.size() == 0)
460 {
461 return linkList;
462 }
463
464 Link link;
465 if (links.size() > 1)
466 {
467 link = gtu.getStrategicalPlanner().nextLink(lastLink, gtu.getType());
468 }
469 else
470 {
471 link = links.iterator().next();
472 }
473
474
475 lastNode = lastLink.getEndNode();
476 lastLink = link;
477 linkList.add(lastLink);
478 lengthForward = lengthForward.plus(lastLink.getLength());
479 }
480 return linkList;
481 }
482
483
484 @Override
485 public final CarFollowingModel getCarFollowingModel()
486 {
487 return this.carFollowingModel;
488 }
489
490
491
492
493
494 public final void setCarFollowingModel(final CarFollowingModel carFollowingModel)
495 {
496 this.carFollowingModel = carFollowingModel;
497 }
498
499
500 @Override
501 public final LanePerception getPerception()
502 {
503 return this.lanePerception;
504 }
505
506 }