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