Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/RailEdge.h
193780 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 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 RailEdge.h
15
/// @author Jakob Erdmann
16
/// @date 26.02.2020
17
///
18
// The RailEdge is a wrapper around a ROEdge or a MSEdge used for railway routing
19
/****************************************************************************/
20
#pragma once
21
#include <config.h>
22
#include <cassert>
23
24
//#define RailEdge_DEBUG_TURNS
25
//#define RailEdge_DEBUG_INIT
26
//#define RailEdge_DEBUG_SUCCESSORS
27
#define RailEdge_DEBUGID ""
28
//#define RailEdge_DEBUG_COND(obj) ((obj != 0 && (obj)->getID() == RailEdge_DEBUGID))
29
#define RailEdge_DEBUG_COND(obj) (true)
30
31
#define REVERSAL_SLACK (POSITION_EPS + NUMERICAL_EPS)
32
33
// ===========================================================================
34
// class definitions
35
// ===========================================================================
36
/// @brief the edge type representing backward edges
37
template<class E, class V>
38
class RailEdge {
39
public:
40
typedef RailEdge<E, V> _RailEdge;
41
typedef std::vector<std::pair<const _RailEdge*, const _RailEdge*> > ConstEdgePairVector;
42
43
RailEdge(const E* orig) :
44
myNumericalID(orig->getNumericalID()),
45
myOriginal(orig),
46
myTurnaround(nullptr),
47
myIsVirtual(true)
48
{ }
49
50
RailEdge(const E* turnStart, const E* turnEnd, int numericalID) :
51
myNumericalID(numericalID),
52
myID("TrainReversal!" + turnStart->getID() + "->" + turnEnd->getID()),
53
myOriginal(nullptr),
54
myTurnaround(nullptr),
55
myIsVirtual(true),
56
myMaxLength(turnStart->getLength() - REVERSAL_SLACK),
57
myStartLength(turnStart->getLength() - REVERSAL_SLACK) {
58
myViaSuccessors.push_back(std::make_pair(turnEnd->getRailwayRoutingEdge(), nullptr));
59
}
60
61
/// @brief Destructor.
62
virtual ~RailEdge() {
63
delete myTurnaround;
64
}
65
66
void update(double maxTrainLength, const std::vector<const E*>& replacementEdges) {
67
if (maxTrainLength > myMaxLength) {
68
myMaxLength = maxTrainLength;
69
myReplacementEdges = replacementEdges;
70
#ifdef RailEdge_DEBUG_INIT
71
std::cout << " update RailEdge " << getID() << " myMaxLength=" << myMaxLength << " repl=" << toString(myReplacementEdges) << "\n";
72
#endif
73
}
74
}
75
76
void addVirtualTurns(const E* forward, const E* backward,
77
std::vector<_RailEdge*>& railEdges, int& numericalID, double dist,
78
double maxTrainLength, const std::vector<const E*>& replacementEdges) {
79
// search backwards until dist and add virtual turnaround edges with
80
// replacement edges up to the real turnaround
81
#ifdef RailEdge_DEBUG_INIT
82
std::cout << "addVirtualTurns forward=" << forward->getID() << " backward=" << backward->getID() << " dist=" << dist
83
<< " maxLength=" << maxTrainLength << " repl=" << toString(replacementEdges) << "\n";
84
#endif
85
if (dist <= 0) {
86
return;
87
}
88
for (const E* prev : forward->getPredecessors()) {
89
if (prev == backward) {
90
continue;
91
}
92
const E* bidi = prev->getBidiEdge();
93
if (bidi != nullptr && backward->isConnectedTo(*bidi, SVC_IGNORING)) {
94
_RailEdge* prevRailEdge = prev->getRailwayRoutingEdge();
95
if (prevRailEdge->myTurnaround == nullptr) {
96
prevRailEdge->myTurnaround = new _RailEdge(prev, bidi, numericalID++);
97
prevRailEdge->myViaSuccessors.push_back(std::make_pair(prevRailEdge->myTurnaround, nullptr));
98
railEdges.push_back(prevRailEdge->myTurnaround);
99
#ifdef RailEdge_DEBUG_INIT
100
std::cout << " RailEdge " << prevRailEdge->getID() << " virtual turnaround " << prevRailEdge->myTurnaround->getID() << "\n";
101
#endif
102
}
103
/*
104
// doesn't compile though I don't know why
105
auto itFound = std::find(replacementEdges.begin(), replacementEdges.end(), prev);
106
bool notFound = itFound == replacementEdges.end();
107
*/
108
bool notFound = true;
109
for (const E* r : replacementEdges) {
110
if (r == prev) {
111
notFound = false;
112
break;
113
}
114
}
115
116
if (notFound) {
117
// prevent loops in replacementEdges
118
prevRailEdge->myTurnaround->update(prev->getLength() + maxTrainLength - REVERSAL_SLACK, replacementEdges);
119
std::vector<const E*> replacementEdges2;
120
replacementEdges2.push_back(prev);
121
replacementEdges2.insert(replacementEdges2.end(), replacementEdges.begin(), replacementEdges.end());
122
addVirtualTurns(prev, bidi, railEdges, numericalID, dist - prev->getLength(),
123
maxTrainLength + prev->getLength(), replacementEdges2);
124
}
125
}
126
}
127
}
128
129
void init(std::vector<_RailEdge*>& railEdges, int& numericalID, double maxTrainLength, bool permitReversal) {
130
// replace turnaround-via with an explicit RailEdge that checks length
131
for (const auto& viaPair : myOriginal->getViaSuccessors()) {
132
if (viaPair.first == myOriginal->getBidiEdge()) {
133
if (!permitReversal) {
134
continue;
135
}
136
// direction reversal
137
if (myTurnaround == nullptr) {
138
myTurnaround = new _RailEdge(myOriginal, viaPair.first, numericalID++);
139
myViaSuccessors.push_back(std::make_pair(myTurnaround, nullptr));
140
railEdges.push_back(myTurnaround);
141
#ifdef RailEdge_DEBUG_INIT
142
std::cout << " added new turnaround " << myTurnaround->getID() << "\n";
143
#endif
144
}
145
#ifdef RailEdge_DEBUG_INIT
146
std::cout << "RailEdge " << getID() << " actual turnaround " << myTurnaround->getID() << "\n";
147
#endif
148
myTurnaround->myIsVirtual = false;
149
// ensure at least one virtual turnaround (at the start of the
150
// edge) to avoid driving up to the end of long edges
151
const double initialDist = MAX2(maxTrainLength - getLength(), POSITION_EPS);
152
addVirtualTurns(myOriginal, viaPair.first, railEdges, numericalID,
153
initialDist, getLength(), std::vector<const E*> {myOriginal});
154
} else {
155
myViaSuccessors.push_back(std::make_pair(viaPair.first->getRailwayRoutingEdge(),
156
viaPair.second == nullptr ? nullptr : viaPair.second->getRailwayRoutingEdge()));
157
}
158
}
159
#ifdef RailEdge_DEBUG_SUCCESSORS
160
std::cout << "RailEdge " << getID() << " successors=" << myViaSuccessors.size() << " orig=" << myOriginal->getViaSuccessors().size() << "\n";
161
for (const auto& viaPair : myViaSuccessors) {
162
std::cout << " " << viaPair.first->getID() << "\n";
163
}
164
#endif
165
}
166
167
/// @brief Returns the index (numeric id) of the edge
168
inline int getNumericalID() const {
169
return myNumericalID;
170
}
171
172
/// @brief Returns the original edge
173
const E* getOriginal() const {
174
return myOriginal;
175
}
176
177
/** @brief Returns the id of the edge
178
* @return The original edge's id
179
*/
180
const std::string& getID() const {
181
return myOriginal != nullptr ? myOriginal->getID() : myID;
182
}
183
184
void insertOriginalEdges(double length, std::vector<const E*>& into) const {
185
if (myOriginal != nullptr) {
186
into.push_back(myOriginal);
187
} else {
188
double seen = myStartLength;
189
int nPushed = 0;
190
//std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
191
if (seen >= length && !myIsVirtual) {
192
return;
193
}
194
// we need to find a replacement edge that has a real turn
195
for (const E* edge : myReplacementEdges) {
196
into.push_back(edge);
197
nPushed++;
198
seen += edge->getLength() - REVERSAL_SLACK;
199
//std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
200
if (seen >= length && edge->isConnectedTo(*edge->getBidiEdge(), SVC_IGNORING)) {
201
break;
202
}
203
}
204
const int last = (int)into.size() - 1;
205
for (int i = 0; i < nPushed; i++) {
206
into.push_back(into[last - i]->getBidiEdge());
207
}
208
}
209
}
210
211
/** @brief Returns the length of the edge
212
* @return The original edge's length
213
*/
214
double getLength() const {
215
return myOriginal == nullptr ? 0 : myOriginal->getLength();
216
}
217
218
//const RailEdge* getBidiEdge() const {
219
// return myOriginal->getBidiEdge()->getRailwayRoutingEdge();
220
//}
221
222
bool isInternal() const {
223
return myOriginal->isInternal();
224
}
225
226
inline bool prohibits(const V* const vehicle) const {
227
#ifdef RailEdge_DEBUG_TURNS
228
if (myOriginal == nullptr && RailEdge_DEBUG_COND(vehicle)) {
229
std::cout << getID() << " maxLength=" << myMaxLength << " veh=" << vehicle->getID() << " length=" << vehicle->getLength() << "\n";
230
}
231
#endif
232
return vehicle->getLength() > myMaxLength || (myOriginal != nullptr && myOriginal->prohibits(vehicle));
233
}
234
235
inline bool restricts(const V* const vehicle) const {
236
return myOriginal != nullptr && myOriginal->restricts(vehicle);
237
}
238
239
const ConstEdgePairVector& getViaSuccessors(SUMOVehicleClass vClass = SVC_IGNORING, bool ignoreTransientPermissions = false) const {
240
if (vClass == SVC_IGNORING || myOriginal == nullptr || myOriginal->isTazConnector()) { // || !MSNet::getInstance()->hasPermissions()) {
241
return myViaSuccessors;
242
}
243
#ifdef HAVE_FOX
244
FXMutexLock lock(mySuccessorMutex);
245
#endif
246
auto i = myClassesViaSuccessorMap.find(vClass);
247
if (i != myClassesViaSuccessorMap.end()) {
248
// can use cached value
249
return i->second;
250
}
251
// instantiate vector
252
ConstEdgePairVector& result = myClassesViaSuccessorMap[vClass];
253
// this vClass is requested for the first time. rebuild all successors
254
for (const auto& viaPair : myViaSuccessors) {
255
if (viaPair.first->myOriginal == nullptr
256
|| viaPair.first->myOriginal->isTazConnector()
257
|| myOriginal->isConnectedTo(*viaPair.first->myOriginal, vClass, ignoreTransientPermissions)) {
258
result.push_back(viaPair);
259
}
260
}
261
return result;
262
}
263
264
bool isVirtual() const {
265
return myIsVirtual;
266
}
267
268
private:
269
const int myNumericalID;
270
const std::string myID;
271
const E* myOriginal;
272
_RailEdge* myTurnaround;
273
bool myIsVirtual;
274
275
/// @brief actual edges to return when passing this (turnaround) edge - only forward
276
std::vector<const E*> myReplacementEdges;
277
278
/// @brief maximum train length for passing this (turnaround) edge
279
double myMaxLength = std::numeric_limits<double>::max();
280
/// @brief length of the edge where this turn starts
281
double myStartLength = 0;
282
283
/// @brief The successors available for a given vClass
284
mutable std::map<SUMOVehicleClass, ConstEdgePairVector> myClassesViaSuccessorMap;
285
286
mutable ConstEdgePairVector myViaSuccessors;
287
288
#ifdef HAVE_FOX
289
/// @brief Mutex for accessing successor edges
290
mutable FXMutex mySuccessorMutex;
291
#endif
292
293
};
294
295