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.core.gtu.GtuType;
12 import org.opentrafficsim.core.math.Draw;
13 import org.opentrafficsim.core.network.Connector;
14 import org.opentrafficsim.core.network.Link;
15 import org.opentrafficsim.core.network.LinkWeight;
16 import org.opentrafficsim.core.network.NetworkException;
17 import org.opentrafficsim.core.network.Node;
18 import org.opentrafficsim.core.network.route.Route;
19
20 import nl.tudelft.simulation.jstats.streams.StreamInterface;
21
22
23
24
25
26
27
28
29
30
31
32
33 public interface RouteGenerator
34 {
35
36 RouteGenerator NULL = new RouteGenerator()
37 {
38 @Override
39 public Route getRoute(final Node origin, final Node destination, final GtuType gtuType)
40 {
41 return null;
42 }
43 };
44
45
46 MultiKeyMap<RouteGenerator> DEFAULT_SUPPLIERS = new MultiKeyMap<>(StreamInterface.class, LinkWeight.class);
47
48
49
50
51
52
53
54 static RouteGenerator getDefaultRouteSupplier(final StreamInterface stream, final LinkWeight linkWeight)
55 {
56 RouteGenerator def = DEFAULT_SUPPLIERS.get(stream, linkWeight);
57 if (def == null)
58 {
59 def = new DefaultRouteGenerator(stream, linkWeight);
60 DEFAULT_SUPPLIERS.put(def, stream, linkWeight);
61 }
62 return def;
63 }
64
65
66 class DefaultRouteGenerator implements RouteGenerator
67 {
68
69 private final MultiKeyMap<Route> shortestRouteCache =
70 new MultiKeyMap<>(GtuType.class, Node.class, Node.class, List.class);
71
72
73 private final LinkWeight linkWeight;
74
75
76 private final StreamInterface stream;
77
78
79
80
81
82
83 public DefaultRouteGenerator(final StreamInterface stream, final LinkWeight linkWeight)
84 {
85 Throw.whenNull(stream, "Stream may not be null.");
86 Throw.whenNull(linkWeight, "Link weight may not be null.");
87 this.stream = stream;
88 this.linkWeight = linkWeight;
89 }
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 "Could not determine the shortest route from %s to %s via %s.", origin, destination, viaNodes);
149 }
150 return this.shortestRouteCache.get(() -> Try.assign(
151 () -> origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes, this.linkWeight),
152 "Could not determine the shortest route from %s to %s via %s.", origin, destination, viaNodes), gtuType,
153 origin, destination, viaNodes);
154 }
155
156
157 @Override
158 public String toString()
159 {
160 return "DefaultRouteGenerator [linkWeight=" + this.linkWeight + "shortestRouteCache=" + this.shortestRouteCache
161 + "]";
162 }
163 };
164
165
166
167
168
169
170
171
172 Route getRoute(Node origin, Node destination, GtuType gtuType);
173 }