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