1 package org.opentrafficsim.road.gtu.strategical;
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.base.OtsRuntimeException;
12 import org.opentrafficsim.core.gtu.GtuType;
13 import org.opentrafficsim.core.math.Draw;
14 import org.opentrafficsim.core.network.Connector;
15 import org.opentrafficsim.core.network.Link;
16 import org.opentrafficsim.core.network.LinkWeight;
17 import org.opentrafficsim.core.network.NetworkException;
18 import org.opentrafficsim.core.network.Node;
19 import org.opentrafficsim.core.network.route.Route;
20
21 import nl.tudelft.simulation.jstats.streams.StreamInterface;
22
23
24
25
26
27
28
29
30
31
32
33
34 public interface RouteGenerator
35 {
36
37 RouteGenerator NULL = new RouteGenerator()
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 MultiKeyMap<RouteGenerator> DEFAULT_SUPPLIERS = new MultiKeyMap<>(StreamInterface.class, LinkWeight.class);
48
49
50
51
52
53
54
55 static RouteGenerator getDefaultRouteSupplier(final StreamInterface stream, final LinkWeight linkWeight)
56 {
57 RouteGenerator def = DEFAULT_SUPPLIERS.get(stream, linkWeight);
58 if (def == null)
59 {
60 def = new DefaultRouteGenerator(stream, linkWeight);
61 DEFAULT_SUPPLIERS.put(def, stream, linkWeight);
62 }
63 return def;
64 }
65
66
67 class DefaultRouteGenerator implements RouteGenerator
68 {
69
70 private final MultiKeyMap<Route> shortestRouteCache =
71 new MultiKeyMap<>(GtuType.class, Node.class, Node.class, List.class);
72
73
74 private final LinkWeight linkWeight;
75
76
77 private final StreamInterface stream;
78
79
80
81
82
83
84 public DefaultRouteGenerator(final StreamInterface stream, final LinkWeight linkWeight)
85 {
86 Throw.whenNull(stream, "Stream may not be null.");
87 Throw.whenNull(linkWeight, "Link weight may not be null.");
88 this.stream = stream;
89 this.linkWeight = linkWeight;
90 }
91
92 @Override
93 public Route getRoute(final Node origin, final Node destination, final GtuType gtuType)
94 {
95 List<Node> viaNodes = new ArrayList<>();
96 double cumulWeight = 0.0;
97 Map<Link, Double> links = new LinkedHashMap<>();
98 boolean directLinkExists = false;
99 for (Link link : destination.getLinks())
100 {
101 if (link.isConnector() && link instanceof Connector && ((Connector) link).getDemandWeight() > 0.0)
102 {
103
104 List<Node> testViaNode = new ArrayList<>();
105 Node linkEntryNode = link.getStartNode();
106 testViaNode.add(linkEntryNode);
107 try
108 {
109 if (origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes,
110 this.linkWeight) != null)
111 {
112 Double weight = ((Connector) link).getDemandWeight();
113 links.put(link, weight);
114 cumulWeight += weight;
115 }
116 }
117 catch (NetworkException e)
118 {
119
120 }
121 }
122 if (link.getStartNode().equals(origin) || link.getEndNode().equals(origin))
123 {
124 directLinkExists = true;
125 }
126 }
127 if (cumulWeight > 0.0 && links.size() > 1 && (!directLinkExists))
128 {
129 Link via = Draw.drawWeighted(links, this.stream);
130 if (via.getEndNode().equals(destination))
131 {
132 viaNodes.add(via.getStartNode());
133 }
134 else if (via.getStartNode().equals(destination))
135 {
136 viaNodes.add(via.getEndNode());
137 }
138 else
139 {
140 viaNodes.add(via.getEndNode());
141 }
142 }
143 if (!this.linkWeight.isStatic())
144 {
145 return Try.assign(
146 () -> origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes,
147 this.linkWeight),
148 OtsRuntimeException.class, "Could not determine the shortest route from %s to %s via %s.", origin,
149 destination, viaNodes);
150 }
151 return this.shortestRouteCache.get(
152 () -> Try.assign(
153 () -> origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes,
154 this.linkWeight),
155 OtsRuntimeException.class, "Could not determine the shortest route from %s to %s via %s.", origin,
156 destination, viaNodes),
157 gtuType, origin, destination, viaNodes);
158 }
159
160 @Override
161 public String toString()
162 {
163 return "DefaultRouteGenerator [linkWeight=" + this.linkWeight + "shortestRouteCache=" + this.shortestRouteCache
164 + "]";
165 }
166 };
167
168
169
170
171
172
173
174
175 Route getRoute(Node origin, Node destination, GtuType gtuType);
176 }