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-2013 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  const EdgeVector* candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
271  while (candidates->size() == 1) {
272  const std::string& nextID = candidates->front()->getID();
273  if (nextID.find(id) != 0 || nextID.size() <= id.size() + 1 || (nextID[id.size()] != '.' && nextID[id.size()] != '-')) {
274  break;
275  }
276  edge = candidates->front();
277  candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
278  }
279  return edge;
280 }
281 
282 
283 NBEdge*
284 NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
285  // try to retrieve using the given name (iterative)
286  NBEdge* edge = retrieve(id);
287  if (edge != 0) {
288  return edge;
289  }
290  // now, we did not find it; we have to look over all possibilities
291  EdgeVector hints;
292  // check whether at least the hint was not splitted
293  NBEdge* hintedge = retrieve(hint);
294  if (hintedge == 0) {
295  hints = getGeneratedFrom(hint);
296  } else {
297  hints.push_back(hintedge);
298  }
299  EdgeVector candidates = getGeneratedFrom(id);
300  for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) {
301  NBEdge* hintedge = (*i);
302  for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) {
303  NBEdge* poss_searched = (*j);
304  NBNode* node = incoming
305  ? poss_searched->myTo : poss_searched->myFrom;
306  const EdgeVector& cont = incoming
307  ? node->getOutgoingEdges() : node->getIncomingEdges();
308  if (find(cont.begin(), cont.end(), hintedge) != cont.end()) {
309  return poss_searched;
310  }
311  }
312  }
313  return 0;
314 }
315 
316 
317 NBEdge*
318 NBEdgeCont::retrievePossiblySplit(const std::string& id, SUMOReal pos) const {
319  // check whether the edge was not split, yet
320  NBEdge* edge = retrieve(id);
321  if (edge != 0) {
322  return edge;
323  }
324  size_t maxLength = 0;
325  std::string tid = id + "[";
326  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
327  if ((*i).first.find(tid) == 0) {
328  maxLength = MAX2(maxLength, (*i).first.length());
329  }
330  }
331  // find the part of the edge which matches the position
332  SUMOReal seen = 0;
333  std::vector<std::string> names;
334  names.push_back(id + "[1]");
335  names.push_back(id + "[0]");
336  while (names.size() > 0) {
337  // retrieve the first subelement (to follow)
338  std::string cid = names.back();
339  names.pop_back();
340  edge = retrieve(cid);
341  // The edge was splitted; check its subparts within the
342  // next step
343  if (edge == 0) {
344  if (cid.length() + 3 < maxLength) {
345  names.push_back(cid + "[1]");
346  names.push_back(cid + "[0]");
347  }
348  }
349  // an edge with the name was found,
350  // check whether the position lies within it
351  else {
352  seen += edge->getLength();
353  if (seen >= pos) {
354  return edge;
355  }
356  }
357  }
358  return 0;
359 }
360 
361 
362 void
364  extract(dc, edge);
365  delete edge;
366 }
367 
368 
369 void
370 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
371  if (remember) {
372  myExtractedEdges[edge->getID()] = edge;
373  }
374  myEdges.erase(edge->getID());
375  edge->myFrom->removeEdge(edge);
376  edge->myTo->removeEdge(edge);
377  dc.removeFromSinksAndSources(edge);
378 }
379 
380 
381 void
382 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
383  if (myEdges.count(newID) != 0) {
384  throw ProcessError("Attempt to rename edge using existing id '" + newID + "'");
385  }
386  myEdges.erase(edge->getID());
387  edge->setID(newID);
388  myEdges[newID] = edge;
389 }
390 
391 
392 // ----- explicit edge manipulation methods
393 bool
395  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
396  (unsigned int) edge->myLanes.size(), (unsigned int) edge->myLanes.size());
397 }
398 
399 
400 bool
402  const std::string& firstEdgeName,
403  const std::string& secondEdgeName,
404  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
405  SUMOReal pos;
406  pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
407  if (pos <= 0) {
409  edge->myFrom->getPosition(), edge->myTo->getPosition(),
410  node->getPosition());
411  }
412  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
413  return false;
414  }
415  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
416  noLanesFirstEdge, noLanesSecondEdge);
417 }
418 
419 
420 bool
422  NBEdge* edge, SUMOReal pos, NBNode* node,
423  const std::string& firstEdgeName,
424  const std::string& secondEdgeName,
425  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
426  // build the new edges' geometries
427  std::pair<PositionVector, PositionVector> geoms =
428  edge->getGeometry().splitAt(pos);
429  if (geoms.first[-1] != node->getPosition()) {
430  geoms.first.pop_back();
431  geoms.first.push_back(node->getPosition());
432  }
433 
434  if (geoms.second[0] != node->getPosition()) {
435  geoms.second.pop_front();
436  geoms.second.push_front(node->getPosition());
437  }
438  // build and insert the edges
439  NBEdge* one = new NBEdge(firstEdgeName,
440  edge->myFrom, node, edge->myType, edge->mySpeed, noLanesFirstEdge,
441  edge->getPriority(), edge->myLaneWidth, 0, geoms.first,
442  edge->getStreetName(), edge->myLaneSpreadFunction, true);
443  for (unsigned int i = 0; i < noLanesFirstEdge && i < edge->getNumLanes(); i++) {
444  one->setSpeed(i, edge->getLaneSpeed(i));
445  }
446  NBEdge* two = new NBEdge(secondEdgeName,
447  node, edge->myTo, edge->myType, edge->mySpeed, noLanesSecondEdge,
448  edge->getPriority(), edge->myLaneWidth, edge->myOffset, geoms.second,
449  edge->getStreetName(), edge->myLaneSpreadFunction, true);
450  for (unsigned int i = 0; i < noLanesSecondEdge && i < edge->getNumLanes(); i++) {
451  two->setSpeed(i, edge->getLaneSpeed(i));
452  }
453  two->copyConnectionsFrom(edge);
454  // replace information about this edge within the nodes
455  edge->myFrom->replaceOutgoing(edge, one, 0);
456  edge->myTo->replaceIncoming(edge, two, 0);
457  // the edge is now occuring twice in both nodes...
458  // clean up
459  edge->myFrom->removeDoubleEdges();
460  edge->myTo->removeDoubleEdges();
461  // add connections from the first to the second edge
462  // check special case:
463  // one in, one out, the outgoing has one lane more
464  if (noLanesFirstEdge == noLanesSecondEdge - 1) {
465  for (unsigned int i = 0; i < one->getNumLanes(); i++) {
466  if (!one->addLane2LaneConnection(i, two, i + 1, NBEdge::L2L_COMPUTED)) { // !!! Bresenham, here!!!
467  throw ProcessError("Could not set connection!");
468  }
469  }
471  } else {
472  for (unsigned int i = 0; i < one->getNumLanes() && i < two->getNumLanes(); i++) {
473  if (!one->addLane2LaneConnection(i, two, i, NBEdge::L2L_COMPUTED)) {// !!! Bresenham, here!!!
474  throw ProcessError("Could not set connection!");
475  }
476  }
477  }
479  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) != myEdges2Keep.end()) {
480  myEdges2Keep.insert(one->getID());
481  myEdges2Keep.insert(two->getID());
482  }
483  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
484  myEdges2Remove.insert(one->getID());
485  myEdges2Remove.insert(two->getID());
486  }
487  }
488  // erase the splitted edge
489  erase(dc, edge);
490  insert(one, true);
491  insert(two, true);
492  myEdgesSplit++;
493  return true;
494 }
495 
496 
497 
498 // ----- container access methods
499 std::vector<std::string>
501  std::vector<std::string> ret;
502  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
503  ret.push_back((*i).first);
504  }
505  return ret;
506 }
507 
508 
509 // ----- Adapting the input
510 void
512  EdgeVector toRemove;
513  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
514  NBEdge* edge = (*i).second;
515  if (!myEdges2Keep.count(edge->getID())) {
516  edge->getFromNode()->removeEdge(edge);
517  edge->getToNode()->removeEdge(edge);
518  toRemove.push_back(edge);
519  }
520  }
521  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
522  erase(dc, *j);
523  }
524 }
525 
526 
527 void
529  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
530  if ((*i).second->getGeometry().size() < 3) {
531  continue;
532  }
533  (*i).second->splitGeometry(*this, nc);
534  }
535 }
536 
537 
538 void
540  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
541  (*i).second->reduceGeometry(minDist);
542  }
543 }
544 
545 
546 void
547 NBEdgeCont::checkGeometries(const SUMOReal maxAngle, const SUMOReal minRadius, bool fix) {
548  if (maxAngle > 0 || minRadius > 0) {
549  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
550  (*i).second->checkGeometry(maxAngle, minRadius, fix);
551  }
552  }
553 }
554 
555 
556 // ----- processing methods
557 void
559  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
560  (*i).second->clearControllingTLInformation();
561  }
562 }
563 
564 
565 void
567  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
568  (*i).second->sortOutgoingConnectionsByAngle();
569  }
570 }
571 
572 
573 void
574 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
575  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
576  (*i).second->computeEdge2Edges(noLeftMovers);
577  }
578 }
579 
580 
581 void
583  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
584  (*i).second->computeLanes2Edges();
585  }
586 }
587 
588 
589 void
591  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
592  (*i).second->recheckLanes();
593  }
594 }
595 
596 
597 void
598 NBEdgeCont::appendTurnarounds(bool noTLSControlled) {
599  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
600  (*i).second->appendTurnaround(noTLSControlled);
601  }
602 }
603 
604 
605 void
606 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
607  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
608  myEdges[*it]->appendTurnaround(noTLSControlled);
609  }
610 }
611 
612 
613 void
615  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
616  (*i).second->computeEdgeShape();
617  }
618 }
619 
620 
621 void
623  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
624  (*i).second->computeLaneShapes();
625  }
626 }
627 
628 
629 void
632  EdgeVector edges) {
633  // !!! Attention!
634  // No merging of the geometry to come is being done
635  // The connections are moved from one edge to another within
636  // the replacement where the edge is a node's incoming edge.
637 
638  // count the number of lanes, the speed and the id
639  unsigned int nolanes = 0;
640  SUMOReal speed = 0;
641  int priority = 0;
642  std::string id;
643  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
644  // retrieve the connected nodes
645  NBEdge* tpledge = *(edges.begin());
646  NBNode* from = tpledge->getFromNode();
647  NBNode* to = tpledge->getToNode();
648  EdgeVector::const_iterator i;
649  for (i = edges.begin(); i != edges.end(); i++) {
650  // some assertions
651  assert((*i)->getFromNode() == from);
652  assert((*i)->getToNode() == to);
653  // ad the number of lanes the current edge has
654  nolanes += (*i)->getNumLanes();
655  // build the id
656  if (i != edges.begin()) {
657  id += "+";
658  }
659  id += (*i)->getID();
660  // compute the speed
661  speed += (*i)->getSpeed();
662  // build the priority
663  priority = MAX2(priority, (*i)->getPriority());
664  }
665  speed /= edges.size();
666  // build the new edge
667  // @bug new edge does not know about allowed vclass of old edges
668  // @bug both the width and the offset are not regarded
669  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
671  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
672  insert(newEdge, true);
673  // replace old edge by current within the nodes
674  // and delete the old
675  from->replaceOutgoing(edges, newEdge);
676  to->replaceIncoming(edges, newEdge);
677  // patch connections
678  // add edge2edge-information
679  for (i = edges.begin(); i != edges.end(); i++) {
680  EdgeVector ev = (*i)->getConnectedEdges();
681  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
682  newEdge->addEdge2EdgeConnection(*j);
683  }
684  }
685  // move lane2lane-connections
686  unsigned int currLane = 0;
687  for (i = edges.begin(); i != edges.end(); i++) {
688  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
689  currLane += (*i)->getNumLanes();
690  }
691  // patch tl-information
692  currLane = 0;
693  for (i = edges.begin(); i != edges.end(); i++) {
694  unsigned int noLanes = (*i)->getNumLanes();
695  for (unsigned int j = 0; j < noLanes; j++, currLane++) {
696  // replace in traffic lights
697  tlc.replaceRemoved(*i, j, newEdge, currLane);
698  }
699  }
700  // delete joined edges
701  for (i = edges.begin(); i != edges.end(); i++) {
702  erase(dc, *i);
703  }
704 }
705 
706 
707 void
709  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
710  std::string oppositeID;
711  if ((*i).first[0] == '-') {
712  oppositeID = (*i).first.substr(1);
713  } else {
714  oppositeID = "-" + (*i).first;
715  }
716  if (myEdges.find(oppositeID) != myEdges.end()) {
717  (*i).second->setLaneSpreadFunction(LANESPREAD_RIGHT);
718  myEdges.find(oppositeID)->second->setLaneSpreadFunction(LANESPREAD_RIGHT);
719  } else {
720  (*i).second->setLaneSpreadFunction(LANESPREAD_CENTER);
721  }
722  }
723 }
724 
725 
726 
727 // ----- other
728 void
729 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass) {
730  myConnections.push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass));
731 }
732 
733 
734 void
736  for (std::vector<PostProcessConnection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
737  NBEdge* from = retrievePossiblySplit((*i).from, true);
738  NBEdge* to = retrievePossiblySplit((*i).to, true);
739  if (from != 0 && to != 0) {
740  if (!from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::L2L_USER, false, (*i).mayDefinitelyPass)) {
741  WRITE_WARNING("Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.");
742  }
743  }
744  }
745  // during loading we also kept some ambiguous connections in hope they might be valid after processing
746  // we need to make sure that all invalid connections are removed now
747  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
748  NBEdge* edge = it->second;
749  NBNode* to = edge->getToNode();
750  // make a copy because we may delete connections
751  std::vector<NBEdge::Connection> connections = edge->getConnections();
752  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
753  NBEdge::Connection& c = *it_con;
754  if (c.toEdge != 0 && c.toEdge->getFromNode() != to) {
755  WRITE_WARNING("Found and removed invalid connection from " + edge->getID() +
756  " to " + c.toEdge->getID() + " via " + to->getID());
757  edge->removeFromConnections(c.toEdge);
758  }
759  }
760  }
761 }
762 
763 
765 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
766  size_t len = id.length();
767  EdgeVector ret;
768  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
769  std::string curr = (*i).first;
770  // the next check makes it possibly faster - we don not have
771  // to compare the names
772  if (curr.length() <= len) {
773  continue;
774  }
775  // the name must be the same as the given id but something
776  // beginning with a '[' must be appended to it
777  if (curr.substr(0, len) == id && curr[len] == '[') {
778  ret.push_back((*i).second);
779  continue;
780  }
781  // ok, maybe the edge is a compound made during joining of edges
782  size_t pos = curr.find(id);
783  // surely not
784  if (pos == std::string::npos) {
785  continue;
786  }
787  // check leading char
788  if (pos > 0) {
789  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
790  // actually, this is another id
791  continue;
792  }
793  }
794  if (pos + id.length() < curr.length()) {
795  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
796  // actually, this is another id
797  continue;
798  }
799  }
800  ret.push_back((*i).second);
801  }
802  return ret;
803 }
804 
805 
806 void
807 NBEdgeCont::guessRoundabouts(std::vector<EdgeVector>& marked) {
808  // step 1: keep only those edges which have no turnarounds
809  std::set<NBEdge*> candidates;
810  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
811  NBEdge* e = (*i).second;
812  NBNode* const to = e->getToNode();
813  if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) {
814  candidates.insert(e);
815  }
816  }
817 
818  // step 2:
819  std::set<NBEdge*> visited;
820  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
821  EdgeVector loopEdges;
822  // start with a random edge (this doesn't have to be a roundabout edge)
823  // loop over connected edges (using always the leftmost one)
824  // and keep the list in loopEdges
825  // continue until we loop back onto a loopEdges and extract the loop
826  NBEdge* e = (*i);
827  if (visited.count(e) > 0) {
828  // already seen
829  continue;
830  }
831  loopEdges.push_back(e);
832  bool doLoop = true;
833  do {
834  visited.insert(e);
835  const EdgeVector& edges = e->getToNode()->getEdges();
836  if (edges.size() < 2) {
837  doLoop = false;
838  break;
839  }
840  if (e->getTurnDestination() != 0 || e->getToNode()->getConnectionTo(e->getFromNode()) != 0) {
841  // do not follow turn-arounds while in a (tentative) loop
842  doLoop = false;
843  break;
844  }
845  EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e);
846  NBContHelper::nextCW(edges, me);
847  NBEdge* left = *me;
848  SUMOReal angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
849  if (angle >= 90) {
850  // roundabouts do not have sharp turns (or they wouldn't be called 'round')
851  doLoop = false;
852  break;
853  }
854  EdgeVector::const_iterator loopClosed = find(loopEdges.begin(), loopEdges.end(), left);
855  const size_t loopSize = loopEdges.end() - loopClosed;
856  if (loopSize > 0) {
857  // loop found
858  if (loopSize < 3) {
859  doLoop = false; // need at least 3 edges for a roundabout
860  } else if (loopSize < loopEdges.size()) {
861  // remove initial edges not belonging to the loop
862  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
863  }
864  // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
865  int attachments = 0;
866  for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
867  if ((*j)->getToNode()->getEdges().size() > 2) {
868  attachments++;
869  }
870  }
871  if (attachments < 3) {
872  doLoop = false;
873  }
874  break;
875  }
876  if (visited.count(left) > 0) {
877  doLoop = false;
878  } else {
879  // keep going
880  loopEdges.push_back(left);
881  e = left;
882  }
883  } while (doLoop);
884  // mark collected edges in the case a loop (roundabout) was found
885  if (doLoop) {
886  std::set<NBEdge*> loopEdgesSet(loopEdges.begin(), loopEdges.end());
887  for (std::set<NBEdge*>::const_iterator j = loopEdgesSet.begin(); j != loopEdgesSet.end(); ++j) {
888  // disable turnarounds on incoming edges
889  NBNode* node = (*j)->getToNode();
890  const EdgeVector& incoming = node->getIncomingEdges();
891  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
892  NBEdge* inEdge = *k;
893  if (loopEdgesSet.count(inEdge) > 0) {
894  continue;
895  }
896  if ((inEdge)->getStep() >= NBEdge::LANES2LANES_USER) {
897  continue;
898  }
899  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
900  }
901  // let the connections to succeeding roundabout edge have a higher priority
902  (*j)->setJunctionPriority(node, 1000);
903  node->setRoundabout();
904  }
905  marked.push_back(loopEdges);
906  }
907  }
908 }
909 
910 
911 void
913  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
914  NBEdge* e = i->second;
915  // is this a "real" junction?
916  // XXX nyi
917  //continue
918  const SUMOReal offset = e->getLength() - 3;
919  switch (e->getToNode()->getType()) {
920  case NODETYPE_PRIORITY:
921  // yield or major?
922  if (e->getJunctionPriority(e->getToNode()) > 0) {
924  } else {
926  }
927  break;
929  // yield or major?
930  if (e->getJunctionPriority(e->getToNode()) > 0) {
932  } else {
934  }
935  break;
938  break;
941  break;
942  default:
943  break;
944  }
945  }
946 }
947 
948 /****************************************************************************/
~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:797
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&#39;s incoming edges.
Definition: NBNode.h:177
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:566
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:1437
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:500
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:2023
void moveOutgoingConnectionsFrom(NBEdge *e, unsigned int laneOff)
Definition: NBEdge.cpp:1612
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:977
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&#39;s lane and an approached one.
Definition: NBEdge.cpp:613
void removeDoubleEdges()
Definition: NBNode.cpp:865
T MAX2(T a, T b)
Definition: StdDefs.h:63
void clearControllingTLInformation() const
Clears information about controlling traffic lights for all connenections of all edges.
Definition: NBEdgeCont.cpp:558
void generateStreetSigns()
assigns street signs to edges based on toNode types
Definition: NBEdgeCont.cpp:912
void rename(NBEdge *edge, const std::string &newID)
Renames the edge. Throws exception if newID already exists.
Definition: NBEdgeCont.cpp:382
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
Definition: NBEdgeCont.cpp:394
void recheckPostProcessConnections()
Try to set any stored connections.
Definition: NBEdgeCont.cpp:735
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:582
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:547
void guessRoundabouts(std::vector< EdgeVector > &marked)
Determines which edges belong to roundabouts and increases their priority.
Definition: NBEdgeCont.cpp:807
NBEdgeCont(NBTypeCont &tc)
Constructor.
Definition: NBEdgeCont.cpp:69
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges.
Definition: NBNode.h:185
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:589
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:165
void reduceGeometries(const SUMOReal minDist)
Definition: NBEdgeCont.cpp:539
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:511
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:370
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:202
void computeEdge2Edges(bool noLeftMovers)
Computes for each edge the approached edges.
Definition: NBEdgeCont.cpp:574
void computeLaneShapes()
Computes the shapes of all lanes of all edges stored in the container.
Definition: NBEdgeCont.cpp:622
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:193
SUMOReal myLaneWidth
This width of this edge&#39;s lanes.
Definition: NBEdge.h:1223
void splitGeometry(NBNodeCont &nc)
Splits edges into multiple if they have a complex geometry.
Definition: NBEdgeCont.cpp:528
EdgeCont myEdges
The instance of the dictionary (id-&gt;edge)
Definition: NBEdgeCont.h:554
#define POSITION_EPS
Definition: config.h:186
SUMOReal myOffset
This edges&#39;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:824
NBEdge * getConnectionTo(NBNode *n) const
Definition: NBNode.cpp:1344
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1096
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
Definition: NBEdgeCont.cpp:630
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:2067
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:761
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:598
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:363
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:1134
void computeEdgeShapes()
Computes the shapes of all edges stored in the container.
Definition: NBEdgeCont.cpp:614
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:2088
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:708
NBEdge * getTurnDestination() const
Definition: NBEdge.cpp:1863
#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:590
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:422
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
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:765
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:729
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:929
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&#39;s geometry at the given node.
Definition: NBEdge.cpp:1116
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