1 package org.opentrafficsim.road.gtu.strategical.route;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Set;
8
9 import org.djunits.value.vdouble.scalar.Time;
10 import org.opentrafficsim.core.gtu.GTUDirectionality;
11 import org.opentrafficsim.core.gtu.GTUException;
12 import org.opentrafficsim.core.gtu.GTUType;
13 import org.opentrafficsim.core.gtu.Try;
14 import org.opentrafficsim.core.network.Link;
15 import org.opentrafficsim.core.network.LinkDirection;
16 import org.opentrafficsim.core.network.NetworkException;
17 import org.opentrafficsim.core.network.Node;
18 import org.opentrafficsim.core.network.route.CompleteRoute;
19 import org.opentrafficsim.core.network.route.Route;
20 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
21 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlanner;
22 import org.opentrafficsim.road.gtu.strategical.AbstractLaneBasedStrategicalPlanner;
23 import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
24 import org.opentrafficsim.road.network.lane.CrossSectionElement;
25 import org.opentrafficsim.road.network.lane.CrossSectionLink;
26 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
27 import org.opentrafficsim.road.network.lane.Lane;
28
29 import nl.tudelft.simulation.language.Throw;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class LaneBasedStrategicalRoutePlanner extends AbstractLaneBasedStrategicalPlanner
46 implements LaneBasedStrategicalPlanner, Serializable
47 {
48
49 private static final long serialVersionUID = 20150724L;
50
51
52 private Route route;
53
54
55 private final Node origin;
56
57
58 private final Node destination;
59
60
61 private final LaneBasedTacticalPlanner fixedTacticalPlanner;
62
63
64 private final RouteSupplier routeSupplier;
65
66
67
68
69
70
71
72
73 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final LaneBasedGTU gtu)
74 throws GTUException
75 {
76 this(fixedTacticalPlanner, null, gtu, null, null, RouteSupplier.NULL);
77 }
78
79
80
81
82
83
84
85
86
87
88 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final Route route,
89 final LaneBasedGTU gtu, final Node origin, final Node destination) throws GTUException
90 {
91 this(fixedTacticalPlanner, route, gtu, origin, destination, RouteSupplier.NULL);
92 }
93
94
95
96
97
98
99
100
101
102
103 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final LaneBasedGTU gtu,
104 final Node origin, final Node destination, final RouteSupplier routeSupplier) throws GTUException
105 {
106 this(fixedTacticalPlanner, null, gtu, origin, destination, routeSupplier);
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final Route route,
121 final LaneBasedGTU gtu, final Node origin, final Node destination, final RouteSupplier routeSupplier)
122 throws GTUException
123 {
124 super(gtu);
125 this.route = route;
126 this.origin = origin;
127 this.destination = destination;
128 this.fixedTacticalPlanner = fixedTacticalPlanner;
129 Throw.when(fixedTacticalPlanner == null, GTUException.class,
130 "Fixed Tactical Planner for a Strategical planner is null");
131 this.routeSupplier = routeSupplier;
132 }
133
134
135 @Override
136 public final LaneBasedTacticalPlanner getTacticalPlanner()
137 {
138 return this.fixedTacticalPlanner;
139 }
140
141
142 @Override
143 public LaneBasedTacticalPlanner getTacticalPlanner(final Time time)
144 {
145 return this.fixedTacticalPlanner;
146 }
147
148
149 @Override
150 public final Node nextNode(final Link link, final GTUDirectionality direction, final GTUType gtuType)
151 throws NetworkException
152 {
153 assureRoute(gtuType);
154 LinkDirection linkDirection = nextLinkDirection(link, direction, gtuType);
155 return linkDirection.getNodeTo();
156 }
157
158
159 @Override
160 public final LinkDirection nextLinkDirection(final Link link, final GTUDirectionality direction, final GTUType gtuType)
161 throws NetworkException
162 {
163 assureRoute(gtuType);
164 Node nextNode = direction.equals(GTUDirectionality.DIR_PLUS) ? link.getEndNode() : link.getStartNode();
165 return nextLinkDirection(nextNode, link, gtuType);
166 }
167
168
169 @Override
170 public final Node nextNode(final Node node, final Link previousLink, final GTUType gtuType) throws NetworkException
171 {
172 assureRoute(gtuType);
173 LinkDirection linkDirection = nextLinkDirection(node, previousLink, gtuType);
174 return linkDirection.getNodeTo();
175 }
176
177
178 @Override
179 public final LinkDirection nextLinkDirection(final Node node, final Link previousLink, final GTUType gtuType)
180 throws NetworkException
181 {
182 assureRoute(gtuType);
183
184
185 if (node.getLinks().size() == 1 && previousLink != null)
186 {
187
188 throw new NetworkException(
189 "LaneBasedStrategicalRoutePlanner is asked for a next link, but node " + node + " has no successors");
190 }
191 if (node.getLinks().size() == 1 && previousLink == null)
192 {
193
194 Link link = node.getLinks().iterator().next();
195 return link.getStartNode().equals(node) ? new LinkDirection(link, GTUDirectionality.DIR_PLUS)
196 : new LinkDirection(link, GTUDirectionality.DIR_MINUS);
197 }
198 if (node.getLinks().size() == 2)
199 {
200 for (Link link : node.getLinks())
201 {
202 if (!link.equals(previousLink))
203 {
204 return link.getStartNode().equals(node) ? new LinkDirection(link, GTUDirectionality.DIR_PLUS)
205 : new LinkDirection(link, GTUDirectionality.DIR_MINUS);
206 }
207 }
208 }
209
210
211 Set<Link> links = node.getLinks().toSet();
212 for (Iterator<Link> linkIterator = links.iterator(); linkIterator.hasNext();)
213 {
214 Link link = linkIterator.next();
215 if (link.equals(previousLink))
216 {
217
218 linkIterator.remove();
219 }
220 else
221 {
222
223 if ((link.getStartNode().equals(node) && !link.getDirectionality(gtuType).isForwardOrBoth())
224 || (link.getEndNode().equals(node) && !link.getDirectionality(gtuType).isBackwardOrBoth()))
225 {
226 linkIterator.remove();
227 }
228 else
229 {
230
231 boolean out = false;
232 CrossSectionLink csLink = (CrossSectionLink) link;
233
234 for (CrossSectionElement cse : csLink.getCrossSectionElementList())
235 {
236 if (cse instanceof Lane)
237 {
238 Lane lane = (Lane) cse;
239 if ((link.getStartNode().equals(node)
240 && lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_PLUS))
241 || (link.getEndNode().equals(node)
242 && lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_MINUS)))
243 {
244 out = true;
245 }
246 }
247 }
248 if (!out)
249 {
250 linkIterator.remove();
251 }
252 }
253 }
254 }
255
256 if (links.size() == 1)
257 {
258 Link link = links.iterator().next();
259 return link.getStartNode().equals(node) ? new LinkDirection(link, GTUDirectionality.DIR_PLUS)
260 : new LinkDirection(link, GTUDirectionality.DIR_MINUS);
261 }
262
263
264 if (getRoute() == null)
265 {
266 throw new NetworkException("LaneBasedStrategicalRoutePlanner does not have a route");
267 }
268 int i = this.route.getNodes().indexOf(node);
269 if (i == -1)
270 {
271 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from " + previousLink
272 + ", but node " + node + " not in route " + this.route);
273 }
274 if (i == this.route.getNodes().size() - 1)
275 {
276 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from " + previousLink
277 + ", but the GTU reached the last node for route " + this.route);
278 }
279 Node nextNode = this.route.getNode(i + 1);
280 LinkDirection result = null;
281 for (Link link : links)
282 {
283
284
285 LinkDirection ld = null;
286 if (link.getStartNode().equals(nextNode) && link.getEndNode().equals(node))
287 {
288 ld = new LinkDirection(link, GTUDirectionality.DIR_MINUS);
289 }
290 if (link.getEndNode().equals(nextNode) && link.getStartNode().equals(node))
291 {
292 ld = new LinkDirection(link, GTUDirectionality.DIR_PLUS);
293 }
294 if (null != result && null != ld)
295 {
296 throw new NetworkException("Cannot choose among multiple links from " + node + " to " + nextNode);
297 }
298 else if (null == result)
299 {
300 result = ld;
301 }
302 }
303 if (null == result)
304 {
305 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from "
306 + previousLink.getId() + ", but no link could be found connecting node " + node + " and node " + nextNode
307 + " for route " + this.route);
308 }
309 return result;
310 }
311
312
313 @Override
314 public final Route getRoute()
315 {
316 assureRoute(getGtu().getGTUType());
317 if (this.route == null && this.destination != null)
318 {
319 try
320 {
321 DirectedLanePosition pos = getGtu().getReferencePosition();
322 CrossSectionLink link = pos.getLane().getParentLink();
323 Node from = pos.getGtuDirection().isPlus() ? link.getStartNode() : link.getEndNode();
324 this.route = link.getNetwork().getShortestRouteBetween(getGtu().getGTUType(), from, this.destination);
325 }
326 catch (GTUException | NetworkException exception)
327 {
328 throw new RuntimeException("Route could not be determined.", exception);
329 }
330 }
331 return this.route;
332 }
333
334
335
336
337
338 private void assureRoute(final GTUType gtuType)
339 {
340 if (this.route == null && this.destination != null && !this.routeSupplier.equals(RouteSupplier.NULL))
341 {
342 DirectedLanePosition ref = Try.assign(() -> getGtu().getReferencePosition(), "GTU could not be obtained.");
343 List<Node> nodes = new ArrayList<>();
344 if (this.origin != null)
345 {
346 nodes.addAll(
347 this.routeSupplier.getRoute(this.origin, ref.getLinkDirection().getNodeFrom(), gtuType).getNodes());
348 }
349 else
350 {
351 nodes.add(ref.getLinkDirection().getNodeFrom());
352 }
353
354
355
356 nodes.addAll(this.routeSupplier.getRoute(ref.getLinkDirection().getNodeTo(), this.destination, gtuType).getNodes());
357 this.route =
358 Try.assign(
359 () -> new CompleteRoute("Route for " + gtuType + " from " + this.origin + "to " + this.destination
360 + " via " + ref.getLinkDirection(), gtuType, nodes),
361 "No route possible over nodes %s", nodes);
362
363 }
364 }
365
366
367 @Override
368 public final Node getOrigin()
369 {
370 return this.origin;
371 }
372
373
374 @Override
375 public final Node getDestination()
376 {
377 return this.destination;
378 }
379
380
381 @Override
382 public final String toString()
383 {
384 return "LaneBasedStrategicalRoutePlanner [route=" + this.route + ", fixedTacticalPlanner=" + this.fixedTacticalPlanner
385 + "]";
386 }
387
388 }