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.opentrafficsim.core.gtu.GTUDirectionality;
9 import org.opentrafficsim.core.gtu.GTUType;
10 import org.opentrafficsim.core.gtu.NestedCache;
11 import org.opentrafficsim.core.gtu.Try;
12 import org.opentrafficsim.core.math.Draw;
13 import org.opentrafficsim.core.network.Link;
14 import org.opentrafficsim.core.network.Node;
15 import org.opentrafficsim.core.network.route.Route;
16 import org.opentrafficsim.road.network.lane.CrossSectionLink;
17
18 import nl.tudelft.simulation.jstats.streams.StreamInterface;
19 import nl.tudelft.simulation.language.Throw;
20
21
22
23
24
25
26
27
28
29
30
31
32 public interface RouteSupplier
33 {
34
35 RouteSupplier NULL = new RouteSupplier()
36 {
37 @Override
38 public Route getRoute(final Node origin, final Node destination, final GTUType gtuType)
39 {
40 return null;
41 }
42 };
43
44
45 Map<StreamInterface, RouteSupplier> DEFAULT_MAP = new LinkedHashMap<>();
46
47
48
49
50
51
52 static RouteSupplier getDefaultRouteSupplier(final StreamInterface stream)
53 {
54 RouteSupplier def = DEFAULT_MAP.get(stream);
55 if (def == null)
56 {
57 def = new DefaultRouteSupplier(stream);
58 DEFAULT_MAP.put(stream, def);
59 }
60 return def;
61 }
62
63
64 class DefaultRouteSupplier implements RouteSupplier
65 {
66
67 private NestedCache<Route> shortestRouteCache = new NestedCache<>(GTUType.class, Node.class, Node.class, List.class);
68
69
70 private final StreamInterface stream;
71
72
73
74
75
76 public DefaultRouteSupplier(final StreamInterface stream)
77 {
78 Throw.whenNull(stream, "Stream may not be null.");
79 this.stream = stream;
80 }
81
82 @Override
83 public Route getRoute(final Node origin, final Node destination, final GTUType gtuType)
84 {
85 List<Node> viaNodes = new ArrayList<>();
86 double cumulWeight = 0.0;
87 List<Double> weights = new ArrayList<>();
88 Map<Link, Double> links = new LinkedHashMap<>();
89 for (Link link : destination.getLinks())
90 {
91 GTUDirectionality direction =
92 link.getEndNode().equals(destination) ? GTUDirectionality.DIR_PLUS : GTUDirectionality.DIR_MINUS;
93 if (link.getLinkType().isConnector() && link.getDirectionality(gtuType).permits(direction)
94 && link instanceof CrossSectionLink && ((CrossSectionLink) link).getDemandWeight() != null)
95 {
96 Double weight = ((CrossSectionLink) link).getDemandWeight();
97 weights.add(weight);
98 links.put(link, weight);
99 cumulWeight += weight;
100 }
101 }
102 if (cumulWeight > 0.0)
103 {
104 Link via = Draw.drawWeighted(links, this.stream);
105 viaNodes.add(via.getStartNode().equals(destination) ? via.getEndNode() : via.getStartNode());
106 }
107 return this.shortestRouteCache.getValue(
108 () -> Try.assign(() -> origin.getNetwork().getShortestRouteBetween(gtuType, origin, destination, viaNodes),
109 "Could not determine the shortest route from %s to %s via %s.", origin, destination, viaNodes),
110 gtuType, origin, destination, viaNodes);
111 }
112
113
114 @Override
115 public String toString()
116 {
117 return "ShortestRouteGTUCharacteristicsGeneratorOD [shortestRouteCache=" + this.shortestRouteCache + "]";
118 }
119 };
120
121
122
123
124
125
126
127
128 Route getRoute(Node origin, Node destination, GTUType gtuType);
129 }