Eclipse SUMO - Simulation of Urban MObility
NBAlgorithms_Railway.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-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 /****************************************************************************/
15 // Algorithms for highway on-/off-ramps computation
16 /****************************************************************************/
17 
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
24 #include <cassert>
27 #include <utils/common/ToString.h>
32 #include "NBNetBuilder.h"
33 #include "NBAlgorithms.h"
34 #include "NBNodeCont.h"
35 #include "NBEdgeCont.h"
36 #include "NBNode.h"
37 #include "NBEdge.h"
38 #include "NBVehicle.h"
39 #include "NBAlgorithms_Railway.h"
40 
41 //#define DEBUG_SEQSTOREVERSE
42 #define DEBUGNODEID "gneJ34"
43 #define DEBUGNODEID2 "28842974"
44 #define DEBUGEDGEID "22820560#0"
45 #define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID))
46 
47 #define SHARP_THRESHOLD_SAMEDIR 100
48 #define SHARP_THRESHOLD 80
49 
50 // ===========================================================================
51 // static members
52 // ===========================================================================
53 
54 // ---------------------------------------------------------------------------
55 // Track methods
56 // ---------------------------------------------------------------------------
57 
58 void
60  successors.push_back(track);
61  viaSuccessors.push_back(std::make_pair(track, nullptr));
62  minPermissions &= track->edge->getPermissions();
63 }
64 
65 const std::vector<NBRailwayTopologyAnalyzer::Track*>&
67  if ((minPermissions & svc) != 0) {
68  return successors;
69  } else {
70  if (svcSuccessors.count(svc) == 0) {
71  std::vector<Track*> succ;
72  for (Track* t : successors) {
73  if ((t->edge->getPermissions() & svc) != 0) {
74  succ.push_back(t);
75  }
76  }
77  svcSuccessors[svc] = succ;
78  }
79  return svcSuccessors[svc];
80  }
81 }
82 
83 const std::vector<std::pair<const NBRailwayTopologyAnalyzer::Track*, const NBRailwayTopologyAnalyzer::Track*> >&
85  if ((minPermissions & svc) != 0) {
86  return viaSuccessors;
87  } else {
88  if (svcViaSuccessors.count(svc) == 0) {
89  std::vector<std::pair<const Track*, const Track*> >& succ = svcViaSuccessors[svc];
90  for (const Track* const t : successors) {
91  if ((t->edge->getPermissions() & svc) != 0) {
92  succ.push_back(std::make_pair(t, nullptr));
93  }
94  }
95  }
96  return svcViaSuccessors[svc];
97  }
98 }
99 
100 // ===========================================================================
101 // method definitions
102 // ===========================================================================
103 void
105  getBrokenRailNodes(nb, true);
106 }
107 
108 
109 void
111  extendBidiEdges(nb);
112  reverseEdges(nb);
116  if (OptionsCont::getOptions().getBool("railway.topology.repair.connect-straight")) {
119  extendBidiEdges(nb);
120  }
121 }
122 
123 
124 void
126  int numRailEdges = 0;
127  int numBidiEdges = 0;
128  int numNotCenterEdges = 0;
129  int numAddedBidiEdges = 0;
130  for (NBEdge* edge : nb.getEdgeCont().getAllEdges()) {
131  if ((edge->getPermissions() & SVC_RAIL_CLASSES) != 0) {
132  numRailEdges++;
133  // rebuild connections if given from an earlier network
134  edge->invalidateConnections(true);
135  if (!edge->isBidiRail()) {
136  if (edge->getLaneSpreadFunction() == LANESPREAD_CENTER) {
137  NBEdge* e2 = addBidiEdge(nb, edge, false);
138  if (e2 != nullptr) {
139  numAddedBidiEdges++;
140  }
141  } else {
142  numNotCenterEdges++;
143  }
144  } else {
145  numBidiEdges++;
146  }
147  }
148  }
149  WRITE_MESSAGE("Added " + toString(numAddedBidiEdges) + " bidi-edges to ensure that all tracks are usable in both directions.");
150  if (numNotCenterEdges) {
151  WRITE_WARNING("Ignore " + toString(numNotCenterEdges) + " edges because they have the wrong spreadType");
152  }
153 }
154 
155 NBEdge*
157  assert(edge->getLaneSpreadFunction() == LANESPREAD_CENTER);
158  assert(!edge->isBidiRail());
159  const std::string id2 = (edge->getID()[0] == '-'
160  ? edge->getID().substr(1)
161  : "-" + edge->getID());
162  if (nb.getEdgeCont().retrieve(id2) == nullptr) {
163  NBEdge* e2 = new NBEdge(id2, edge->getToNode(), edge->getFromNode(),
164  edge, edge->getGeometry().reverse());
165  nb.getEdgeCont().insert(e2);
166  if (update) {
167  updateTurns(edge);
168  // reconnected added edges
170  }
171  return e2;
172  } else {
173  WRITE_WARNING("Could not add bidi-edge '" + id2 + "'.");
174  return nullptr;
175  }
176 }
177 
178 void
180  EdgeVector& inEdges, EdgeVector& outEdges) {
181  for (NBEdge* e : node->getIncomingEdges()) {
182  if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
183  inEdges.push_back(e);
184  }
185  }
186  for (NBEdge* e : node->getOutgoingEdges()) {
187  if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
188  outEdges.push_back(e);
189  }
190  }
191 }
192 
193 
194 
195 std::set<NBNode*>
197  std::set<NBNode*> brokenNodes;
198  OutputDevice& device = OutputDevice::getDevice(verbose
199  ? OptionsCont::getOptions().getString("railway.topology.output")
200  : "/dev/null");
201 
202  device.writeXMLHeader("railwayTopology", "");
203  std::set<NBNode*> railNodes = getRailNodes(nb, verbose);
204  std::map<std::pair<int, int>, std::set<NBNode*, ComparatorIdLess> > types;
205  std::set<NBEdge*, ComparatorIdLess> bidiEdges;
206  std::set<NBEdge*, ComparatorIdLess> bufferStops;
207  for (NBNode* node : railNodes) {
208  EdgeVector inEdges, outEdges;
209  getRailEdges(node, inEdges, outEdges);
210  types[std::make_pair((int)inEdges.size(), (int)outEdges.size())].insert(node);
211  for (NBEdge* e : outEdges) {
212  if (e->isBidiRail() && bidiEdges.count(e->getTurnDestination(true)) == 0) {
213  NBEdge* primary = e;
214  NBEdge* secondary = e->getTurnDestination(true);
215  if (e->getID()[0] == '-') {
216  std::swap(primary, secondary);
217  } else if (primary->getID()[0] != '-' && secondary->getID()[0] != '-' && secondary->getID() < primary->getID()) {
218  std::swap(primary, secondary);
219  }
220  if (bidiEdges.count(secondary) == 0) {
221  // avoid duplicate when both ids start with '-'
222  bidiEdges.insert(primary);
223  }
224  }
225  }
226  }
227 
228  int numBrokenA = 0;
229  int numBrokenB = 0;
230  int numBrokenC = 0;
231  int numBrokenD = 0;
232  int numBufferStops = 0;
233  if (verbose && types.size() > 0) {
234  WRITE_MESSAGE("Railway nodes by number of incoming,outgoing edges:")
235  }
236  device.openTag("legend");
237  device.openTag("error");
238  device.writeAttr(SUMO_ATTR_ID, "a");
239  device.writeAttr("meaning", "edge pair angle supports driving but both are outgoing");
240  device.closeTag();
241  device.openTag("error");
242  device.writeAttr(SUMO_ATTR_ID, "b");
243  device.writeAttr("meaning", "edge pair angle supports driving but both are incoming");
244  device.closeTag();
245  device.openTag("error");
246  device.writeAttr(SUMO_ATTR_ID, "c");
247  device.writeAttr("meaning", "an incoming edge has a sharp angle to all outgoing edges");
248  device.closeTag();
249  device.openTag("error");
250  device.writeAttr(SUMO_ATTR_ID, "d");
251  device.writeAttr("meaning", "an outgoing edge has a sharp angle from all incoming edges");
252  device.closeTag();
253  device.closeTag();
254 
255  for (auto it : types) {
256  int numBrokenType = 0;
257  device.openTag("railNodeType");
258  int in = it.first.first;
259  int out = it.first.second;
260  device.writeAttr("in", in);
261  device.writeAttr("out", out);
262  for (NBNode* n : it.second) {
263  device.openTag(SUMO_TAG_NODE);
264  device.writeAttr(SUMO_ATTR_ID, n->getID());
265  EdgeVector inRail, outRail;
266  getRailEdges(n, inRail, outRail);
267  // check if there is a mismatch between angle and edge direction
268  // (see above)
269 
270  std::string broken = "";
271  if (in < 2 && hasStraightPair(n, outRail, outRail)) {
272  broken += "a";
273  numBrokenA++;
274  }
275  if (out < 2 && hasStraightPair(n, inRail, inRail)) {
276  broken += "b";
277  numBrokenB++;
278  }
279  if (out > 0) {
280  for (NBEdge* e : inRail) {
281  EdgeVector tmp;
282  tmp.push_back(e);
283  if (allSharp(n, tmp, outRail)) {
284  broken += "c";
285  numBrokenC++;
286  break;
287  }
288  }
289  }
290  if (in > 0) {
291  for (NBEdge* e : outRail) {
292  EdgeVector tmp;
293  tmp.push_back(e);
294  if (allSharp(n, inRail, tmp)) {
295  broken += "d";
296  numBrokenD++;
297  break;
298  }
299  }
300  }
301  // do not mark bidi nodes as broken
302  if (((in == 1 && out == 1) || (in == 2 && out == 2))
303  && allBidi(inRail) && allBidi(outRail)) {
304  broken = "";
305  }
306 
307  if (broken.size() > 0) {
308  device.writeAttr("broken", broken);
309  brokenNodes.insert(n);
310  numBrokenType++;
311  }
312  if (StringUtils::toBool(n->getParameter("buffer_stop", "false"))) {
313  device.writeAttr("buffer_stop", "true");
314  numBufferStops++;
315  }
316  device.closeTag();
317  }
318  device.closeTag();
319  if (verbose) {
320  WRITE_MESSAGE(" " + toString(it.first.first) + "," + toString(it.first.second)
321  + " count: " + toString(it.second.size()) + " broken: " + toString(numBrokenType));
322  }
323 
324  }
325  if (verbose) {
326  WRITE_MESSAGE("Found " + toString(brokenNodes.size()) + " broken railway nodes "
327  + "(A=" + toString(numBrokenA)
328  + " B=" + toString(numBrokenB)
329  + " C=" + toString(numBrokenC)
330  + " D=" + toString(numBrokenD)
331  + ")");
332  WRITE_MESSAGE("Found " + toString(numBufferStops) + " railway nodes marked as buffer_stop");
333  }
334 
335  for (NBEdge* e : bidiEdges) {
336  device.openTag("bidiEdge");
337  device.writeAttr(SUMO_ATTR_ID, e->getID());
338  device.writeAttr("bidi", e->getTurnDestination(true)->getID());
339  device.closeTag();
340  }
341  if (verbose) {
342  WRITE_MESSAGE("Found " + toString(bidiEdges.size()) + " bidirectional rail edges");
343  }
344 
345  device.close();
346  return brokenNodes;
347 }
348 
349 
350 std::set<NBNode*>
352  std::set<NBNode*> railNodes;
353 
354  NBEdgeCont& ec = nb.getEdgeCont();
355  int numRailEdges = 0;
356  for (auto it = ec.begin(); it != ec.end(); it++) {
357  if (isRailway(it->second->getPermissions())) {
358  numRailEdges++;
359  railNodes.insert(it->second->getFromNode());
360  railNodes.insert(it->second->getToNode());
361 
362  }
363  }
364  std::set<NBNode*> railSignals;
365  for (NBNode* node : railNodes) {
366  if (node->getType() == NODETYPE_RAIL_SIGNAL) {
367  railSignals.insert(node);
368  }
369  }
370  if (verbose) {
371  WRITE_MESSAGE("Found " + toString(numRailEdges) + " railway edges and " + toString(railNodes.size()) + " railway nodes (" + toString(railSignals.size()) + " signals).");
372  }
373  return railNodes;
374 }
375 
376 
377 bool
378 NBRailwayTopologyAnalyzer::isStraight(const NBNode* node, const NBEdge* e1, const NBEdge* e2) {
379  const double relAngle = NBHelpers::normRelAngle(e1->getAngleAtNode(node), e2->getAngleAtNode(node));
380  /*
381  std::cout << " isStraight n=" << node->getID()
382  << " e1=" << e1->getID()
383  << " e2=" << e2->getID()
384  << " a1=" << e1->getAngleAtNode(node)
385  << " a2=" << e2->getAngleAtNode(node)
386  << " rel=" << relAngle
387  << "\n";
388  */
389  if ((e1->getToNode() == node && e2->getFromNode() == node)
390  || (e1->getFromNode() == node && e2->getToNode() == node)) {
391  // edges go in the same direction
392  return fabs(relAngle) < SHARP_THRESHOLD;
393  } else {
394  // edges go in the opposite direction (both incoming or outgoing)
395  return fabs(relAngle) > SHARP_THRESHOLD_SAMEDIR;
396  }
397 }
398 
399 
400 bool
402  const EdgeVector& edges2) {
403 #ifdef DEBUG_SEQSTOREVERSE
404  //if (node->getID() == DEBUGNODEID2) {
405  // std::cout << " edges=" << toString(edges) << " edges2=" << toString(edges2) << "\n";
406  //}
407 #endif
408  for (NBEdge* e1 : edges) {
409  for (NBEdge* e2 : edges2) {
410  //if (e1->getID() == "195411601#2" && e2->getID() == "93584120#3") {
411  // std::cout
412  // << " DEBUG normRelA=" << NBHelpers::normRelAngle(
413  // e1->getAngleAtNode(node),
414  // e2->getAngleAtNode(node))
415  // << "\n";
416  //}
417  if (e1 != e2 && isStraight(node, e1, e2)) {
418  return true;
419  }
420  }
421  }
422  return false;
423 }
424 
425 
426 bool
427 NBRailwayTopologyAnalyzer::allBroken(const NBNode* node, NBEdge* candOut, const EdgeVector& in, const EdgeVector& out) {
428  for (NBEdge* e : in) {
429  if (e != candOut && isStraight(node, e, candOut)) {
430  if (gDebugFlag1) {
431  std::cout << " isStraight e=" << e->getID() << " candOut=" << candOut->getID() << "\n";
432  }
433  return false;
434  }
435  }
436  for (NBEdge* e : out) {
437  if (e != candOut && !isStraight(node, e, candOut)) {
438  if (gDebugFlag1) {
439  std::cout << " isSharp e=" << e->getID() << " candOut=" << candOut->getID() << "\n";
440  }
441  return false;
442  }
443  }
444  return true;
445 }
446 
447 
448 bool
449 NBRailwayTopologyAnalyzer::allSharp(const NBNode* node, const EdgeVector& in, const EdgeVector& out, bool countBidiAsSharp) {
450  bool allBidi = true;
451  for (NBEdge* e1 : in) {
452  for (NBEdge* e2 : out) {
453  if (e1 != e2 && isStraight(node, e1, e2)) {
454  return false;
455  }
456  if (!e1->isBidiRail(true)) {
457  //std::cout << " allSharp node=" << node->getID() << " e1=" << e1->getID() << " is not bidi\n";
458  allBidi = false;
459  }
460  }
461  }
462  return !allBidi || countBidiAsSharp;
463 }
464 
465 
466 bool
468  for (NBEdge* e : edges) {
469  if (!e->isBidiRail()) {
470  return false;
471  }
472  }
473  return true;
474 }
475 
476 
477 int
479  int added = 0;
480  std::set<NBNode*> railNodes = getRailNodes(nb);
481  NBEdgeCont& ec = nb.getEdgeCont();
482  for (auto it = ec.begin(); it != ec.end(); it++) {
483  NBEdge* e = it->second;
484  if (e->isBidiRail()) {
485  added += extendBidiEdges(nb, e->getFromNode(), e->getTurnDestination(true));
486  added += extendBidiEdges(nb, e->getToNode(), e);
487  }
488  }
489  if (added > 0) {
490  WRITE_MESSAGE("Added " + toString(added) + " bidi-edges as extension of existing bidi edges.");
491  }
492  return added;
493 }
494 
495 
496 int
498  assert(bidiIn->getToNode() == node);
499  NBEdge* bidiOut = bidiIn->getTurnDestination(true);
500  if (bidiOut == nullptr) {
501  WRITE_WARNING("Could not find bidi-edge for edge '" + bidiIn->getID() + "'");
502  return 0;
503  }
504  EdgeVector tmpBidiOut;
505  tmpBidiOut.push_back(bidiOut);
506  EdgeVector tmpBidiIn;
507  tmpBidiIn.push_back(bidiIn);
508  int added = 0;
509  EdgeVector inRail, outRail;
510  getRailEdges(node, inRail, outRail);
511  for (NBEdge* cand : outRail) {
512  //std::cout << " extendBidiEdges n=" << node->getID() << " bidiIn=" << bidiIn->getID() << " cand=" << cand->getID() << " isStraight=" << isStraight(node, bidiIn, cand) << " allSharp=" << allSharp(node, inRail, tmpBidiOut, true) << "\n";
513  if (!cand->isBidiRail() && isStraight(node, bidiIn, cand)
514  && cand->getLaneSpreadFunction() == LANESPREAD_CENTER
515  && allSharp(node, inRail, tmpBidiOut, true)) {
516  NBEdge* e2 = addBidiEdge(nb, cand);
517  if (e2 != nullptr) {
518  added += 1 + extendBidiEdges(nb, cand->getToNode(), cand);
519  }
520  }
521  }
522  for (NBEdge* cand : inRail) {
523  //std::cout << " extendBidiEdges n=" << node->getID() << " bidiOut=" << bidiOut->getID() << " cand=" << cand->getID() << " isStraight=" << isStraight(node, cand, bidiOut) << " allSharp=" << allSharp(node, outRail, tmpBidiIn, true) << "\n";
524  if (!cand->isBidiRail() && isStraight(node, cand, bidiOut)
525  && cand->getLaneSpreadFunction() == LANESPREAD_CENTER
526  && allSharp(node, outRail, tmpBidiIn, true)) {
527  NBEdge* e2 = addBidiEdge(nb, cand);
528  if (e2 != nullptr) {
529  added += 1 + extendBidiEdges(nb, cand->getFromNode(), e2);
530  }
531  }
532  }
533  return added;
534 }
535 
536 
537 void
539  std::set<NBNode*> brokenNodes = getBrokenRailNodes(nb);
540  // find reversible edge sequences between broken nodes
541  std::vector<EdgeVector> seqsToReverse;
542  for (NBNode* n : brokenNodes) {
543  EdgeVector inRail, outRail;
544  getRailEdges(n, inRail, outRail);
545  for (NBEdge* start : outRail) {
546  EdgeVector tmp;
547  tmp.push_back(start);
548  // only reverse edges where the node would be unbroken afterwards
549  if (!allBroken(n, start, inRail, outRail)
550  || (inRail.size() == 1 && outRail.size() == 1)) {
551 #ifdef DEBUG_SEQSTOREVERSE
552  if (n->getID() == DEBUGNODEID) {
553  std::cout << " abort at start n=" << n->getID() << " (not all broken)\n";
554  }
555 #endif
556  continue;
557  }
558  //std::cout << " get sequences from " << start->getID() << "\n";
559  bool forward = true;
560  EdgeVector seq;
561  while (forward) {
562  seq.push_back(start);
563  //std::cout << " seq=" << toString(seq) << "\n";
564  NBNode* n2 = start->getToNode();
565  EdgeVector inRail2, outRail2;
566  getRailEdges(n2, inRail2, outRail2);
567  if (brokenNodes.count(n2) != 0) {
568  EdgeVector tmp2;
569  tmp2.push_back(start);
570  if (allBroken(n2, start, outRail2, inRail2)) {
571  seqsToReverse.push_back(seq);
572  } else {
573 #ifdef DEBUG_SEQSTOREVERSE
574  if (n->getID() == DEBUGNODEID) {
575  std::cout << " abort at n2=" << n2->getID() << " (not all broken)\n";
576  }
577 #endif
578  }
579  forward = false;
580  } else {
581  if (outRail2.size() == 0) {
582  // stop at network border
583  forward = false;
584 #ifdef DEBUG_SEQSTOREVERSE
585  if (n->getID() == DEBUGNODEID) {
586  std::cout << " abort at n2=" << n2->getID() << " (border)\n";
587  }
588 #endif
589  } else if (outRail2.size() > 1 || inRail2.size() > 1) {
590  // stop at switch
591  forward = false;
592 #ifdef DEBUG_SEQSTOREVERSE
593  if (n->getID() == DEBUGNODEID) {
594  std::cout << " abort at n2=" << n2->getID() << " (switch)\n";
595  }
596 #endif
597  } else {
598  start = outRail2.front();
599  }
600  }
601  }
602  }
603  }
604  // sort by sequence length
605  if (seqsToReverse.size() > 0) {
606  WRITE_MESSAGE("Found " + toString(seqsToReverse.size()) + " reversible edge sequences between broken rail nodes");
607  }
608  std::sort(seqsToReverse.begin(), seqsToReverse.end(),
609  [](const EdgeVector & a, const EdgeVector & b) {
610  return a.size() < b.size();
611  });
612  int numReversed = 0;
613  std::set<NBNode*> affectedEndpoints;
614  std::set<std::string> reversedIDs;
615  std::map<int, int> seqLengths;
616  for (EdgeVector& seq : seqsToReverse) {
617  NBNode* seqStart = seq.front()->getFromNode();
618  NBNode* seqEnd = seq.back()->getToNode();
619  // avoid reversing sequenes on both sides of a broken node
620  if (affectedEndpoints.count(seqStart) == 0
621  && affectedEndpoints.count(seqEnd) == 0) {
622  affectedEndpoints.insert(seqStart);
623  affectedEndpoints.insert(seqEnd);
624  //WRITE_MESSAGE(" reversed seq=" + toString(seq));
625  for (NBEdge* e : seq) {
626  e->reinitNodes(e->getToNode(), e->getFromNode());
627  e->setGeometry(e->getGeometry().reverse());
628  reversedIDs.insert(e->getID());
629  }
630  seqLengths[(int)seq.size()]++;
631  numReversed++;
632  }
633  }
634  if (numReversed > 0) {
635  WRITE_MESSAGE("Reversed " + toString(numReversed) + " sequences (count by length: " + joinToString(seqLengths, " ", ":") + ")");
636  for (auto& item : nb.getPTStopCont().getStops()) {
637  if (reversedIDs.count(item.second->getEdgeId())) {
638  item.second->findLaneAndComputeBusStopExtent(nb.getEdgeCont());
639  }
640  }
641  }
642 }
643 
644 
645 void
647  std::set<NBNode*> brokenNodes = getBrokenRailNodes(nb);
648  std::set<NBNode*> railNodes = getRailNodes(nb);
649  // find buffer stops and ensure that thay are connect to the network in both directions
650  int numBufferStops = 0;
651  int numAddedBidiTotal = 0;
652  for (NBNode* node : railNodes) {
653  if (StringUtils::toBool(node->getParameter("buffer_stop", "false"))) {
654  if (node->getEdges().size() != 1) {
655  WRITE_WARNING("Ignoring buffer stop junction '" + node->getID() + "' with " + toString(node->getEdges().size()) + " edges\n");
656  continue;
657  }
658  int numAddedBidi = 0;
659  numBufferStops++;
660  NBEdge* prev = nullptr;
661  NBEdge* prev2 = nullptr;
662  EdgeVector inRail, outRail;
663  getRailEdges(node, inRail, outRail);
664  bool addAway = true; // add new edges away from buffer stop
665  while (prev == nullptr || (inRail.size() + outRail.size()) == 3) {
666  NBEdge* e = nullptr;
667  if (prev == nullptr) {
668  assert(node->getEdges().size() == 1);
669  e = node->getEdges().front();
670  addAway = node == e->getToNode();
671  } else {
672  if (addAway) {
673  // XXX if node is broken we need to switch direction
674  assert(inRail.size() == 2);
675  e = inRail.front() == prev2 ? inRail.back() : inRail.front();
676  } else {
677  // XXX if node is broken we need to switch direction
678  assert(outRail.size() == 2);
679  e = outRail.front() == prev2 ? outRail.back() : outRail.front();
680  }
681  }
683  NBNode* e2From = nullptr;
684  NBNode* e2To = nullptr;
685  if (addAway) {
686  e2From = node;
687  e2To = e->getFromNode();
688  node = e2To;
689  } else {
690  e2From = e->getToNode();
691  e2To = node;
692  node = e2From;
693  }
694  NBEdge* e2 = addBidiEdge(nb, e);
695  if (e2 == nullptr) {
696  break;
697  }
698  prev = e;
699  prev2 = e2;
700  numAddedBidi++;
701  numAddedBidiTotal++;
702  inRail.clear();
703  outRail.clear();
704  getRailEdges(node, inRail, outRail);
705  }
706  //if (numAddedBidi > 0) {
707  // WRITE_MESSAGE(" added " + toString(numAddedBidi) + " edges between buffer stop junction '" + bufferStop->getID() + "' and junction '" + node->getID() + "'");
708  //}
709  }
710  }
711  if (numAddedBidiTotal > 0) {
712  WRITE_MESSAGE("Added " + toString(numAddedBidiTotal) + " edges to connect " + toString(numBufferStops) + " buffer stops in both directions.");
713  }
714 }
715 
716 NBEdge*
718  EdgeVector inRail, outRail;
719  getRailEdges(n, inRail, outRail);
720  if (inRail.size() == 2 && outRail.size() == 1 && isStraight(n, inRail.front(), inRail.back())) {
721  if (isStraight(n, inRail.front(), outRail.front())) {
722  return inRail.front();
723  } else if (isStraight(n, inRail.back(), outRail.front())) {
724  return inRail.back();
725  }
726  }
727  if (inRail.size() == 1 && outRail.size() == 2 && isStraight(n, outRail.front(), outRail.back())) {
728  if (isStraight(n, outRail.front(), inRail.front())) {
729  return outRail.front();
730  } else if (isStraight(n, outRail.back(), inRail.front())) {
731  return outRail.back();
732  }
733  }
734  return nullptr;
735 }
736 
737 
738 void
740  std::set<NBNode*> brokenNodes = getBrokenRailNodes(nb);
741  std::map<int, int> seqLengths;
742  int numAdded = 0;
743  int numSeqs = 0;
744  for (NBNode* n : brokenNodes) {
745  NBEdge* edge = isBidiSwitch(n);
746  if (edge != nullptr) {
747  std::vector<NBNode*> nodeSeq;
748  EdgeVector edgeSeq;
749  NBNode* prev = n;
750  nodeSeq.push_back(prev);
751  edgeSeq.push_back(edge);
752  bool forward = true;
753  //std::cout << "Looking for potential bidi-edge sequence starting at junction '" << n->getID() << "' with edge '" + edge->getID() << "'\n";
754  // find a suitable end point for adding bidi edges
755  while (forward) {
756  NBNode* next = edge->getFromNode() == prev ? edge->getToNode() : edge->getFromNode();
757  EdgeVector allRail;
758  getRailEdges(next, allRail, allRail);
759  if (allRail.size() == 2 && isStraight(next, allRail.front(), allRail.back())) {
760  prev = next;
761  edge = allRail.front() == edge ? allRail.back() : allRail.front();
762  nodeSeq.push_back(prev);
763  edgeSeq.push_back(edge);
764  } else {
765  forward = false;
766  EdgeVector inRail2, outRail2;
767  getRailEdges(next, inRail2, outRail2);
768  if (isBidiSwitch(next) == edge) {
769  // suitable switch found as endpoint, add reverse edges
770  //WRITE_MESSAGE("Adding " + toString(edgeSeq.size())
771  // + " bidi-edges between switches junction '" + n->getID() + "' and junction '" + next->getID() + "'");
772  for (NBEdge* e : edgeSeq) {
773  addBidiEdge(nb, e);
774  }
775  seqLengths[(int)edgeSeq.size()]++;
776  numSeqs++;
777  numAdded += (int)edgeSeq.size();
778  } else {
779  //std::cout << " sequence ended at junction " << next->getID()
780  // << " in=" << inRail2.size()
781  // << " out=" << outRail2.size()
782  // << " bidiSwitch=" << Named::getIDSecure(isBidiSwitch(next))
783  // << "\n";
784  }
785 
786  }
787  }
788 
789  }
790  }
791  if (seqLengths.size() > 0) {
792  WRITE_MESSAGE("Added " + toString(numAdded) + " bidi-edges between " + toString(numSeqs) + " pairs of railway switches (count by length: " + joinToString(seqLengths, " ", ":") + ")");
793  }
794 }
795 
796 
797 void
799  // generate bidirectional routing graph
800  NBEdgeCont& ec = nb.getEdgeCont();
801  std::vector<Track*> tracks;
802  for (NBEdge* edge : nb.getEdgeCont().getAllEdges()) {
803  tracks.push_back(new Track(edge));
804  }
805  const int numEdges = (int)tracks.size();
806  for (NBEdge* edge : nb.getEdgeCont().getAllEdges()) {
807  tracks.push_back(new Track(edge, (int)tracks.size(), edge->getID() + "_reverse"));
808  }
809  // add special tracks for starting end ending in both directions
810  std::map<NBEdge*, std::pair<Track*, Track*> > stopTracks;
811  for (NBEdge* edge : nb.getEdgeCont().getAllEdges()) {
812  if ((edge->getPermissions() & SVC_RAIL_CLASSES) != 0) {
813  Track* start = new Track(edge, (int)tracks.size(), edge->getID() + "_start");
814  tracks.push_back(start);
815  Track* end = new Track(edge, (int)tracks.size(), edge->getID() + "_end");
816  tracks.push_back(end);
817  stopTracks[edge] = std::make_pair(start, end);
818  }
819  }
820  // set successors based on angle (connections are not yet built)
821  for (NBNode* node : getRailNodes(nb)) {
822  EdgeVector railEdges;
823  getRailEdges(node, railEdges, railEdges);
824  for (NBEdge* e1 : railEdges) {
825  for (NBEdge* e2 : railEdges) {
826  if (e1 != e2 && isStraight(node, e1, e2)) {
827  int i = e1->getNumericalID();
828  int i2 = e2->getNumericalID();
829  if (e1->getToNode() == node) {
830  if (e2->getFromNode() == node) {
831  // case 1) plain forward connection
832  tracks[i]->addSuccessor(tracks[i2]);
833  // reverse edge (numerical id incremented by numEdges)
834  tracks[i2 + numEdges]->addSuccessor(tracks[i + numEdges]);
835  } else {
836  // case 2) both edges pointing towards each ohter
837  tracks[i]->addSuccessor(tracks[i2 + numEdges]);
838  tracks[i2]->addSuccessor(tracks[i + numEdges]);
839  }
840  } else {
841  if (e2->getFromNode() == node) {
842  // case 3) both edges pointing away from each other
843  tracks[i + numEdges]->addSuccessor(tracks[i2]);
844  tracks[i2 + numEdges]->addSuccessor(tracks[i]);
845  } else {
846  // already handled via case 1)
847  }
848  }
849 
850  }
851  }
852  }
853  }
854  // define start and end successors
855  for (auto& item : stopTracks) {
856  const int index = item.first->getNumericalID();
857  // start
858  item.second.first->addSuccessor(tracks[index]);
859  item.second.first->addSuccessor(tracks[index + numEdges]);
860  // end
861  tracks[index]->addSuccessor(item.second.second);
862  tracks[index + numEdges]->addSuccessor(item.second.second);
863  }
864  // DEBUG
865  /*
866  for (Track* t : tracks) {
867  std::cout << "track " << t->getID() << " e=" << t->edge->getID() << " i=" << t->getNumericalID() << " succ:\n";
868  for (Track* s : t->getSuccessors(SVC_IGNORING)) {
869  std::cout << " succ=" << s->getID() << "\n";
870  }
871  }
872  */
873 
875  tracks, true, &NBRailwayTopologyAnalyzer::getTravelTimeStatic, nullptr, true);
876 
877  int added = 0;
878  int numDisconnected = 0;
879  std::set<NBEdge*> addBidiStops;
880  std::set<NBEdge*> addBidiEdges;
881  std::set<std::pair<NBEdge*, NBEdge*> > visited;
882  for (const auto& item : nb.getPTLineCont().getLines()) {
883  NBPTLine* line = item.second;
884  std::vector<NBEdge*> stops = line->getStopEdges(ec);
885  NBEdge* routeStart = line->getRouteStart(ec);
886  NBEdge* routeEnd = line->getRouteEnd(ec);
887  if (routeStart != nullptr) {
888  stops.insert(stops.begin(), routeStart);
889  }
890  if (routeEnd != nullptr) {
891  stops.push_back(routeEnd);
892  }
893  if (stops.size() < 2) {
894  continue;
895  }
896  for (auto it = stops.begin(); it + 1 != stops.end(); ++it) {
897  NBEdge* fromEdge = *it;
898  NBEdge* toEdge = *(it + 1);
899  std::pair<NBEdge*, NBEdge*> trip(fromEdge, toEdge);
900  //std::cout << " trip=" << Named::getIDSecure(fromEdge) << "->" << Named::getIDSecure(toEdge) << " visited=" << (visited.count(trip) != 0) << "\n";
901  if (visited.count(trip) != 0) {
902  continue;
903  } else {
904  visited.insert(trip);
905  }
906  if (stopTracks.count(fromEdge) == 0
907  || stopTracks.count(toEdge) == 0) {
908  continue;
909  }
910  NBVehicle veh(line->getRef(), (SUMOVehicleClass)(fromEdge->getPermissions() & SVC_RAIL_CLASSES));
911  std::vector<const Track*> route;
912  router->compute(stopTracks[fromEdge].first, stopTracks[toEdge].second, &veh, 0, route);
913  //if (fromEdge->getID() == "356053025#1" && toEdge->getID() == "23256161") {
914  // std::cout << "DEBUG: route=" << toString(route) << "\n";
915  //}
916  if (route.size() > 0) {
917  assert(route.size() > 2);
918  for (int i = 1; i < (int)route.size() - 1; ++i) {
919  if (route[i]->getNumericalID() >= numEdges) {
920  NBEdge* edge = route[i]->edge;
921  if (addBidiEdges.count(edge) == 0) {
922  if (!edge->isBidiRail(true)) {
923  bool isStop = i == 1 || i == (int)route.size() - 2;
924  if (edge->getLaneSpreadFunction() == LANESPREAD_CENTER) {
925  addBidiEdges.insert(edge);
926  if (isStop) {
927  addBidiStops.insert(edge);
928  }
929  } else {
930  if (isStop) {
931  WRITE_WARNING("Stop on edge " + fromEdge->getID() + " can only be reached in reverse but edge has the wrong spreadType");
932  }
933  }
934  }
935  }
936  }
937  }
938  } else {
939  WRITE_WARNING("No connection found between stops on edge '" + fromEdge->getID() + "' and edge '" + toEdge->getID() + "'");
940  numDisconnected++;
941  }
942  }
943  }
944  for (NBEdge* edge : addBidiEdges) {
945  if (!edge->isBidiRail()) {
946  NBEdge* e2 = addBidiEdge(nb, edge);
947  //std::cout << " add bidiEdge for stop at edge " << edge->getID() << "\n";
948  if (e2 != nullptr) {
949  added++;
950  added += extendBidiEdges(nb, edge->getToNode(), edge);
951  added += extendBidiEdges(nb, edge->getFromNode(), e2);
952  }
953  }
954  }
955 
956  if (addBidiEdges.size() > 0 || numDisconnected > 0) {
957  WRITE_MESSAGE("Added " + toString(addBidiStops.size()) + " bidi-edges for public transport stops and a total of "
958  + toString(added) + " bidi-edges to ensure connectivity of stops ("
959  + toString(numDisconnected) + " stops remain disconnected)");
960  }
961 
962  // clean up
963  for (Track* t : tracks) {
964  delete t;
965  }
966  delete router;
967 }
968 
969 
970 void
972  int added = 0;
973  std::set<NBNode*> brokenNodes = getBrokenRailNodes(nb);
974  for (const auto& e : nb.getEdgeCont()) {
975  if (!isRailway(e.second->getPermissions())) {
976  continue;
977  }
978  NBNode* const from = e.second->getFromNode();
979  NBNode* const to = e.second->getToNode();
980  if (brokenNodes.count(from) == 0 && brokenNodes.count(to) == 0) {
981  continue;
982  }
983  if (e.second->isBidiRail()) {
984  continue;
985  }
986  EdgeVector inRailFrom, outRailFrom, inRailTo, outRailTo;
987  getRailEdges(from, inRailFrom, outRailFrom);
988  getRailEdges(to, inRailTo, outRailTo);
989  // check whether there is a straight edge pointing away from this one at the from-node
990  // and there is no straight incoming edge at the from-node
991  bool haveStraight = false;
992  bool haveStraightReverse = false;
993  if (!geometryLike || outRailFrom.size() + inRailFrom.size() == 2) {
994  for (const NBEdge* fromStraightCand : outRailFrom) {
995  if (fromStraightCand != e.second && isStraight(from, fromStraightCand, e.second)) {
996  haveStraightReverse = true;
997  //std::cout << " haveStraightReverse outRailFrom=" << fromStraightCand->getID() << "\n";
998  break;
999  }
1000  }
1001  if (haveStraightReverse) {
1002  for (const NBEdge* fromStraightCand : inRailFrom) {
1003  if (fromStraightCand != e.second && isStraight(from, fromStraightCand, e.second)) {
1004  haveStraight = true;
1005  //std::cout << " haveStraight inRailFrom=" << fromStraightCand->getID() << "\n";
1006  break;
1007  }
1008  }
1009  }
1010  }
1011  if ((!haveStraightReverse || haveStraight) && (!geometryLike || outRailTo.size() + inRailTo.size() == 2)) {
1012  // check whether there is a straight edge pointing towards this one at the to-node
1013  // and there is no straight outoing edge at the to-node
1014  haveStraight = false;
1015  haveStraightReverse = false;
1016  for (const NBEdge* toStraightCand : inRailTo) {
1017  if (toStraightCand != e.second && isStraight(to, toStraightCand, e.second)) {
1018  haveStraightReverse = true;
1019  //std::cout << " haveStraightReverse inRailTo=" << toStraightCand->getID() << "\n";
1020  break;
1021  }
1022  }
1023  if (haveStraightReverse) {
1024  for (const NBEdge* toStraightCand : outRailTo) {
1025  if (toStraightCand != e.second && isStraight(to, toStraightCand, e.second)) {
1026  haveStraight = true;
1027  //std::cout << " haveStraightReverse outRailTo=" << toStraightCand->getID() << "\n";
1028  break;
1029  }
1030  }
1031  }
1032  }
1033  //std::cout << "edge=" << e.second->getID() << " haveStraight=" << haveStraight << " haveStraightReverse=" << haveStraightReverse << "\n";
1034  if (haveStraightReverse && !haveStraight) {
1035  NBEdge* e2 = addBidiEdge(nb, e.second);
1036  //std::cout << " add bidiEdge for straight connectivity at edge " << e.second->getID() << " fromBroken=" << brokenNodes.count(from) << " toBroken=" << brokenNodes.count(to) << "\n";
1037  if (e2 != nullptr) {
1038  added++;
1039  added += extendBidiEdges(nb, to, e.second);
1040  added += extendBidiEdges(nb, from, e2);
1041  }
1042  }
1043  }
1044  if (added > 0) {
1045  if (geometryLike) {
1046  WRITE_MESSAGE("Added " + toString(added) + " bidi-edges to ensure connectivity of straight tracks at geometry-like nodes.");
1047  } else {
1048  WRITE_MESSAGE("Added " + toString(added) + " bidi-edges to ensure connectivity of straight tracks at switches.");
1049  }
1050  }
1051 }
1052 
1053 
1054 void
1058 }
1059 
1060 
1061 double
1062 NBRailwayTopologyAnalyzer::getTravelTimeStatic(const Track* const track, const NBVehicle* const veh, double time) {
1063  return NBEdge::getTravelTimeStatic(track->edge, veh, time);
1064 }
1065 
1066 /****************************************************************************/
1067 
SUMOAbstractRouter::compute
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
SUMOVehicleClass
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
Definition: SUMOVehicleClass.h:133
NBRailwayTopologyAnalyzer::Track
routing edge
Definition: NBAlgorithms_Railway.h:58
ToString.h
NBRailwayTopologyAnalyzer::makeAllBidi
static void makeAllBidi(NBNetBuilder &nb)
Definition: NBAlgorithms_Railway.cpp:125
NBEdgeCont::retrieve
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:246
StringUtils::toBool
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
Definition: StringUtils.cpp:374
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:275
NBEdgeCont
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:60
NBNetBuilder
Instance responsible for building networks.
Definition: NBNetBuilder.h:109
OutputDevice
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:63
NBRailwayTopologyAnalyzer::isStraight
static bool isStraight(const NBNode *node, const NBEdge *e1, const NBEdge *e2)
Definition: NBAlgorithms_Railway.cpp:378
NBRailwayTopologyAnalyzer::Track::getViaSuccessors
const std::vector< std::pair< const Track *, const Track * > > & getViaSuccessors(SUMOVehicleClass svc=SVC_IGNORING) const
Definition: NBAlgorithms_Railway.cpp:84
OptionsCont.h
DEBUGNODEID
#define DEBUGNODEID
Definition: NBAlgorithms_Railway.cpp:42
MsgHandler.h
EdgeVector
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
NBRailwayTopologyAnalyzer::Track::viaSuccessors
std::vector< std::pair< const Track *, const Track * > > viaSuccessors
Definition: NBAlgorithms_Railway.h:96
NBNode::getOutgoingEdges
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:260
NBPTLine
Definition: NBPTLine.h:33
NBEdge::isBidiRail
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:691
NBEdgeCont.h
NBRailwayTopologyAnalyzer::addBidiEdgesForBufferStops
static void addBidiEdgesForBufferStops(NBNetBuilder &nb)
add bidi-edges to connect buffers stops in both directions
Definition: NBAlgorithms_Railway.cpp:646
NBHelpers::normRelAngle
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:59
OptionsCont::getOptions
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:57
NBEdgeCont::insert
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:153
SUMO_ATTR_ID
@ SUMO_ATTR_ID
Definition: SUMOXMLDefinitions.h:378
NBEdge::getPermissions
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3404
NBEdge::setLaneSpreadFunction
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:885
NBRailwayTopologyAnalyzer::updateTurns
static void updateTurns(NBEdge *edge)
recompute turning directions for both nodes of the given edge
Definition: NBAlgorithms_Railway.cpp:1055
OutputDevice::close
void close()
Closes the device and removes it from the dictionary.
Definition: OutputDevice.cpp:207
LANESPREAD_CENTER
@ LANESPREAD_CENTER
Definition: SUMOXMLDefinitions.h:1099
DijkstraRouter
Computes the shortest path through a network using the Dijkstra algorithm.
Definition: DijkstraRouter.h:61
NBNetBuilder::getEdgeCont
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:150
NBRailwayTopologyAnalyzer::getRailEdges
static void getRailEdges(const NBNode *node, EdgeVector &inEdges, EdgeVector &outEdges)
filter out rail edges among all edges of a the given node
Definition: NBAlgorithms_Railway.cpp:179
NBRailwayTopologyAnalyzer::Track::edge
NBEdge * edge
Definition: NBAlgorithms_Railway.h:90
Parameterised::getParameter
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
Definition: Parameterised.cpp:72
NBEdge
The representation of a single edge during network building.
Definition: NBEdge.h:91
OutputDevice::closeTag
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Definition: OutputDevice.cpp:253
NBRailwayTopologyAnalyzer::addBidiEdge
static NBEdge * addBidiEdge(NBNetBuilder &nb, NBEdge *edge, bool update=true)
add bidi-edge for the given edge
Definition: NBAlgorithms_Railway.cpp:156
OutputDevice::writeAttr
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:255
NBRailwayTopologyAnalyzer::extendBidiEdges
static int extendBidiEdges(NBNetBuilder &nb)
add further bidi-edges near existing bidi-edges
Definition: NBAlgorithms_Railway.cpp:478
NBTurningDirectionsComputer::computeTurnDirectionsForNode
static void computeTurnDirectionsForNode(NBNode *node, bool warn)
Computes turnaround destinations for all incoming edges of the given nodes (if any)
Definition: NBAlgorithms.cpp:54
NODETYPE_RAIL_SIGNAL
@ NODETYPE_RAIL_SIGNAL
Definition: SUMOXMLDefinitions.h:1059
NBPTLine::getStopEdges
std::vector< NBEdge * > getStopEdges(const NBEdgeCont &ec) const
get stop edges
Definition: NBPTLine.cpp:141
NBRailwayTopologyAnalyzer::hasStraightPair
static bool hasStraightPair(const NBNode *node, const EdgeVector &edges, const EdgeVector &edges2)
Definition: NBAlgorithms_Railway.cpp:401
NBEdge::getToNode
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:498
NBEdge::getGeometry
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:692
NBNetBuilder::getPTStopCont
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:176
NBRailwayTopologyAnalyzer::Track::minPermissions
SVCPermissions minPermissions
Definition: NBAlgorithms_Railway.h:97
NBNetBuilder::getPTLineCont
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:181
NBNode::invalidateIncomingConnections
void invalidateIncomingConnections()
invalidate incoming connections
Definition: NBNode.cpp:1662
SVC_RAIL_CLASSES
@ SVC_RAIL_CLASSES
classes which drive on tracks
Definition: SUMOVehicleClass.h:204
NBEdgeCont::size
int size() const
Returns the number of edges.
Definition: NBEdgeCont.h:304
NBRailwayTopologyAnalyzer::repairTopology
static void repairTopology(NBNetBuilder &nb)
Definition: NBAlgorithms_Railway.cpp:110
SHARP_THRESHOLD_SAMEDIR
#define SHARP_THRESHOLD_SAMEDIR
Definition: NBAlgorithms_Railway.cpp:47
update
NBPTLineCont::getLines
const std::map< std::string, NBPTLine * > & getLines() const
Definition: NBPTLineCont.h:38
OutputDevice.h
NBNetBuilder.h
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:363
NBVehicle
A vehicle as used by router.
Definition: NBVehicle.h:43
NBRailwayTopologyAnalyzer::getRailNodes
static std::set< NBNode * > getRailNodes(NBNetBuilder &nb, bool verbose=false)
Definition: NBAlgorithms_Railway.cpp:351
NBEdgeCont::end
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:192
SHARP_THRESHOLD
#define SHARP_THRESHOLD
Definition: NBAlgorithms_Railway.cpp:48
NBEdgeCont::getAllEdges
EdgeVector getAllEdges() const
return all edges
Definition: NBEdgeCont.cpp:1599
SUMOAbstractRouter
Definition: SUMOAbstractRouter.h:46
NBPTLine::getRouteEnd
NBEdge * getRouteEnd(const NBEdgeCont &ec) const
return last valid edge of myRoute (if it doest not lie before the last stop)
Definition: NBPTLine.cpp:182
NBRailwayTopologyAnalyzer::getTravelTimeStatic
static double getTravelTimeStatic(const Track *const track, const NBVehicle *const veh, double time)
Definition: NBAlgorithms_Railway.cpp:1062
OutputDevice::openTag
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
Definition: OutputDevice.cpp:239
NBNodeCont.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:47
StringUtils.h
NBPTStopCont::getStops
const std::map< std::string, NBPTStop * > & getStops() const
Definition: NBPTStopCont.h:61
OutputDevice::getDevice
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
Definition: OutputDevice.cpp:54
NBRailwayTopologyAnalyzer::Track::addSuccessor
void addSuccessor(Track *track)
Definition: NBAlgorithms_Railway.cpp:59
NBRailwayTopologyAnalyzer::addBidiEdgesForStops
static void addBidiEdgesForStops(NBNetBuilder &nb)
add bidi-edges to connect successive public transport stops
Definition: NBAlgorithms_Railway.cpp:798
PositionVector::reverse
PositionVector reverse() const
reverse position vector
Definition: PositionVector.cpp:1086
NBRailwayTopologyAnalyzer::Track::getSuccessors
const std::vector< Track * > & getSuccessors(SUMOVehicleClass svc=SVC_IGNORING) const
Definition: NBAlgorithms_Railway.cpp:66
NBRailwayTopologyAnalyzer::analyzeTopology
static void analyzeTopology(NBNetBuilder &nb)
Computes highway on-/off-ramps (if wished)
Definition: NBAlgorithms_Railway.cpp:104
OutputDevice_String.h
NBNode::getIncomingEdges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:255
NBAlgorithms_Railway.h
joinToString
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:246
NBPTLine::getRef
const std::string & getRef() const
get line reference (not unique)
Definition: NBPTLine.h:61
NBRailwayTopologyAnalyzer::addBidiEdgesBetweenSwitches
static void addBidiEdgesBetweenSwitches(NBNetBuilder &nb)
add bidi-edges to connect switches that are approached in both directions
Definition: NBAlgorithms_Railway.cpp:739
config.h
NBRailwayTopologyAnalyzer::allSharp
static bool allSharp(const NBNode *node, const EdgeVector &in, const EdgeVector &out, bool countBidiAsSharp=false)
Definition: NBAlgorithms_Railway.cpp:449
gDebugFlag1
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:32
DijkstraRouter.h
NBEdge::getTravelTimeStatic
static double getTravelTimeStatic(const NBEdge *const edge, const NBVehicle *const, double)
Definition: NBEdge.h:1351
NBPTLine::getRouteStart
NBEdge * getRouteStart(const NBEdgeCont &ec) const
return first valid edge of myRoute (if it doest not lie after the first stop)
Definition: NBPTLine.cpp:153
NBRailwayTopologyAnalyzer::allBroken
static bool allBroken(const NBNode *node, NBEdge *candOut, const EdgeVector &in, const EdgeVector &out)
Definition: NBAlgorithms_Railway.cpp:427
NBRailwayTopologyAnalyzer::Track::successors
std::vector< Track * > successors
Definition: NBAlgorithms_Railway.h:95
NBRailwayTopologyAnalyzer::getBrokenRailNodes
static std::set< NBNode * > getBrokenRailNodes(NBNetBuilder &nb, bool verbose=false)
Definition: NBAlgorithms_Railway.cpp:196
OutputDevice::writeXMLHeader
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >())
Writes an XML header with optional configuration.
Definition: OutputDevice.cpp:227
NBNode
Represents a single node (junction) during network building.
Definition: NBNode.h:67
NBRailwayTopologyAnalyzer::reverseEdges
static void reverseEdges(NBNetBuilder &nb)
reverse edges sequences that are to broken nodes on both sides
Definition: NBAlgorithms_Railway.cpp:538
NBRailwayTopologyAnalyzer::isBidiSwitch
static NBEdge * isBidiSwitch(const NBNode *n)
Definition: NBAlgorithms_Railway.cpp:717
NBVehicle.h
NBAlgorithms.h
NBNode.h
NBRailwayTopologyAnalyzer::addBidiEdgesForStraightConnectivity
static void addBidiEdgesForStraightConnectivity(NBNetBuilder &nb, bool geometryLike)
add bidi-edges to connect straight tracks
Definition: NBAlgorithms_Railway.cpp:971
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:76
NBEdge::getAngleAtNode
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1836
NBEdgeCont::begin
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:184
NBEdge::getFromNode
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:491
WRITE_MESSAGE
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:277
NBRailwayTopologyAnalyzer::allBidi
static bool allBidi(const EdgeVector &edges)
Definition: NBAlgorithms_Railway.cpp:467
NBEdge.h
NBEdge::getLaneSpreadFunction
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition: NBEdge.h:777
NBEdge::getTurnDestination
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3084
SUMO_TAG_NODE
@ SUMO_TAG_NODE
alternative definition for junction
Definition: SUMOXMLDefinitions.h:208
NBEdge::getID
const std::string & getID() const
Definition: NBEdge.h:1380