Eclipse SUMO - Simulation of Urban MObility
RailEdge.h
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 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 /****************************************************************************/
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 // ===========================================================================
37 template<class E, class V>
38 class RailEdge {
39 public:
41  typedef std::vector<std::pair<const _RailEdge*, const _RailEdge*> > ConstEdgePairVector;
42 
43  RailEdge(const E* orig) :
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 
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) {
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  // direction reversal
134  if (myTurnaround == nullptr) {
135  myTurnaround = new _RailEdge(myOriginal, viaPair.first, numericalID++);
136  myViaSuccessors.push_back(std::make_pair(myTurnaround, nullptr));
137  railEdges.push_back(myTurnaround);
138 #ifdef RailEdge_DEBUG_INIT
139  std::cout << " added new turnaround " << myTurnaround->getID() << "\n";
140 #endif
141  }
142 #ifdef RailEdge_DEBUG_INIT
143  std::cout << "RailEdge " << getID() << " actual turnaround " << myTurnaround->getID() << "\n";
144 #endif
145  myTurnaround->myIsVirtual = false;
146  // ensure at least one virtual turnaround (at the start of the
147  // edge) to avoid driving up to the end of long edges
148  const double initialDist = MAX2(maxTrainLength - getLength(), POSITION_EPS);
149  addVirtualTurns(myOriginal, viaPair.first, railEdges, numericalID,
150  initialDist, getLength(), std::vector<const E*> {myOriginal});
151  } else {
152  myViaSuccessors.push_back(std::make_pair(viaPair.first->getRailwayRoutingEdge(),
153  viaPair.second == nullptr ? nullptr : viaPair.second->getRailwayRoutingEdge()));
154  }
155  }
156 #ifdef RailEdge_DEBUG_SUCCESSORS
157  std::cout << "RailEdge " << getID() << " successors=" << myViaSuccessors.size() << " orig=" << myOriginal->getViaSuccessors().size() << "\n";
158  for (const auto& viaPair : myViaSuccessors) {
159  std::cout << " " << viaPair.first->getID() << "\n";
160  }
161 #endif
162  }
163 
165  inline int getNumericalID() const {
166  return myNumericalID;
167  }
168 
170  const E* getOriginal() const {
171  return myOriginal;
172  }
173 
177  const std::string& getID() const {
178  return myOriginal != nullptr ? myOriginal->getID() : myID;
179  }
180 
181  void insertOriginalEdges(double length, std::vector<const E*>& into) const {
182  if (myOriginal != nullptr) {
183  into.push_back(myOriginal);
184  } else {
185  double seen = myStartLength;
186  int nPushed = 0;
187  //std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
188  if (seen >= length && !myIsVirtual) {
189  return;
190  }
191  // we need to find a replacement edge that has a real turn
192  for (const E* edge : myReplacementEdges) {
193  into.push_back(edge);
194  nPushed++;
195  seen += edge->getLength() - REVERSAL_SLACK;
196  //std::cout << "insertOriginalEdges e=" << getID() << " length=" << length << " seen=" << seen << " into=" << toString(into) << "\n";
197  if (seen >= length && edge->isConnectedTo(*edge->getBidiEdge(), SVC_IGNORING)) {
198  break;
199  }
200  }
201  const int last = (int)into.size() - 1;
202  for (int i = 0; i < nPushed; i++) {
203  into.push_back(into[last - i]->getBidiEdge());
204  }
205  }
206  }
207 
211  double getLength() const {
212  return myOriginal == nullptr ? 0 : myOriginal->getLength();
213  }
214 
215  //const RailEdge* getBidiEdge() const {
216  // return myOriginal->getBidiEdge()->getRailwayRoutingEdge();
217  //}
218 
219  bool isInternal() const {
220  return myOriginal->isInternal();
221  }
222 
223  inline bool prohibits(const V* const vehicle) const {
224 #ifdef RailEdge_DEBUG_TURNS
225  if (myOriginal == nullptr && RailEdge_DEBUG_COND(vehicle)) {
226  std::cout << getID() << " maxLength=" << myMaxLength << " veh=" << vehicle->getID() << " length=" << vehicle->getLength() << "\n";
227  }
228 #endif
229  return vehicle->getLength() > myMaxLength || (myOriginal != nullptr && myOriginal->prohibits(vehicle));
230  }
231 
232  inline bool restricts(const V* const vehicle) const {
233  return myOriginal != nullptr && myOriginal->restricts(vehicle);
234  }
235 
236  const ConstEdgePairVector& getViaSuccessors(SUMOVehicleClass vClass = SVC_IGNORING, bool ignoreTransientPermissions = false) const {
237  UNUSED_PARAMETER(ignoreTransientPermissions); // @todo this should be changed (somewhat hidden by #14756)
238  if (vClass == SVC_IGNORING || myOriginal == nullptr || myOriginal->isTazConnector()) { // || !MSNet::getInstance()->hasPermissions()) {
239  return myViaSuccessors;
240  }
241 #ifdef HAVE_FOX
242  FXMutexLock lock(mySuccessorMutex);
243 #endif
244  auto i = myClassesViaSuccessorMap.find(vClass);
245  if (i != myClassesViaSuccessorMap.end()) {
246  // can use cached value
247  return i->second;
248  }
249  // instantiate vector
251  // this vClass is requested for the first time. rebuild all successors
252  for (const auto& viaPair : myViaSuccessors) {
253  if (viaPair.first->myOriginal == nullptr
254  || viaPair.first->myOriginal->isTazConnector()
255  || myOriginal->isConnectedTo(*viaPair.first->myOriginal, vClass)) {
256  result.push_back(viaPair);
257  }
258  }
259  return result;
260  }
261 
262  bool isVirtual() const {
263  return myIsVirtual;
264  }
265 
266 private:
267  const int myNumericalID;
268  const std::string myID;
269  const E* myOriginal;
272 
274  std::vector<const E*> myReplacementEdges;
275 
277  double myMaxLength = std::numeric_limits<double>::max();
279  double myStartLength = 0;
280 
282  mutable std::map<SUMOVehicleClass, ConstEdgePairVector> myClassesViaSuccessorMap;
283 
285 
286 #ifdef HAVE_FOX
288  mutable FXMutex mySuccessorMutex;
289 #endif
290 
291 };
#define REVERSAL_SLACK
Definition: RailEdge.h:31
#define RailEdge_DEBUG_COND(obj)
Definition: RailEdge.h:29
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_IGNORING
vehicles ignoring classes
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
the edge type representing backward edges
Definition: RailEdge.h:38
RailEdge(const E *orig)
Definition: RailEdge.h:43
const std::string myID
Definition: RailEdge.h:268
double myStartLength
length of the edge where this turn starts
Definition: RailEdge.h:279
void insertOriginalEdges(double length, std::vector< const E * > &into) const
Definition: RailEdge.h:181
bool myIsVirtual
Definition: RailEdge.h:271
int getNumericalID() const
Returns the index (numeric id) of the edge.
Definition: RailEdge.h:165
const E * getOriginal() const
Returns the original edge.
Definition: RailEdge.h:170
ConstEdgePairVector myViaSuccessors
Definition: RailEdge.h:284
std::vector< const E * > myReplacementEdges
actual edges to return when passing this (turnaround) edge - only forward
Definition: RailEdge.h:274
void addVirtualTurns(const E *forward, const E *backward, std::vector< _RailEdge * > &railEdges, int &numericalID, double dist, double maxTrainLength, const std::vector< const E * > &replacementEdges)
Definition: RailEdge.h:76
bool isVirtual() const
Definition: RailEdge.h:262
double getLength() const
Returns the length of the edge.
Definition: RailEdge.h:211
virtual ~RailEdge()
Destructor.
Definition: RailEdge.h:62
const ConstEdgePairVector & getViaSuccessors(SUMOVehicleClass vClass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Definition: RailEdge.h:236
const E * myOriginal
Definition: RailEdge.h:269
const int myNumericalID
Definition: RailEdge.h:267
bool isInternal() const
Definition: RailEdge.h:219
double myMaxLength
maximum train length for passing this (turnaround) edge
Definition: RailEdge.h:277
bool prohibits(const V *const vehicle) const
Definition: RailEdge.h:223
RailEdge< E, V > _RailEdge
Definition: RailEdge.h:40
bool restricts(const V *const vehicle) const
Definition: RailEdge.h:232
std::map< SUMOVehicleClass, ConstEdgePairVector > myClassesViaSuccessorMap
The successors available for a given vClass.
Definition: RailEdge.h:282
std::vector< std::pair< const _RailEdge *, const _RailEdge * > > ConstEdgePairVector
Definition: RailEdge.h:41
void init(std::vector< _RailEdge * > &railEdges, int &numericalID, double maxTrainLength)
Definition: RailEdge.h:129
_RailEdge * myTurnaround
Definition: RailEdge.h:270
RailEdge(const E *turnStart, const E *turnEnd, int numericalID)
Definition: RailEdge.h:50
void update(double maxTrainLength, const std::vector< const E * > &replacementEdges)
Definition: RailEdge.h:66
const std::string & getID() const
Returns the id of the edge.
Definition: RailEdge.h:177