1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    IntermodalRouter.h
11 /// @author  Jakob Erdmann
12 /// @author  Michael Behrisch
13 /// @date    Mon, 03 March 2014
14 /// @version $Id$
15 ///
16 // The IntermodalRouter builds a special network and (delegates to a SUMOAbstractRouter)
17 /****************************************************************************/
18 #ifndef IntermodalRouter_h
19 #define IntermodalRouter_h
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <string>
28 #include <vector>
29 #include <algorithm>
30 #include <assert.h>
31 #include <utils/common/MsgHandler.h>
32 #include <utils/common/SUMOTime.h>
33 #include <utils/common/ToString.h>
34 #include <utils/iodevices/OutputDevice.h>
35 #include "SUMOAbstractRouter.h"
36 #include "DijkstraRouter.h"
37 #include "AStarRouter.h"
38 #include "IntermodalNetwork.h"
39 #include "EffortCalculator.h"
40 #include "CarEdge.h"
41 #include "StopEdge.h"
42 #include "PedestrianRouter.h"
43 
44 //#define IntermodalRouter_DEBUG_ROUTES
45 
46 
47 // ===========================================================================
48 // class definitions
49 // ===========================================================================
50 /**
51  * @class IntermodalRouter
52  * The router for pedestrians (on a bidirectional network of sidewalks and crossings)
53  */
54 template<class E, class L, class N, class V>
55 class IntermodalRouter : public SUMOAbstractRouter<E, IntermodalTrip<E, N, V> > {
56 public:
57     typedef IntermodalNetwork<E, L, N, V> Network;
58 
59 private:
60     typedef void(*CreateNetCallback)(IntermodalRouter <E, L, N, V>&);
61     typedef IntermodalEdge<E, L, N, V> _IntermodalEdge;
62     typedef IntermodalTrip<E, N, V> _IntermodalTrip;
63     typedef SUMOAbstractRouterPermissions<_IntermodalEdge, _IntermodalTrip> _InternalRouter;
64     typedef DijkstraRouter<_IntermodalEdge, _IntermodalTrip, _InternalRouter> _InternalDijkstra;
65     typedef AStarRouter<_IntermodalEdge, _IntermodalTrip, _InternalRouter> _InternalAStar;
66 
67 public:
68     struct TripItem {
69         TripItem(const std::string& _line = "") :
lineTripItem70             line(_line), intended(_line), depart(-1), traveltime(0.), cost(0.) {}
71         std::string line;
72         std::string vType;
73         std::string destStop;
74         std::string intended; // intended public transport vehicle id
75         double depart; // intended public transport departure
76         std::vector<const E*> edges;
77         double traveltime;
78         double cost;
79         double length;
80         double departPos;
81         double arrivalPos;
82         std::string description;
83     };
84 
85     /// Constructor
86     IntermodalRouter(CreateNetCallback callback, const int carWalkTransfer, const std::string& routingAlgorithm,
87                      const int routingMode = 0, EffortCalculator* calc = nullptr) :
88         SUMOAbstractRouter<E, _IntermodalTrip>("IntermodalRouter", true),
89         myAmClone(false), myInternalRouter(nullptr), myIntermodalNet(nullptr),
90         myCallback(callback), myCarWalkTransfer(carWalkTransfer), myRoutingAlgorithm(routingAlgorithm),
91         myRoutingMode(routingMode), myExternalEffort(calc) {
92     }
93 
94     /// Destructor
~IntermodalRouter()95     virtual ~IntermodalRouter() {
96         delete myInternalRouter;
97         if (!myAmClone) {
98             delete myIntermodalNet;
99         }
100     }
101 
clone()102     SUMOAbstractRouter<E, _IntermodalTrip>* clone() {
103         createNet();
104         return new IntermodalRouter<E, L, N, V>(myIntermodalNet, myCarWalkTransfer, myRoutingAlgorithm, myRoutingMode, myExternalEffort);
105     }
106 
107     /** @brief Builds the route between the given edges using the minimum effort at the given time
108         The definition of the effort depends on the wished routing scheme */
109     bool compute(const E* from, const E* to, const double departPos, const double arrivalPos,
110                  const std::string stopID, const double speed,
111                  const V* const vehicle, const SVCPermissions modeSet, const SUMOTime msTime,
112                  std::vector<TripItem>& into, const double externalFactor = 0.) {
113         createNet();
114         _IntermodalTrip trip(from, to, departPos, arrivalPos, speed, msTime, 0, vehicle, modeSet, myExternalEffort, externalFactor);
115         std::vector<const _IntermodalEdge*> intoEdges;
116         //std::cout << "compute from=" << from->getID() << " to=" << to->getID() << " dPos=" << departPos << " aPos=" << arrivalPos << " stopID=" << stopID << " speed=" << speed << " veh=" << Named::getIDSecure(vehicle) << " modeSet=" << modeSet << " t=" << msTime << " iFrom=" << myIntermodalNet->getDepartEdge(from, trip.departPos)->getID() << " iTo=" << (stopID != "" ? myIntermodalNet->getStopEdge(stopID) : myIntermodalNet->getArrivalEdge(to, trip.arrivalPos))->getID() << "\n";
117         const bool success = myInternalRouter->compute(myIntermodalNet->getDepartEdge(from, trip.departPos),
118                              stopID != "" ? myIntermodalNet->getStopEdge(stopID) : myIntermodalNet->getArrivalEdge(to, trip.arrivalPos),
119                              &trip, msTime, intoEdges);
120         if (success) {
121             std::string lastLine = "";
122             double time = STEPS2TIME(msTime);
123             double effort = 0.;
124             double length = 0.;
125             const _IntermodalEdge* prev = nullptr;
126             for (const _IntermodalEdge* iEdge : intoEdges) {
127                 if (iEdge->includeInRoute(false)) {
128                     if (iEdge->getLine() == "!stop") {
129                         if (into.size() > 0) {
130                             // previous stage ends at stop
131                             into.back().destStop = iEdge->getID();
132                             if (myExternalEffort != nullptr) {
133                                 into.back().description = myExternalEffort->output(iEdge->getNumericalID());
134                             }
135                             if (lastLine == "!ped") {
136                                 lastLine = ""; // a stop always starts a new trip item
137                             }
138                         } else {
139                             // trip starts at stop
140                             lastLine = "";
141                             into.push_back(TripItem("!stop"));
142                             into.back().destStop = iEdge->getID();
143                         }
144                     } else {
145                         if (iEdge->getLine() != lastLine) {
146                             lastLine = iEdge->getLine();
147                             if (lastLine == "!car") {
148                                 into.push_back(TripItem(vehicle->getID()));
149                                 into.back().vType = vehicle->getParameter().vtypeid;
150                             } else if (lastLine == "!ped") {
151                                 into.push_back(TripItem());
152                             } else {
153                                 into.push_back(TripItem(lastLine));
154                                 into.back().depart = iEdge->getIntended(time, into.back().intended);
155                             }
156                             into.back().departPos = iEdge->getStartPos();
157                         }
158                         if (into.back().edges.empty() || into.back().edges.back() != iEdge->getEdge()) {
159                             into.back().edges.push_back(iEdge->getEdge());
160                             into.back().arrivalPos = iEdge->getEndPos();
161                         }
162                     }
163                 }
164                 const double prevTime = time, prevEffort = effort, prevLength = length;
165                 myInternalRouter->updateViaCost(prev, iEdge, &trip, time, effort, length);
166                 prev = iEdge;
167                 if (!into.empty()) {
168                     into.back().traveltime += time - prevTime;
169                     into.back().cost += effort - prevEffort;
170                     into.back().length += length - prevLength;
171                 }
172             }
173         }
174 #ifdef IntermodalRouter_DEBUG_ROUTES
175         double time = STEPS2TIME(msTime);
176         for (const _IntermodalEdge* iEdge : intoEdges) {
177             const double edgeEffort = myInternalRouter->getEffort(iEdge, &trip, time);
178             time += edgeEffort;
179             std::cout << iEdge->getID() << "(" << iEdge->getLine() << "): " << edgeEffort << std::endl;
180         }
181         std::cout << TIME2STEPS(msTime) << " trip from " << from->getID() << " to " << (to != nullptr ? to->getID() : stopID)
182                   << " departPos=" << trip.departPos
183                   << " arrivalPos=" << trip.arrivalPos
184                   << " edges=" << toString(intoEdges)
185 //                  << " resultEdges=" << toString(into)
186                   << " time=" << time
187                   << "\n";
188 #endif
189         return success;
190     }
191 
192     /** @brief Builds the route between the given edges using the minimum effort at the given time
193         The definition of the effort depends on the wished routing scheme */
compute(const E *,const E *,const _IntermodalTrip * const,SUMOTime,std::vector<const E * > &,bool)194     bool compute(const E*, const E*, const _IntermodalTrip* const,
195                  SUMOTime, std::vector<const E*>&, bool) {
196         throw ProcessError("Do not use this method");
197     }
198 
prohibit(const std::vector<E * > & toProhibit)199     void prohibit(const std::vector<E*>& toProhibit) {
200         createNet();
201         std::vector<_IntermodalEdge*> toProhibitPE;
202         for (typename std::vector<E*>::const_iterator it = toProhibit.begin(); it != toProhibit.end(); ++it) {
203             toProhibitPE.push_back(myIntermodalNet->getBothDirections(*it).first);
204             toProhibitPE.push_back(myIntermodalNet->getBothDirections(*it).second);
205             toProhibitPE.push_back(myIntermodalNet->getCarEdge(*it));
206         }
207         myInternalRouter->prohibit(toProhibitPE);
208     }
209 
writeNetwork(OutputDevice & dev)210     void writeNetwork(OutputDevice& dev) {
211         createNet();
212         for (_IntermodalEdge* e : myIntermodalNet->getAllEdges()) {
213             dev.openTag(SUMO_TAG_EDGE);
214             dev.writeAttr(SUMO_ATTR_ID, e->getID());
215             dev.writeAttr(SUMO_ATTR_LINE, e->getLine());
216             dev.writeAttr(SUMO_ATTR_LENGTH, e->getLength());
217             dev.writeAttr("successors", toString(e->getSuccessors(SVC_IGNORING)));
218             dev.closeTag();
219         }
220     }
221 
writeWeights(OutputDevice & dev)222     void writeWeights(OutputDevice& dev) {
223         createNet();
224         _IntermodalTrip trip(nullptr, nullptr, 0., 0., DEFAULT_PEDESTRIAN_SPEED, 0, 0, nullptr, SVC_PASSENGER | SVC_BICYCLE | SVC_BUS);
225         for (_IntermodalEdge* e : myIntermodalNet->getAllEdges()) {
226             dev.openTag(SUMO_TAG_EDGE);
227             dev.writeAttr(SUMO_ATTR_ID, e->getID());
228             dev.writeAttr("traveltime", e->getTravelTime(&trip, 0.));
229             dev.writeAttr("effort", e->getEffort(&trip, 0.));
230             dev.closeTag();
231         }
232     }
233 
getNetwork()234     Network* getNetwork() const {
235         return myIntermodalNet;
236     }
237 
getExternalEffort()238     EffortCalculator* getExternalEffort() const {
239         return myExternalEffort;
240     }
241 
242 private:
IntermodalRouter(Network * net,const int carWalkTransfer,const std::string & routingAlgorithm,const int routingMode,EffortCalculator * calc)243     IntermodalRouter(Network* net, const int carWalkTransfer, const std::string& routingAlgorithm,
244                      const int routingMode, EffortCalculator* calc) :
245         SUMOAbstractRouter<E, _IntermodalTrip>("IntermodalRouterClone", true), myAmClone(true),
246         myInternalRouter(new _InternalDijkstra(net->getAllEdges(), true,
247                                                gWeightsRandomFactor > 1 ? & _IntermodalEdge::getTravelTimeStaticRandomized : & _IntermodalEdge::getTravelTimeStatic)),
248         myIntermodalNet(net), myCarWalkTransfer(carWalkTransfer), myRoutingAlgorithm(routingAlgorithm), myRoutingMode(routingMode), myExternalEffort(calc) {}
249 
getEffortAggregated(const _IntermodalEdge * const edge,const _IntermodalTrip * const trip,double time)250     static inline double getEffortAggregated(const _IntermodalEdge* const edge, const _IntermodalTrip* const trip, double time) {
251         return edge == nullptr || !edge->hasEffort() ? 0. : edge->getEffort(trip, time);
252     }
253 
getCombined(const _IntermodalEdge * const edge,const _IntermodalTrip * const trip,double time)254     static inline double getCombined(const _IntermodalEdge* const edge, const _IntermodalTrip* const trip, double time) {
255         return edge->getTravelTime(trip, time) + trip->externalFactor * trip->calc->getEffort(edge->getNumericalID());
256     }
257 
createNet()258     inline void createNet() {
259         if (myIntermodalNet == nullptr) {
260             myIntermodalNet = new Network(E::getAllEdges(), false, myCarWalkTransfer);
261             myIntermodalNet->addCarEdges(E::getAllEdges());
262             myCallback(*this);
263             switch (myRoutingMode) {
264                 case 0:
265                     if (myRoutingAlgorithm == "astar") {
266                         myInternalRouter = new _InternalAStar(myIntermodalNet->getAllEdges(), true,
267                                                               gWeightsRandomFactor > 1 ? &_IntermodalEdge::getTravelTimeStaticRandomized : &_IntermodalEdge::getTravelTimeStatic);
268                     } else {
269                         myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true,
270                                 gWeightsRandomFactor > 1 ? &_IntermodalEdge::getTravelTimeStaticRandomized : &_IntermodalEdge::getTravelTimeStatic);
271                     }
272                     break;
273                 case 1:
274                     myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &getEffortAggregated, &_IntermodalEdge::getTravelTimeStatic);
275                     break;
276                 case 2:
277                     myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &_IntermodalEdge::getEffortStatic, &_IntermodalEdge::getTravelTimeStatic);
278                     break;
279                 case 3:
280                     if (myExternalEffort != nullptr) {
281                         std::vector<std::string> edgeLines;
282                         for (const auto e : myIntermodalNet->getAllEdges()) {
283                             edgeLines.push_back(e->getLine());
284                         }
285                         myExternalEffort->init(edgeLines);
286                     }
287                     myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &getCombined, &_IntermodalEdge::getTravelTimeStatic, false, myExternalEffort);
288                     break;
289             }
290         }
291     }
292 
293 private:
294     const bool myAmClone;
295     _InternalRouter* myInternalRouter;
296     Network* myIntermodalNet;
297     CreateNetCallback myCallback;
298     const int myCarWalkTransfer;
299     const std::string myRoutingAlgorithm;
300     const int myRoutingMode;
301     EffortCalculator* const myExternalEffort;
302 
303 
304 private:
305     /// @brief Invalidated assignment operator
306     IntermodalRouter& operator=(const IntermodalRouter& s);
307 
308 };
309 
310 
311 #endif
312 
313 /****************************************************************************/
314