1 package org.opentrafficsim.road.gtu.strategical;
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.djutils.exceptions.Throw;
11 import org.djutils.exceptions.Try;
12 import org.opentrafficsim.core.gtu.GtuException;
13 import org.opentrafficsim.core.gtu.GtuType;
14 import org.opentrafficsim.core.network.Link;
15 import org.opentrafficsim.core.network.NetworkException;
16 import org.opentrafficsim.core.network.Node;
17 import org.opentrafficsim.core.network.route.Route;
18 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
19 import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedTacticalPlanner;
20 import org.opentrafficsim.road.network.lane.CrossSectionLink;
21 import org.opentrafficsim.road.network.lane.Lane;
22 import org.opentrafficsim.road.network.lane.LanePosition;
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class LaneBasedStrategicalRoutePlanner implements LaneBasedStrategicalPlanner, Serializable
37 {
38
39 private static final long serialVersionUID = 20151126L;
40
41
42 private final LaneBasedGtu gtu;
43
44
45 private Route route;
46
47
48 private final Node origin;
49
50
51 private Node destination;
52
53
54 private final LaneBasedTacticalPlanner fixedTacticalPlanner;
55
56
57 private final RouteGenerator routeGenerator;
58
59
60
61
62
63
64
65
66 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final LaneBasedGtu gtu)
67 throws GtuException
68 {
69 this(fixedTacticalPlanner, null, gtu, null, null, RouteGenerator.NULL);
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83 public LaneBasedStrategicalRoutePlanner(final LaneBasedTacticalPlanner fixedTacticalPlanner, final Route route,
84 final LaneBasedGtu gtu, final Node origin, final Node destination, final RouteGenerator routeGenerator)
85 throws GtuException
86 {
87 this.gtu = gtu;
88 this.route = route;
89 this.origin = origin;
90 this.destination = destination;
91 this.fixedTacticalPlanner = fixedTacticalPlanner;
92 Throw.when(fixedTacticalPlanner == null, GtuException.class,
93 "Fixed Tactical Planner for a Strategical planner is null");
94 this.routeGenerator = routeGenerator;
95 }
96
97
98 @Override
99 public final LaneBasedGtu getGtu()
100 {
101 return this.gtu;
102 }
103
104
105 @Override
106 public final LaneBasedTacticalPlanner getTacticalPlanner()
107 {
108 return this.fixedTacticalPlanner;
109 }
110
111
112 @Override
113 public LaneBasedTacticalPlanner getTacticalPlanner(final Time time)
114 {
115 return this.fixedTacticalPlanner;
116 }
117
118
119 @Override
120 public final Link nextLink(final Link previousLink, final GtuType gtuType) throws NetworkException
121 {
122 assureRoute(gtuType);
123
124 Node node = previousLink.getEndNode();
125
126 if (node.getLinks().size() == 1 && previousLink != null)
127 {
128
129 throw new NetworkException(
130 "LaneBasedStrategicalRoutePlanner is asked for a next link, but node " + node + " has no successors");
131 }
132 if (node.getLinks().size() == 1 && previousLink == null)
133 {
134
135 return node.getLinks().iterator().next();
136 }
137 if (node.getLinks().size() == 2)
138 {
139 for (Link link : node.getLinks())
140 {
141 if (!link.equals(previousLink))
142 {
143 return link;
144 }
145 }
146 }
147
148
149 Set<Link> links = node.getLinks().toSet();
150 for (Iterator<Link> linkIterator = links.iterator(); linkIterator.hasNext();)
151 {
152 Link link = linkIterator.next();
153 if (link.equals(previousLink))
154 {
155
156 linkIterator.remove();
157 }
158 else
159 {
160
161 if (link.getEndNode().equals(node))
162 {
163 linkIterator.remove();
164 }
165 else
166 {
167
168 boolean out = false;
169 CrossSectionLink csLink = (CrossSectionLink) link;
170 for (Lane lane : csLink.getLanes())
171 {
172 if ((link.getStartNode().equals(node) && lane.getType().isCompatible(gtuType)))
173 {
174 out = true;
175 break;
176 }
177 }
178 if (!out)
179 {
180 linkIterator.remove();
181 }
182 }
183 }
184 }
185
186 if (links.size() == 1)
187 {
188 return links.iterator().next();
189 }
190
191
192 if (getRoute() == null)
193 {
194 throw new NetworkException("LaneBasedStrategicalRoutePlanner does not have a route");
195 }
196 int i = this.route.getNodes().indexOf(node);
197 if (i == -1)
198 {
199 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from " + previousLink
200 + ", but node " + node + " not in route " + this.route);
201 }
202 if (i == this.route.getNodes().size() - 1)
203 {
204 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from " + previousLink
205 + ", but the GTU reached the last node for route " + this.route);
206 }
207 Node nextNode = this.route.getNode(i + 1);
208 Link result = null;
209 for (Link link : links)
210 {
211
212
213 Link l = null;
214 if (link.getStartNode().equals(nextNode) && link.getEndNode().equals(node))
215 {
216 l = link;
217 }
218 if (link.getEndNode().equals(nextNode) && link.getStartNode().equals(node))
219 {
220 l = link;
221 }
222 if (null != result && null != l)
223 {
224 throw new NetworkException("Cannot choose among multiple links from " + node + " to " + nextNode);
225 }
226 else if (null == result)
227 {
228 result = l;
229 }
230 }
231 if (null == result)
232 {
233 throw new NetworkException("LaneBasedStrategicalRoutePlanner is asked for a next link coming from "
234 + previousLink.getId() + ", but no link could be found connecting node " + node + " and node " + nextNode
235 + " for route " + this.route);
236 }
237 return result;
238 }
239
240
241 @Override
242 public final Route getRoute()
243 {
244 assureRoute(getGtu().getType());
245
246 if (this.route == null && this.destination != null)
247 {
248 try
249 {
250 LanePosition pos = getGtu().getReferencePosition();
251 CrossSectionLink link = pos.lane().getLink();
252 Node from = link.getStartNode();
253 this.route = link.getNetwork().getShortestRouteBetween(getGtu().getType(), from, this.destination);
254 }
255 catch (GtuException | NetworkException exception)
256 {
257 throw new RuntimeException("Route could not be determined.", exception);
258 }
259 }
260 return this.route;
261 }
262
263
264
265
266
267 private void assureRoute(final GtuType gtuType)
268 {
269 if (this.route == null && this.destination != null && !this.routeGenerator.equals(RouteGenerator.NULL))
270 {
271 LanePosition ref = Try.assign(() -> getGtu().getReferencePosition(), "Could not retrieve GTU reference position.");
272 List<Node> nodes = new ArrayList<>();
273 if (this.origin != null)
274 {
275 nodes.addAll(this.routeGenerator.getRoute(this.origin, ref.lane().getLink().getStartNode(), gtuType)
276 .getNodes());
277 }
278 else
279 {
280 nodes.add(ref.lane().getLink().getStartNode());
281 }
282 Route newRoute =
283 this.routeGenerator.getRoute(ref.lane().getLink().getEndNode(), this.destination, gtuType);
284 nodes.addAll(newRoute.getNodes());
285 this.route = Try.assign(() -> new Route("Route for " + gtuType + " from " + this.origin + "to " + this.destination
286 + " via " + ref.lane().getLink(), gtuType, nodes), "No route possible over nodes %s", nodes);
287 }
288 }
289
290
291 @Override
292 public final Node getOrigin()
293 {
294 return this.origin;
295 }
296
297
298 @Override
299 public final Node getDestination()
300 {
301 return this.destination;
302 }
303
304
305 @Override
306 public final String toString()
307 {
308 return "LaneBasedStrategicalRoutePlanner [route=" + this.route + ", fixedTacticalPlanner=" + this.fixedTacticalPlanner
309 + "]";
310 }
311
312 }