1 package org.opentrafficsim.road.gtu.strategical.route;
2
3 import java.util.ArrayList;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.djutils.exceptions.Throw;
9 import org.djutils.exceptions.Try;
10 import org.djutils.multikeymap.MultiKeyMap;
11 import org.opentrafficsim.core.gtu.GTUDirectionality;
12 import org.opentrafficsim.core.gtu.GTUType;
13 import org.opentrafficsim.core.math.Draw;
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.network.lane.CrossSectionLink;
19
20 import nl.tudelft.simulation.jstats.streams.StreamInterface;
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public interface RouteGeneratorOD
35 {
36
37 RouteGeneratorOD NULL = new RouteGeneratorOD()
38 {
39 @Override
40 public Route getRoute(final Node origin, final Node destination, final GTUType gtuType)
41 {
42 return null;
43 }
44 };
45
46
47 Map<StreamInterface, RouteGeneratorOD> DEFAULT_MAP = new LinkedHashMap<>();
48
49
50
51
52
53
54 static RouteGeneratorOD getDefaultRouteSupplier(final StreamInterface stream)
55 {
56 RouteGeneratorOD def = DEFAULT_MAP.get(stream);
57 if (def == null)
58 {
59 def = new DefaultRouteGenerator(stream);
60 DEFAULT_MAP.put(stream, def);
61 }
62 return def;
63 }
64
65
66 class DefaultRouteGenerator implements RouteGeneratorOD
67 {
68
69 private MultiKeyMap<Route> shortestRouteCache = new MultiKeyMap<>(GTUType.class, Node.class, Node.class, List.class);
70
71
72 private final StreamInterface stream;
73
74
75
76
77
78 public DefaultRouteGenerator(final StreamInterface stream)
79 {
80 Throw.whenNull(stream, "Stream may not be null.");
81 this.stream = stream;
82 }
83
84 @Override
85 public Route getRoute(final Node origin, final Node destination, final GTUType gtuType)
86 {
87 List<Node> viaNodes = new ArrayList<>();
88 double cumulWeight = 0.0;
89 List<Double> weights = new ArrayList<>();
90 Map<Link, Double> links = new LinkedHashMap<>();
91 boolean directLinkExists = false;
92 for (Link link : destination.getLinks())
93 {
94 GTUDirectionality direction =
95 link.getEndNode().equals(destination) ? GTUDirectionality.DIR_PLUS : GTUDirectionality.DIR_MINUS;
96 if (link.getLinkType().isConnector() && link.getDirectionality(gtuType).permits(direction)
97 && link instanceof CrossSectionLink && ((CrossSectionLink) link).getDemandWeight() != null)
98 {
99
100 List<Node> testViaNode = new ArrayList<>();
101 Node linkEntryNode = direction.isPlus() ? link.getStartNode() : link.getEndNode();
102 testViaNode.add(linkEntryNode);
103 try
104 {
105 if (origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes) != null)
106 {
107 Double weight = ((CrossSectionLink) link).getDemandWeight();
108 weights.add(weight);
109 links.put(link, weight);
110 cumulWeight += weight;
111 }
112 else
113 {
114 System.out.println("No route from origin to link; NOT including link " + link);
115 }
116 }
117 catch (NetworkException e)
118 {
119 e.printStackTrace();
120 }
121 }
122 if (link.getDirectionality(gtuType).permits(direction)
123 && (link.getStartNode().equals(origin) || link.getEndNode().equals(origin)))
124 {
125 directLinkExists = true;
126 }
127 }
128 if (cumulWeight > 0.0 && links.size() > 1 && (!directLinkExists))
129 {
130 System.out.println("Need to select access point to destination from " + links.size() + " options:");
131 for (Link link : links.keySet())
132 {
133 System.out.println(" " + link);
134 }
135 Link via = Draw.drawWeighted(links, this.stream);
136
137 if (via.getEndNode().equals(destination))
138 {
139
140
141 viaNodes.add(via.getStartNode());
142 }
143 else if (via.getStartNode().equals(destination))
144 {
145
146
147 viaNodes.add(via.getEndNode());
148 }
149 else
150 {
151
152
153 viaNodes.add(via.getEndNode());
154 }
155 if (viaNodes.size() > 0 && viaNodes.get(0).getId().startsWith("Centroid "))
156 {
157 System.out.println("oops: via node is a centroid");
158 }
159 System.out.println("Selected via node(s) " + viaNodes);
160 }
161
162 return this.shortestRouteCache.get(
163 () -> Try.assign(() -> origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes),
164 "Could not determine the shortest route from %s to %s via %s.", origin, destination, viaNodes),
165 gtuType, origin, destination, viaNodes);
166 }
167
168
169 @Override
170 public String toString()
171 {
172 return "ShortestRouteGTUCharacteristicsGeneratorOD [shortestRouteCache=" + this.shortestRouteCache + "]";
173 }
174 };
175
176
177
178
179
180
181
182
183 Route getRoute(Node origin, Node destination, GTUType gtuType);
184 }