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