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