Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/IntermodalRouter.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file IntermodalRouter.h
15
/// @author Jakob Erdmann
16
/// @author Michael Behrisch
17
/// @date Mon, 03 March 2014
18
///
19
// The IntermodalRouter builds a special network and (delegates to a SUMOAbstractRouter)
20
/****************************************************************************/
21
#pragma once
22
#include <config.h>
23
24
#include <string>
25
#include <vector>
26
#include <algorithm>
27
#include <assert.h>
28
#include <utils/common/MsgHandler.h>
29
#include <utils/common/SUMOTime.h>
30
#include <utils/common/ToString.h>
31
#include <utils/iodevices/OutputDevice.h>
32
#include "SUMOAbstractRouter.h"
33
#include "DijkstraRouter.h"
34
#include "AStarRouter.h"
35
#include "IntermodalNetwork.h"
36
#include "EffortCalculator.h"
37
#include "CarEdge.h"
38
#include "StopEdge.h"
39
#include "PedestrianRouter.h"
40
41
//#define IntermodalRouter_DEBUG_ROUTES
42
43
44
// ===========================================================================
45
// class definitions
46
// ===========================================================================
47
/**
48
* @class IntermodalRouter
49
* The router for pedestrians (on a bidirectional network of sidewalks and crossings)
50
*/
51
template<class E, class L, class N, class V>
52
class IntermodalRouter : public SUMOAbstractRouter<E, IntermodalTrip<E, N, V> > {
53
public:
54
typedef IntermodalNetwork<E, L, N, V> Network;
55
56
private:
57
typedef void(*CreateNetCallback)(IntermodalRouter <E, L, N, V>&);
58
typedef IntermodalEdge<E, L, N, V> _IntermodalEdge;
59
typedef IntermodalTrip<E, N, V> _IntermodalTrip;
60
typedef SUMOAbstractRouter<_IntermodalEdge, _IntermodalTrip> _InternalRouter;
61
typedef MapMatcher<E, L, N> _MapMatcher;
62
typedef DijkstraRouter<_IntermodalEdge, _IntermodalTrip> _InternalDijkstra;
63
typedef AStarRouter<_IntermodalEdge, _IntermodalTrip, _MapMatcher> _InternalAStar;
64
65
public:
66
struct TripItem {
67
TripItem(const std::string& _line = "") :
68
line(_line), intended(_line) {}
69
std::string line;
70
std::string vType = "";
71
std::string destStop = "";
72
std::string intended; // intended public transport vehicle id
73
double depart = -1.; // intended public transport departure
74
std::vector<const E*> edges;
75
double traveltime = 0.;
76
double cost = 0.;
77
double length = 0.;
78
double departPos = INVALID_DOUBLE;
79
double arrivalPos = INVALID_DOUBLE;
80
std::string description = "";
81
std::vector<double> exitTimes;
82
};
83
84
/// Constructor
85
IntermodalRouter(CreateNetCallback callback, const int carWalkTransfer, double taxiWait, const std::string& routingAlgorithm,
86
const int routingMode = 0, EffortCalculator* calc = nullptr) :
87
SUMOAbstractRouter<E, _IntermodalTrip>("IntermodalRouter", true, nullptr, nullptr, false, false),
88
myAmClone(false), myInternalRouter(nullptr), myIntermodalNet(nullptr),
89
myCallback(callback), myCarWalkTransfer(carWalkTransfer), myTaxiWait(taxiWait),
90
myRoutingAlgorithm(routingAlgorithm),
91
myRoutingMode(routingMode), myExternalEffort(calc) {
92
}
93
94
/// Destructor
95
virtual ~IntermodalRouter() {
96
delete myInternalRouter;
97
if (!myAmClone) {
98
delete myIntermodalNet;
99
}
100
}
101
102
SUMOAbstractRouter<E, _IntermodalTrip>* clone() {
103
createNet();
104
return new IntermodalRouter<E, L, N, V>(myIntermodalNet, myCarWalkTransfer, myTaxiWait, myRoutingAlgorithm, myRoutingMode, myExternalEffort);
105
}
106
107
int getCarWalkTransfer() const {
108
return myCarWalkTransfer;
109
}
110
111
/** @brief Builds the route between the given edges using the minimum effort at the given time
112
The definition of the effort depends on the wished routing scheme */
113
bool compute(const E* from, const E* to,
114
const double departPos, const std::string& originStopID,
115
const double arrivalPos, const std::string& stopID,
116
const double speed, const V* const vehicle, const SVCPermissions modeSet, const SUMOTime msTime,
117
std::vector<TripItem>& into, const double externalFactor = 0.) {
118
createNet();
119
_IntermodalTrip trip(from, to, departPos, arrivalPos, speed, msTime, 0, vehicle, modeSet, myExternalEffort, externalFactor);
120
std::vector<const _IntermodalEdge*> intoEdges;
121
//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";
122
const _IntermodalEdge* iFrom = originStopID != "" ? myIntermodalNet->getStopEdge(originStopID) : myIntermodalNet->getDepartEdge(from, trip.departPos);
123
const _IntermodalEdge* iTo = stopID != "" ? myIntermodalNet->getStopEdge(stopID) : myIntermodalNet->getArrivalEdge(to, trip.arrivalPos);
124
const bool success = myInternalRouter->compute(iFrom, iTo, &trip, msTime, intoEdges, true);
125
if (success) {
126
std::string lastLine = "";
127
const _IntermodalEdge* lastLineEdge = nullptr;
128
double lastLineTime = STEPS2TIME(msTime);
129
double time = STEPS2TIME(msTime);
130
double effort = 0.;
131
double length = 0.;
132
const _IntermodalEdge* prev = nullptr;
133
for (const _IntermodalEdge* iEdge : intoEdges) {
134
bool addedEdge = false;
135
if (iEdge->includeInRoute(false)) {
136
if (iEdge->getLine() == "!stop") {
137
if (into.size() > 0) {
138
// previous stage ends at stop
139
into.back().destStop = iEdge->getID();
140
if (myExternalEffort != nullptr) {
141
into.back().description = myExternalEffort->output(iEdge->getNumericalID());
142
}
143
if (lastLine == "!ped") {
144
lastLine = ""; // a stop always starts a new trip item
145
}
146
} else {
147
// trip starts at stop
148
lastLine = "";
149
into.push_back(TripItem("!stop"));
150
into.back().destStop = iEdge->getID();
151
}
152
} else {
153
if (iEdge->getLine() != lastLine || loopedLineTransfer(lastLineEdge, iEdge, lastLineTime, time)) {
154
lastLine = iEdge->getLine();
155
lastLineEdge = iEdge;
156
lastLineTime = time;
157
if (lastLine == "!car") {
158
into.push_back(TripItem(vehicle->getID()));
159
into.back().vType = vehicle->getParameter().vtypeid;
160
} else if (lastLine == "!ped") {
161
into.push_back(TripItem());
162
} else {
163
into.push_back(TripItem(lastLine));
164
into.back().depart = iEdge->getIntended(time, into.back().intended);
165
}
166
into.back().departPos = iEdge->getStartPos();
167
}
168
if (into.back().edges.empty() || into.back().edges.back() != iEdge->getEdge()) {
169
into.back().edges.push_back(iEdge->getEdge());
170
into.back().arrivalPos = iEdge->getEndPos();
171
addedEdge = true;
172
}
173
}
174
}
175
const double prevTime = time;
176
const double prevEffort = effort;
177
const double prevLength = length;
178
myInternalRouter->updateViaCost(prev, iEdge, &trip, time, effort, length);
179
// correct intermodal length:
180
length += iEdge->getPartialLength(&trip) - iEdge->getLength();
181
prev = iEdge;
182
if (!into.empty()) {
183
into.back().traveltime += time - prevTime;
184
into.back().cost += effort - prevEffort;
185
into.back().length += length - prevLength;
186
if (into.back().depart < 0) {
187
into.back().depart = prevTime;
188
}
189
if (addedEdge) {
190
into.back().exitTimes.push_back(time);
191
}
192
}
193
}
194
} else {
195
const std::string oType = originStopID != "" ? "stop" : "edge";
196
const std::string oID = originStopID != "" ? originStopID : from->getID();
197
const std::string dType = stopID != "" ? "stop" : "edge";
198
const std::string dID = stopID != "" ? stopID : to->getID();
199
this->myErrorMsgHandler->informf(TL("No connection between % '%' and % '%' found."), oType, oID, dType, dID);
200
}
201
if (into.size() > 0) {
202
into.back().arrivalPos = arrivalPos;
203
}
204
#ifdef IntermodalRouter_DEBUG_ROUTES
205
double time = STEPS2TIME(msTime);
206
for (const _IntermodalEdge* iEdge : intoEdges) {
207
const double edgeEffort = myInternalRouter->getEffort(iEdge, &trip, time);
208
time += edgeEffort;
209
std::cout << iEdge->getID() << "(" << iEdge->getLine() << "): " << edgeEffort << " l=" << iEdge->getLength() << " pL=" << iEdge->getPartialLength(&trip) << "\n";
210
}
211
std::cout << TIME2STEPS(msTime) << " trip from " << from->getID() << " to " << (to != nullptr ? to->getID() : stopID)
212
<< " departPos=" << trip.departPos
213
<< " arrivalPos=" << trip.arrivalPos
214
<< " modes=" << getVehicleClassNames(modeSet)
215
<< " edges=" << toString(intoEdges)
216
// << " resultEdges=" << toString(into)
217
<< " time=" << time
218
<< "\n";
219
#endif
220
return success;
221
}
222
223
/** @brief Builds the route between the given edges using the minimum effort at the given time
224
The definition of the effort depends on the wished routing scheme */
225
bool compute(const E*, const E*, const _IntermodalTrip* const,
226
SUMOTime, std::vector<const E*>&, bool) {
227
throw ProcessError(TL("Do not use this method"));
228
}
229
230
inline void setBulkMode(const bool mode) {
231
SUMOAbstractRouter<E, _IntermodalTrip>::setBulkMode(mode);
232
if (myInternalRouter != nullptr) {
233
myInternalRouter->setBulkMode(mode);
234
}
235
}
236
237
void prohibit(const std::map<const E*, double>& toProhibit) {
238
createNet();
239
std::map<const _IntermodalEdge*, double> toProhibitPE;
240
for (auto item : toProhibit) {
241
toProhibitPE[myIntermodalNet->getBothDirections(item.first).first] = item.second;
242
toProhibitPE[myIntermodalNet->getBothDirections(item.first).second] = item.second;
243
toProhibitPE[myIntermodalNet->getCarEdge(item.first)] = item.second;
244
}
245
myInternalRouter->prohibit(toProhibitPE);
246
}
247
248
void writeNetwork(OutputDevice& dev) {
249
createNet();
250
for (_IntermodalEdge* e : myIntermodalNet->getAllEdges()) {
251
dev.openTag(SUMO_TAG_EDGE);
252
dev.writeAttr(SUMO_ATTR_ID, e->getID());
253
dev.writeAttr(SUMO_ATTR_LINE, e->getLine());
254
dev.writeAttr(SUMO_ATTR_LENGTH, e->getLength());
255
dev.writeAttr("successors", toString(e->getSuccessors(SVC_IGNORING)));
256
dev.closeTag();
257
}
258
}
259
260
void writeWeights(OutputDevice& dev) {
261
createNet();
262
_IntermodalTrip trip(nullptr, nullptr, 0., 0., DEFAULT_PEDESTRIAN_SPEED, 0, 0, nullptr, SVC_PASSENGER | SVC_BICYCLE | SVC_BUS);
263
for (_IntermodalEdge* e : myIntermodalNet->getAllEdges()) {
264
dev.openTag(SUMO_TAG_EDGE);
265
dev.writeAttr(SUMO_ATTR_ID, e->getID());
266
dev.writeAttr("traveltime", e->getTravelTime(&trip, 0.));
267
dev.writeAttr("effort", e->getEffort(&trip, 0.));
268
dev.closeTag();
269
}
270
}
271
272
Network* getNetwork() const {
273
return myIntermodalNet;
274
}
275
276
EffortCalculator* getExternalEffort() const {
277
return myExternalEffort;
278
}
279
280
private:
281
IntermodalRouter(Network* net, const int carWalkTransfer, double taxiWait, const std::string& routingAlgorithm,
282
const int routingMode, EffortCalculator* calc) :
283
SUMOAbstractRouter<E, _IntermodalTrip>("IntermodalRouterClone", true, nullptr, nullptr, false, false),
284
myAmClone(true), myInternalRouter(nullptr), myIntermodalNet(net),
285
myCarWalkTransfer(carWalkTransfer),
286
myTaxiWait(taxiWait),
287
myRoutingAlgorithm(routingAlgorithm), myRoutingMode(routingMode), myExternalEffort(calc) {
288
createNet();
289
}
290
291
static inline double getCombined(const _IntermodalEdge* const edge, const _IntermodalTrip* const trip, double time) {
292
return edge->getTravelTime(trip, time) + trip->externalFactor * trip->calc->getEffort(edge->getNumericalID());
293
}
294
295
inline void createNet() {
296
if (myIntermodalNet == nullptr) {
297
myIntermodalNet = new Network(E::getAllEdges(), false, myCarWalkTransfer);
298
myIntermodalNet->addCarEdges(E::getAllEdges(), myTaxiWait);
299
myCallback(*this);
300
}
301
if (myInternalRouter == nullptr) {
302
switch (myRoutingMode) {
303
case 0:
304
if (myRoutingAlgorithm == "astar") {
305
myInternalRouter = new _InternalAStar(myIntermodalNet->getAllEdges(), true,
306
gWeightsRandomFactor > 1 ? &_IntermodalEdge::getTravelTimeStaticRandomized : &_IntermodalEdge::getTravelTimeStatic, nullptr, true);
307
} else {
308
myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true,
309
gWeightsRandomFactor > 1 ? &_IntermodalEdge::getTravelTimeStaticRandomized : &_IntermodalEdge::getTravelTimeStatic, nullptr, false, nullptr, true);
310
}
311
break;
312
case 1:
313
myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &_IntermodalEdge::getTravelTimeAggregated, nullptr, false, nullptr, true);
314
break;
315
case 2:
316
myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &_IntermodalEdge::getEffortStatic, &_IntermodalEdge::getTravelTimeStatic, false, nullptr, true);
317
break;
318
case 3:
319
if (myExternalEffort != nullptr) {
320
std::vector<std::string> edgeLines;
321
for (const auto e : myIntermodalNet->getAllEdges()) {
322
edgeLines.push_back(e->getLine());
323
}
324
myExternalEffort->init(edgeLines);
325
}
326
myInternalRouter = new _InternalDijkstra(myIntermodalNet->getAllEdges(), true, &getCombined, &_IntermodalEdge::getTravelTimeStatic, false, myExternalEffort, true);
327
break;
328
}
329
}
330
}
331
332
333
bool loopedLineTransfer(const _IntermodalEdge* prev, const _IntermodalEdge* cur, double prevTime, double time) {
334
assert(prev != nullptr);
335
if (myIntermodalNet->isLooped(cur->getLine())) {
336
// check if the last two edges are served by different vehicles
337
std::string intended1;
338
std::string intended2;
339
prev->getIntended(prevTime, intended1);
340
cur->getIntended(time, intended2);
341
return intended1 != intended2;
342
}
343
return false;
344
}
345
346
private:
347
const bool myAmClone;
348
_InternalRouter* myInternalRouter;
349
Network* myIntermodalNet;
350
CreateNetCallback myCallback;
351
const int myCarWalkTransfer;
352
const double myTaxiWait;
353
const std::string myRoutingAlgorithm;
354
const int myRoutingMode;
355
EffortCalculator* const myExternalEffort;
356
357
358
private:
359
/// @brief Invalidated assignment operator
360
IntermodalRouter& operator=(const IntermodalRouter& s);
361
362
};
363
364