View Javadoc
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   * Generates a route by determining one. This class is different from {@code RouteGenerator} in that it has the origin,
23   * destination and GTU type as input.
24   * <p>
25   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
27   * <p>
28   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 24 mrt. 2018 <br>
29   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
30   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
31   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
32   */
33  public interface RouteGeneratorOD
34  {
35      /** No route route generator. */
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      /** Cache of default route generators per stream. */
46      Map<StreamInterface, RouteGeneratorOD> DEFAULT_MAP = new LinkedHashMap<>();
47  
48      /**
49       * Returns a default route generator for shortest routes based on the given stream.
50       * @param stream StreamInterface; random number stream
51       * @return RouteSupplier; default route generator for shortest routes based on the given stream
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      /** Shortest route route generator. */
65      class DefaultRouteGenerator implements RouteGeneratorOD
66      {
67          /** Shortest route cache. */
68          private NestedCache<Route> shortestRouteCache = new NestedCache<>(GTUType.class, Node.class, Node.class, List.class);
69  
70          /** Stream of random numbers. */
71          private final StreamInterface stream;
72  
73          /**
74           * Constructor.
75           * @param stream StreamInterface; stream of random numbers
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         /** {@inheritDoc} */
115         @Override
116         public String toString()
117         {
118             return "ShortestRouteGTUCharacteristicsGeneratorOD [shortestRouteCache=" + this.shortestRouteCache + "]";
119         }
120     };
121 
122     /**
123      * Returns a route.
124      * @param origin Node; origin
125      * @param destination Node; destination
126      * @param gtuType GTUType; gtu type
127      * @return Route; route
128      */
129     Route getRoute(Node origin, Node destination, GTUType gtuType);
130 }