SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBEdgeCont.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Storage for edges, including some functionality operating on multiple edges
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
13 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <vector>
35 #include <string>
36 #include <cassert>
37 #include <algorithm>
38 #include <iostream>
39 #include <fstream>
40 #include <iomanip>
41 #include <utils/geom/Boundary.h>
42 #include <utils/geom/GeomHelper.h>
45 #include <utils/common/ToString.h>
48 #include "NBNetBuilder.h"
49 #include "NBEdgeCont.h"
50 #include "NBNodeCont.h"
51 #include "NBHelpers.h"
52 #include "NBCont.h"
54 #include "NBDistrictCont.h"
55 #include <cmath>
56 #include "NBTypeCont.h"
60 
61 #ifdef CHECK_MEMORY_LEAKS
62 #include <foreign/nvwa/debug_new.h>
63 #endif // CHECK_MEMORY_LEAKS
64 
65 
66 // ===========================================================================
67 // method definitions
68 // ===========================================================================
70  myTypeCont(tc),
71  myEdgesSplit(0),
72  myVehicleClasses2Keep(0),
73  myVehicleClasses2Remove(0),
74  myNeedGeoTransformedPrunningBoundary(false)
75 {}
76 
77 
79  clear();
80 }
81 
82 
83 void
85  myAmLeftHanded = oc.getBool("lefthand");
86  // set edges dismiss/accept options
87  myEdgesMinSpeed = oc.isSet("keep-edges.min-speed") ? oc.getFloat("keep-edges.min-speed") : -1;
88  myRemoveEdgesAfterJoining = oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload");
89  if (oc.isSet("keep-edges.explicit")) {
90  const std::vector<std::string> edges = oc.getStringVector("keep-edges.explicit");
91  myEdges2Keep.insert(edges.begin(), edges.end());
92  }
93  if (oc.isSet("remove-edges.explicit")) {
94  const std::vector<std::string> edges = oc.getStringVector("remove-edges.explicit");
95  myEdges2Remove.insert(edges.begin(), edges.end());
96  }
97  if (oc.exists("keep-edges.by-vclass") && oc.isSet("keep-edges.by-vclass")) {
98  const std::vector<std::string> classes = oc.getStringVector("keep-edges.by-vclass");
99  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
101  }
102  }
103  if (oc.exists("remove-edges.by-vclass") && oc.isSet("remove-edges.by-vclass")) {
104  const std::vector<std::string> classes = oc.getStringVector("remove-edges.by-vclass");
105  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
107  }
108  }
109  if (oc.exists("keep-edges.by-type") && oc.isSet("keep-edges.by-type")) {
110  const std::vector<std::string> types = oc.getStringVector("keep-edges.by-type");
111  myTypes2Keep.insert(types.begin(), types.end());
112  }
113  if (oc.exists("remove-edges.by-type") && oc.isSet("remove-edges.by-type")) {
114  const std::vector<std::string> types = oc.getStringVector("remove-edges.by-type");
115  myTypes2Remove.insert(types.begin(), types.end());
116  }
117 
118  if (oc.isSet("keep-edges.in-boundary") || oc.isSet("keep-edges.in-geo-boundary")) {
119  std::vector<std::string> polyS = oc.getStringVector(oc.isSet("keep-edges.in-boundary") ?
120  "keep-edges.in-boundary" : "keep-edges.in-geo-boundary");
121  // !!! throw something if length<4 || length%2!=0?
122  std::vector<SUMOReal> poly;
123  for (std::vector<std::string>::iterator i = polyS.begin(); i != polyS.end(); ++i) {
124  poly.push_back(TplConvert::_2SUMOReal((*i).c_str())); // !!! may throw something anyhow...
125  }
126  if (poly.size() < 4) {
127  throw ProcessError("Invalid boundary: need at least 2 coordinates");
128  } else if (poly.size() % 2 != 0) {
129  throw ProcessError("Invalid boundary: malformed coordinate");
130  } else if (poly.size() == 4) {
131  // prunning boundary (box)
132  myPrunningBoundary.push_back(Position(poly[0], poly[1]));
133  myPrunningBoundary.push_back(Position(poly[2], poly[1]));
134  myPrunningBoundary.push_back(Position(poly[2], poly[3]));
135  myPrunningBoundary.push_back(Position(poly[0], poly[3]));
136  } else {
137  for (std::vector<SUMOReal>::iterator j = poly.begin(); j != poly.end();) {
138  SUMOReal x = *j++;
139  SUMOReal y = *j++;
141  }
142  }
143  myNeedGeoTransformedPrunningBoundary = oc.isSet("keep-edges.in-geo-boundary");
144  }
145 }
146 
147 
148 void
150  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
151  delete((*i).second);
152  }
153  myEdges.clear();
154  for (EdgeCont::iterator i = myExtractedEdges.begin(); i != myExtractedEdges.end(); i++) {
155  delete((*i).second);
156  }
157  myExtractedEdges.clear();
158 }
159 
160 
161 
162 // ----- edge access methods
163 bool
164 NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
165  if (myAmLeftHanded) {
166  edge->setLeftHanded();
167  }
168  if (myEdges.count(edge->getID())) {
169  return false;
170  }
171  if (!ignorePrunning && ignoreFilterMatch(edge)) {
172  edge->getFromNode()->removeEdge(edge);
173  edge->getToNode()->removeEdge(edge);
174  myIgnoredEdges.insert(edge->getID());
175  delete edge;
176  } else {
178  if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
180  }
181  myEdges[edge->getID()] = edge;
182  }
183  return true;
184 }
185 
186 
187 bool
189  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
190  if (edge->getSpeed() < myEdgesMinSpeed) {
191  return true;
192  }
193  // check whether the edge is a named edge to keep
194  if (!myRemoveEdgesAfterJoining && myEdges2Keep.size() != 0) {
195  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) == myEdges2Keep.end()) {
196  return true;
197  }
198  }
199  // check whether the edge is a named edge to remove
200  if (myEdges2Remove.size() != 0) {
201  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
202  return true;
203  }
204  }
205  // check whether the edge shall be removed because it does not allow any of the wished classes
206  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
207  return true;
208  }
209  // check whether the edge shall be removed due to allowing unwished classes only
211  return true;
212  }
213  // check whether the edge shall be removed because it does not have one of the requested types
214  if (myTypes2Keep.size() != 0) {
215  if (myTypes2Keep.count(edge->getTypeID()) == 0) {
216  return true;
217  }
218  }
219  // check whether the edge shall be removed because it has one of the forbidden types
220  if (myTypes2Remove.size() != 0) {
221  if (myTypes2Remove.count(edge->getTypeID()) > 0) {
222  return true;
223  }
224  }
225  // check whether the edge is within the prunning boundary
226  if (myPrunningBoundary.size() != 0) {
230  } else if (GeoConvHelper::getLoaded().usingGeoProjection()) {
231  // XXX what if input file with different projections are loaded?
232  for (int i = 0; i < (int) myPrunningBoundary.size(); i++) {
234  }
235  } else {
236  WRITE_ERROR("Cannot prune edges using a geo-boundary because no projection has been loaded");
237  }
238  }
240  return true;
241  }
242  }
244  return true;
245  }
246  return false;
247 }
248 
249 
250 NBEdge*
251 NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
252  EdgeCont::const_iterator i = myEdges.find(id);
253  if (i == myEdges.end()) {
254  if (retrieveExtracted) {
255  i = myExtractedEdges.find(id);
256  if (i == myExtractedEdges.end()) {
257  return 0;
258  }
259  } else {
260  return 0;
261  }
262  }
263  return (*i).second;
264 }
265 
266 
267 NBEdge*
268 NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
269  NBEdge* edge = retrieve(id);
270  if (edge == 0) {
271  return 0;
272  }
273  const EdgeVector* candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
274  while (candidates->size() == 1) {
275  const std::string& nextID = candidates->front()->getID();
276  if (nextID.find(id) != 0 || nextID.size() <= id.size() + 1 || (nextID[id.size()] != '.' && nextID[id.size()] != '-')) {
277  break;
278  }
279  edge = candidates->front();
280  candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
281  }
282  return edge;
283 }
284 
285 
286 NBEdge*
287 NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
288  // try to retrieve using the given name (iterative)
289  NBEdge* edge = retrieve(id);
290  if (edge != 0) {
291  return edge;
292  }
293  // now, we did not find it; we have to look over all possibilities
294  EdgeVector hints;
295  // check whether at least the hint was not splitted
296  NBEdge* hintedge = retrieve(hint);
297  if (hintedge == 0) {
298  hints = getGeneratedFrom(hint);
299  } else {
300  hints.push_back(hintedge);
301  }
302  EdgeVector candidates = getGeneratedFrom(id);
303  for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) {
304  NBEdge* hintedge = (*i);
305  for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) {
306  NBEdge* poss_searched = (*j);
307  NBNode* node = incoming
308  ? poss_searched->myTo : poss_searched->myFrom;
309  const EdgeVector& cont = incoming
310  ? node->getOutgoingEdges() : node->getIncomingEdges();
311  if (find(cont.begin(), cont.end(), hintedge) != cont.end()) {
312  return poss_searched;
313  }
314  }
315  }
316  return 0;
317 }
318 
319 
320 NBEdge*
321 NBEdgeCont::retrievePossiblySplit(const std::string& id, SUMOReal pos) const {
322  // check whether the edge was not split, yet
323  NBEdge* edge = retrieve(id);
324  if (edge != 0) {
325  return edge;
326  }
327  size_t maxLength = 0;
328  std::string tid = id + "[";
329  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
330  if ((*i).first.find(tid) == 0) {
331  maxLength = MAX2(maxLength, (*i).first.length());
332  }
333  }
334  // find the part of the edge which matches the position
335  SUMOReal seen = 0;
336  std::vector<std::string> names;
337  names.push_back(id + "[1]");
338  names.push_back(id + "[0]");
339  while (names.size() > 0) {
340  // retrieve the first subelement (to follow)
341  std::string cid = names.back();
342  names.pop_back();
343  edge = retrieve(cid);
344  // The edge was splitted; check its subparts within the
345  // next step
346  if (edge == 0) {
347  if (cid.length() + 3 < maxLength) {
348  names.push_back(cid + "[1]");
349  names.push_back(cid + "[0]");
350  }
351  }
352  // an edge with the name was found,
353  // check whether the position lies within it
354  else {
355  seen += edge->getLength();
356  if (seen >= pos) {
357  return edge;
358  }
359  }
360  }
361  return 0;
362 }
363 
364 
365 void
367  extract(dc, edge);
368  delete edge;
369 }
370 
371 
372 void
373 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
374  if (remember) {
375  myExtractedEdges[edge->getID()] = edge;
376  }
377  myEdges.erase(edge->getID());
378  edge->myFrom->removeEdge(edge);
379  edge->myTo->removeEdge(edge);
380  dc.removeFromSinksAndSources(edge);
381 }
382 
383 
384 void
385 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
386  if (myEdges.count(newID) != 0) {
387  throw ProcessError("Attempt to rename edge using existing id '" + newID + "'");
388  }
389  myEdges.erase(edge->getID());
390  edge->setID(newID);
391  myEdges[newID] = edge;
392 }
393 
394 
395 // ----- explicit edge manipulation methods
396 bool
398  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
399  (unsigned int) edge->myLanes.size(), (unsigned int) edge->myLanes.size());
400 }
401 
402 
403 bool
405  const std::string& firstEdgeName,
406  const std::string& secondEdgeName,
407  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
408  SUMOReal pos;
409  pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
410  if (pos <= 0) {
412  edge->myFrom->getPosition(), edge->myTo->getPosition(),
413  node->getPosition());
414  }
415  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
416  return false;
417  }
418  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
419  noLanesFirstEdge, noLanesSecondEdge);
420 }
421 
422 
423 bool
425  NBEdge* edge, SUMOReal pos, NBNode* node,
426  const std::string& firstEdgeName,
427  const std::string& secondEdgeName,
428  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
429  // build the new edges' geometries
430  std::pair<PositionVector, PositionVector> geoms =
431  edge->getGeometry().splitAt(pos);
432  if (geoms.first[-1] != node->getPosition()) {
433  geoms.first.pop_back();
434  geoms.first.push_back(node->getPosition());
435  }
436 
437  if (geoms.second[0] != node->getPosition()) {
438  geoms.second.pop_front();
439  geoms.second.push_front(node->getPosition());
440  }
441  // build and insert the edges
442  NBEdge* one = new NBEdge(firstEdgeName,
443  edge->myFrom, node, edge->myType, edge->mySpeed, noLanesFirstEdge,
444  edge->getPriority(), edge->myLaneWidth, 0, geoms.first,
445  edge->getStreetName(), edge->myLaneSpreadFunction, true);
446  for (unsigned int i = 0; i < noLanesFirstEdge && i < edge->getNumLanes(); i++) {
447  one->setSpeed(i, edge->getLaneSpeed(i));
448  }
449  NBEdge* two = new NBEdge(secondEdgeName,
450  node, edge->myTo, edge->myType, edge->mySpeed, noLanesSecondEdge,
451  edge->getPriority(), edge->myLaneWidth, edge->myOffset, geoms.second,
452  edge->getStreetName(), edge->myLaneSpreadFunction, true);
453  for (unsigned int i = 0; i < noLanesSecondEdge && i < edge->getNumLanes(); i++) {
454  two->setSpeed(i, edge->getLaneSpeed(i));
455  }
456  two->copyConnectionsFrom(edge);
457  // replace information about this edge within the nodes
458  edge->myFrom->replaceOutgoing(edge, one, 0);
459  edge->myTo->replaceIncoming(edge, two, 0);
460  // the edge is now occuring twice in both nodes...
461  // clean up
462  edge->myFrom->removeDoubleEdges();
463  edge->myTo->removeDoubleEdges();
464  // add connections from the first to the second edge
465  // check special case:
466  // one in, one out, the outgoing has one lane more
467  if (noLanesFirstEdge == noLanesSecondEdge - 1) {
468  for (unsigned int i = 0; i < one->getNumLanes(); i++) {
469  if (!one->addLane2LaneConnection(i, two, i + 1, NBEdge::L2L_COMPUTED)) { // !!! Bresenham, here!!!
470  throw ProcessError("Could not set connection!");
471  }
472  }
474  } else {
475  for (unsigned int i = 0; i < one->getNumLanes() && i < two->getNumLanes(); i++) {
476  if (!one->addLane2LaneConnection(i, two, i, NBEdge::L2L_COMPUTED)) {// !!! Bresenham, here!!!
477  throw ProcessError("Could not set connection!");
478  }
479  }
480  }
482  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) != myEdges2Keep.end()) {
483  myEdges2Keep.insert(one->getID());
484  myEdges2Keep.insert(two->getID());
485  }
486  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
487  myEdges2Remove.insert(one->getID());
488  myEdges2Remove.insert(two->getID());
489  }
490  }
491  // erase the splitted edge
492  erase(dc, edge);
493  insert(one, true);
494  insert(two, true);
495  myEdgesSplit++;
496  return true;
497 }
498 
499 
500 
501 // ----- container access methods
502 std::vector<std::string>
504  std::vector<std::string> ret;
505  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
506  ret.push_back((*i).first);
507  }
508  return ret;
509 }
510 
511 
512 // ----- Adapting the input
513 void
515  EdgeVector toRemove;
516  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
517  NBEdge* edge = (*i).second;
518  if (!myEdges2Keep.count(edge->getID())) {
519  edge->getFromNode()->removeEdge(edge);
520  edge->getToNode()->removeEdge(edge);
521  toRemove.push_back(edge);
522  }
523  }
524  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
525  erase(dc, *j);
526  }
527 }
528 
529 
530 void
532  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
533  if ((*i).second->getGeometry().size() < 3) {
534  continue;
535  }
536  (*i).second->splitGeometry(*this, nc);
537  }
538 }
539 
540 
541 void
543  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
544  (*i).second->reduceGeometry(minDist);
545  }
546 }
547 
548 
549 void
550 NBEdgeCont::checkGeometries(const SUMOReal maxAngle, const SUMOReal minRadius, bool fix) {
551  if (maxAngle > 0 || minRadius > 0) {
552  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
553  (*i).second->checkGeometry(maxAngle, minRadius, fix);
554  }
555  }
556 }
557 
558 
559 // ----- processing methods
560 void
562  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
563  (*i).second->clearControllingTLInformation();
564  }
565 }
566 
567 
568 void
570  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
571  (*i).second->sortOutgoingConnectionsByAngle();
572  }
573 }
574 
575 
576 void
577 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
578  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
579  (*i).second->computeEdge2Edges(noLeftMovers);
580  }
581 }
582 
583 
584 void
586  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
587  (*i).second->computeLanes2Edges();
588  }
589 }
590 
591 
592 void
594  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
595  (*i).second->recheckLanes();
596  }
597 }
598 
599 
600 void
601 NBEdgeCont::appendTurnarounds(bool noTLSControlled) {
602  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
603  (*i).second->appendTurnaround(noTLSControlled);
604  }
605 }
606 
607 
608 void
609 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
610  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
611  myEdges[*it]->appendTurnaround(noTLSControlled);
612  }
613 }
614 
615 
616 void
618  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
619  (*i).second->computeEdgeShape();
620  }
621 }
622 
623 
624 void
626  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
627  (*i).second->computeLaneShapes();
628  }
629 }
630 
631 
632 void
635  EdgeVector edges) {
636  // !!! Attention!
637  // No merging of the geometry to come is being done
638  // The connections are moved from one edge to another within
639  // the replacement where the edge is a node's incoming edge.
640 
641  // count the number of lanes, the speed and the id
642  unsigned int nolanes = 0;
643  SUMOReal speed = 0;
644  int priority = 0;
645  std::string id;
646  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
647  // retrieve the connected nodes
648  NBEdge* tpledge = *(edges.begin());
649  NBNode* from = tpledge->getFromNode();
650  NBNode* to = tpledge->getToNode();
651  EdgeVector::const_iterator i;
652  for (i = edges.begin(); i != edges.end(); i++) {
653  // some assertions
654  assert((*i)->getFromNode() == from);
655  assert((*i)->getToNode() == to);
656  // ad the number of lanes the current edge has
657  nolanes += (*i)->getNumLanes();
658  // build the id
659  if (i != edges.begin()) {
660  id += "+";
661  }
662  id += (*i)->getID();
663  // compute the speed
664  speed += (*i)->getSpeed();
665  // build the priority
666  priority = MAX2(priority, (*i)->getPriority());
667  }
668  speed /= edges.size();
669  // build the new edge
670  // @bug new edge does not know about allowed vclass of old edges
671  // @bug both the width and the offset are not regarded
672  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
674  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
675  insert(newEdge, true);
676  // replace old edge by current within the nodes
677  // and delete the old
678  from->replaceOutgoing(edges, newEdge);
679  to->replaceIncoming(edges, newEdge);
680  // patch connections
681  // add edge2edge-information
682  for (i = edges.begin(); i != edges.end(); i++) {
683  EdgeVector ev = (*i)->getConnectedEdges();
684  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
685  newEdge->addEdge2EdgeConnection(*j);
686  }
687  }
688  // move lane2lane-connections
689  unsigned int currLane = 0;
690  for (i = edges.begin(); i != edges.end(); i++) {
691  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
692  currLane += (*i)->getNumLanes();
693  }
694  // patch tl-information
695  currLane = 0;
696  for (i = edges.begin(); i != edges.end(); i++) {
697  unsigned int noLanes = (*i)->getNumLanes();
698  for (unsigned int j = 0; j < noLanes; j++, currLane++) {
699  // replace in traffic lights
700  tlc.replaceRemoved(*i, j, newEdge, currLane);
701  }
702  }
703  // delete joined edges
704  for (i = edges.begin(); i != edges.end(); i++) {
705  erase(dc, *i);
706  }
707 }
708 
709 
710 void
712  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
713  std::string oppositeID;
714  if ((*i).first[0] == '-') {
715  oppositeID = (*i).first.substr(1);
716  } else {
717  oppositeID = "-" + (*i).first;
718  }
719  if (myEdges.find(oppositeID) != myEdges.end()) {
720  (*i).second->setLaneSpreadFunction(LANESPREAD_RIGHT);
721  myEdges.find(oppositeID)->second->setLaneSpreadFunction(LANESPREAD_RIGHT);
722  } else {
723  (*i).second->setLaneSpreadFunction(LANESPREAD_CENTER);
724  }
725  }
726 }
727 
728 
729 
730 // ----- other
731 void
732 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass) {
733  myConnections.push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass));
734 }
735 
736 
737 void
739  for (std::vector<PostProcessConnection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
740  NBEdge* from = retrievePossiblySplit((*i).from, true);
741  NBEdge* to = retrievePossiblySplit((*i).to, false);
742  if (from != 0 && to != 0) {
743  if (!from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::L2L_USER, false, (*i).mayDefinitelyPass)) {
744  WRITE_WARNING("Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.");
745  }
746  }
747  }
748  // during loading we also kept some ambiguous connections in hope they might be valid after processing
749  // we need to make sure that all invalid connections are removed now
750  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
751  NBEdge* edge = it->second;
752  NBNode* to = edge->getToNode();
753  // make a copy because we may delete connections
754  std::vector<NBEdge::Connection> connections = edge->getConnections();
755  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
756  NBEdge::Connection& c = *it_con;
757  if (c.toEdge != 0 && c.toEdge->getFromNode() != to) {
758  WRITE_WARNING("Found and removed invalid connection from " + edge->getID() +
759  " to " + c.toEdge->getID() + " via " + to->getID());
760  edge->removeFromConnections(c.toEdge);
761  }
762  }
763  }
764 }
765 
766 
768 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
769  size_t len = id.length();
770  EdgeVector ret;
771  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
772  std::string curr = (*i).first;
773  // the next check makes it possibly faster - we don not have
774  // to compare the names
775  if (curr.length() <= len) {
776  continue;
777  }
778  // the name must be the same as the given id but something
779  // beginning with a '[' must be appended to it
780  if (curr.substr(0, len) == id && curr[len] == '[') {
781  ret.push_back((*i).second);
782  continue;
783  }
784  // ok, maybe the edge is a compound made during joining of edges
785  size_t pos = curr.find(id);
786  // surely not
787  if (pos == std::string::npos) {
788  continue;
789  }
790  // check leading char
791  if (pos > 0) {
792  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
793  // actually, this is another id
794  continue;
795  }
796  }
797  if (pos + id.length() < curr.length()) {
798  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
799  // actually, this is another id
800  continue;
801  }
802  }
803  ret.push_back((*i).second);
804  }
805  return ret;
806 }
807 
808 
809 void
810 NBEdgeCont::guessRoundabouts(std::vector<EdgeVector>& marked) {
811  // step 1: keep only those edges which have no turnarounds
812  std::set<NBEdge*> candidates;
813  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
814  NBEdge* e = (*i).second;
815  NBNode* const to = e->getToNode();
816  if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) {
817  candidates.insert(e);
818  }
819  }
820 
821  // step 2:
822  std::set<NBEdge*> visited;
823  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
824  EdgeVector loopEdges;
825  // start with a random edge (this doesn't have to be a roundabout edge)
826  // loop over connected edges (using always the leftmost one)
827  // and keep the list in loopEdges
828  // continue until we loop back onto a loopEdges and extract the loop
829  NBEdge* e = (*i);
830  if (visited.count(e) > 0) {
831  // already seen
832  continue;
833  }
834  loopEdges.push_back(e);
835  bool doLoop = true;
836  do {
837  visited.insert(e);
838  const EdgeVector& edges = e->getToNode()->getEdges();
839  if (edges.size() < 2) {
840  doLoop = false;
841  break;
842  }
843  if (e->getTurnDestination() != 0 || e->getToNode()->getConnectionTo(e->getFromNode()) != 0) {
844  // do not follow turn-arounds while in a (tentative) loop
845  doLoop = false;
846  break;
847  }
848  EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e);
849  NBContHelper::nextCW(edges, me);
850  NBEdge* left = *me;
851  SUMOReal angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
852  if (angle >= 90) {
853  // roundabouts do not have sharp turns (or they wouldn't be called 'round')
854  doLoop = false;
855  break;
856  }
857  EdgeVector::const_iterator loopClosed = find(loopEdges.begin(), loopEdges.end(), left);
858  const size_t loopSize = loopEdges.end() - loopClosed;
859  if (loopSize > 0) {
860  // loop found
861  if (loopSize < 3) {
862  doLoop = false; // need at least 3 edges for a roundabout
863  } else if (loopSize < loopEdges.size()) {
864  // remove initial edges not belonging to the loop
865  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
866  }
867  // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
868  int attachments = 0;
869  for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
870  if ((*j)->getToNode()->getEdges().size() > 2) {
871  attachments++;
872  }
873  }
874  if (attachments < 3) {
875  doLoop = false;
876  }
877  break;
878  }
879  if (visited.count(left) > 0) {
880  doLoop = false;
881  } else {
882  // keep going
883  loopEdges.push_back(left);
884  e = left;
885  }
886  } while (doLoop);
887  // mark collected edges in the case a loop (roundabout) was found
888  if (doLoop) {
889  std::set<NBEdge*> loopEdgesSet(loopEdges.begin(), loopEdges.end());
890  for (std::set<NBEdge*>::const_iterator j = loopEdgesSet.begin(); j != loopEdgesSet.end(); ++j) {
891  // disable turnarounds on incoming edges
892  NBNode* node = (*j)->getToNode();
893  const EdgeVector& incoming = node->getIncomingEdges();
894  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
895  NBEdge* inEdge = *k;
896  if (loopEdgesSet.count(inEdge) > 0) {
897  continue;
898  }
899  if ((inEdge)->getStep() >= NBEdge::LANES2LANES_USER) {
900  continue;
901  }
902  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
903  }
904  // let the connections to succeeding roundabout edge have a higher priority
905  (*j)->setJunctionPriority(node, 1000);
906  node->setRoundabout();
907  }
908  marked.push_back(loopEdges);
909  }
910  }
911 }
912 
913 
914 void
916  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
917  NBEdge* e = i->second;
918  // is this a "real" junction?
919  // XXX nyi
920  //continue
921  const SUMOReal offset = e->getLength() - 3;
922  switch (e->getToNode()->getType()) {
923  case NODETYPE_PRIORITY:
924  // yield or major?
925  if (e->getJunctionPriority(e->getToNode()) > 0) {
927  } else {
929  }
930  break;
932  // yield or major?
933  if (e->getJunctionPriority(e->getToNode()) > 0) {
935  } else {
937  }
938  break;
941  break;
944  break;
945  default:
946  break;
947  }
948  }
949 }
950 
951 /****************************************************************************/
~NBEdgeCont()
Destructor.
Definition: NBEdgeCont.cpp:78
SUMOVehicleClass getVehicleClassID(const std::string &name)
Returns the class id of the abstract class given by its name.
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1228
void replaceIncoming(NBEdge *which, NBEdge *by, unsigned int laneOff)
Replaces occurences of the first edge within the list of incoming by the second Connections are remap...
Definition: NBNode.cpp:791
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges.
Definition: NBNode.h:170
const std::string & getTypeID() const
Definition: NBEdge.h:859
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:148
void sortOutgoingLanesConnections()
Sorts all lanes of all edges within the container by their direction.
Definition: NBEdgeCont.cpp:569
bool myAmLeftHanded
Whether the network is left-handed.
Definition: NBEdgeCont.h:566
void setRoundabout()
update the type of this node as a roundabout
Definition: NBNode.cpp:1431
NBEdge * retrievePossiblySplit(const std::string &id, bool downstream) const
Tries to retrieve an edge, even if it is splitted.
Definition: NBEdgeCont.cpp:268
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:201
A class representing a single street sign.
Definition: NBSign.h:50
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation. ...
SUMOReal nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
Definition: NBEdgeCont.cpp:503
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1217
static bool transformCoordinates(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
void addSign(NBSign sign)
Definition: NBEdge.h:1021
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:164
NBNode * myTo
Definition: NBEdge.h:1179
static SUMOReal _2SUMOReal(const E *const data)
Definition: TplConvert.h:223
bool myNeedGeoTransformedPrunningBoundary
whether a geo transform has been applied to the pruning boundary
Definition: NBEdgeCont.h:600
A container for traffic light definitions and built programs.
bool myRemoveEdgesAfterJoining
Whether edges shall be joined first, then removed.
Definition: NBEdgeCont.h:576
void setSpeed(int lane, SUMOReal speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:2049
void moveOutgoingConnectionsFrom(NBEdge *e, unsigned int laneOff)
Definition: NBEdge.cpp:1639
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:97
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:971
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
A container for districts.
static GeoConvHelper & getLoaded()
the coordinate transformation that was loaded fron an input file
bool addLane2LaneConnection(unsigned int fromLane, NBEdge *dest, unsigned int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition: NBEdge.cpp:617
void removeDoubleEdges()
Definition: NBNode.cpp:859
T MAX2(T a, T b)
Definition: StdDefs.h:71
void clearControllingTLInformation() const
Clears information about controlling traffic lights for all connenections of all edges.
Definition: NBEdgeCont.cpp:561
void generateStreetSigns()
assigns street signs to edges based on toNode types
Definition: NBEdgeCont.cpp:915
void rename(NBEdge *edge, const std::string &newID)
Renames the edge. Throws exception if newID already exists.
Definition: NBEdgeCont.cpp:385
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
Definition: NBEdgeCont.cpp:397
void recheckPostProcessConnections()
Try to set any stored connections.
Definition: NBEdgeCont.cpp:738
SUMOReal getFloat(const std::string &name) const
Returns the SUMOReal-value of the named option (only for Option_Float)
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
unsigned int myEdgesSplit
the number of splits of edges during the building
Definition: NBEdgeCont.h:563
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:203
void computeLanes2Edges()
Computes for each edge which lanes approach the next edges.
Definition: NBEdgeCont.cpp:585
std::vector< PostProcessConnection > myConnections
The list of connections to recheck.
Definition: NBEdgeCont.h:547
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:196
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:67
void checkGeometries(const SUMOReal maxAngle, const SUMOReal minRadius, bool fix)
Definition: NBEdgeCont.cpp:550
void guessRoundabouts(std::vector< EdgeVector > &marked)
Determines which edges belong to roundabouts and increases their priority.
Definition: NBEdgeCont.cpp:810
NBEdgeCont(NBTypeCont &tc)
Constructor.
Definition: NBEdgeCont.cpp:69
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges.
Definition: NBNode.h:178
const std::string & getID() const
Returns the id.
Definition: Named.h:60
SUMOReal mySpeed
The maximal speed.
Definition: NBEdge.h:1193
bool addEdge2EdgeConnection(NBEdge *dest)
Adds a connection to another edge.
Definition: NBEdge.cpp:593
bool overlapsWith(const AbstractPoly &poly, SUMOReal offset=0) const
Returns whether the boundary overlaps with the given polygon.
Definition: Boundary.cpp:156
static SUMOReal nearest_offset_on_line_to_point2D(const Position &l1, const Position &l2, const Position &p, bool perpendicular=true)
Definition: GeomHelper.cpp:247
SVCPermissions myVehicleClasses2Keep
Set of vehicle types which must be allowed on edges in order to keep them.
Definition: NBEdgeCont.h:585
const Position & getPosition() const
Returns the position of this node.
Definition: NBNode.h:158
void reduceGeometries(const SUMOReal minDist)
Definition: NBEdgeCont.cpp:542
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
Definition: NBEdge.h:103
bool usingGeoProjection() const
Returns whether a transformation from geo to metric coordinates will be performed.
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:346
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:164
void removeUnwishedEdges(NBDistrictCont &dc)
Removes unwished edges (not in keep-edges)
Definition: NBEdgeCont.cpp:514
void extract(NBDistrictCont &dc, NBEdge *edge, bool remember=false)
Removes the given edge from the container like erase but does not delete it.
Definition: NBEdgeCont.cpp:373
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
void applyOptions(OptionsCont &oc)
Initialises the storage by applying given options.
Definition: NBEdgeCont.cpp:84
unsigned int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:338
std::set< std::string > myEdges2Keep
Set of ids of edges which shall explicitly be kept.
Definition: NBEdgeCont.h:579
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:195
void computeEdge2Edges(bool noLeftMovers)
Computes for each edge the approached edges.
Definition: NBEdgeCont.cpp:577
void computeLaneShapes()
Computes the shapes of all lanes of all edges stored in the container.
Definition: NBEdgeCont.cpp:625
void setLeftHanded()
Marks this edge to be left-handed.
Definition: NBEdge.h:327
const EdgeVector & getEdges() const
Returns all edges which participate in this node.
Definition: NBNode.h:186
SUMOReal myLaneWidth
This width of this edge's lanes.
Definition: NBEdge.h:1223
void splitGeometry(NBNodeCont &nc)
Splits edges into multiple if they have a complex geometry.
Definition: NBEdgeCont.cpp:531
EdgeCont myEdges
The instance of the dictionary (id->edge)
Definition: NBEdgeCont.h:554
#define POSITION_EPS
Definition: config.h:186
SUMOReal myOffset
This edges's offset to the intersection begin (will be applied to all lanes)
Definition: NBEdge.h:1220
void clear()
Deletes all edges.
Definition: NBEdgeCont.cpp:149
EdgeCont myExtractedEdges
The extracted nodes which are kept for reference.
Definition: NBEdgeCont.h:557
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:80
The connection was given by the user.
Definition: NBEdge.h:114
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:828
NBEdge * getConnectionTo(NBNode *n) const
Definition: NBNode.cpp:1338
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1101
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
Definition: NBEdgeCont.cpp:633
std::pair< PositionVector, PositionVector > splitAt(SUMOReal where) const
Returns the two lists made when this list vector is splitted at the given point.
SVCPermissions myVehicleClasses2Remove
Set of vehicle types which need not be supported (edges which allow ONLY these are removed) ...
Definition: NBEdgeCont.h:588
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:201
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2093
PositionVector myPrunningBoundary
Boundary within which an edge must be located in order to be kept.
Definition: NBEdgeCont.h:597
SUMOReal length() const
Returns the length.
void push_back(const PositionVector &p)
Appends all positions from the given vector.
std::set< std::string > myTypes2Keep
Set of edges types which shall be kept.
Definition: NBEdgeCont.h:591
Boundary & grow(SUMOReal by)
extends the boundary by the given amount
Definition: Boundary.cpp:200
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:362
SUMOReal myEdgesMinSpeed
The minimum speed an edge may have in order to be kept (default: -1)
Definition: NBEdgeCont.h:573
void setID(const std::string &newID)
resets the id
Definition: Named.h:68
void replaceOutgoing(NBEdge *which, NBEdge *by, unsigned int laneOff)
Replaces occurences of the first edge within the list of outgoing by the second Connections are remap...
Definition: NBNode.cpp:755
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:251
void appendTurnarounds(bool noTLSControlled)
Appends turnarounds to all edges stored in the container.
Definition: NBEdgeCont.cpp:601
std::vector< NBEdge * > EdgeVector
Definition: NBCont.h:38
bool getShallBeDiscarded(const std::string &type) const
Returns the information whether edges of this type shall be discarded.
Definition: NBTypeCont.cpp:122
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:499
A storage for options typed value containers)
Definition: OptionsCont.h:108
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:366
std::string myType
The type of the edge.
Definition: NBEdge.h:1176
A structure representing a connection between two lanes.
Definition: NBEdgeCont.h:522
SUMOReal getLaneSpeed(unsigned int lane) const
Definition: NBEdge.cpp:1139
void computeEdgeShapes()
Computes the shapes of all edges stored in the container.
Definition: NBEdgeCont.cpp:617
The connection was computed.
Definition: NBEdge.h:112
Represents a single node (junction) during network building.
Definition: NBNode.h:74
void dismissVehicleClassInformation()
Definition: NBEdge.cpp:2114
NBTypeCont & myTypeCont
The network builder; used to obtain type information.
Definition: NBEdgeCont.h:517
void recheckLaneSpread()
Rechecks whether the lane spread is proper.
Definition: NBEdgeCont.cpp:711
NBEdge * getTurnDestination() const
Definition: NBEdge.cpp:1889
#define SUMOReal
Definition: config.h:215
static SUMOReal relAngle(SUMOReal angle1, SUMOReal angle2)
Definition: NBHelpers.cpp:62
void removeFromSinksAndSources(NBEdge *const e)
Removes the given edge from the lists of sources and sinks in all stored districts.
std::set< std::string > myTypes2Remove
Set of edges types which shall be removed.
Definition: NBEdgeCont.h:594
void recheckLanes()
Rechecks whether all lanes have a successor for each of the stored edges.
Definition: NBEdgeCont.cpp:593
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:422
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:64
std::set< std::string > myIgnoredEdges
The ids of ignored edges.
Definition: NBEdgeCont.h:560
EdgeVector getGeneratedFrom(const std::string &id) const
Returns the edges which have been built by splitting the edge of the given id.
Definition: NBEdgeCont.cpp:768
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane)
Replaces occurences of the removed edge/lane in all definitions by the given edge.
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:452
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:724
void addPostProcessConnection(const std::string &from, int fromLane, const std::string &to, int toLane, bool mayDefinitelyPass)
Adds a connection which could not be set during loading.
Definition: NBEdgeCont.cpp:732
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1179
bool exists(const std::string &name) const
Returns the information whether the named option is known.
void copyConnectionsFrom(NBEdge *src)
Definition: NBEdge.cpp:933
bool ignoreFilterMatch(NBEdge *edge)
Returns true if this edge matches one of the removal criteria.
Definition: NBEdgeCont.cpp:188
A storage for available types of edges.
Definition: NBTypeCont.h:56
SUMOReal getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:397
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
SUMOReal getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1121
std::set< std::string > myEdges2Remove
Set of ids of edges which shall explicitly be removed.
Definition: NBEdgeCont.h:582
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:354