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.sourceforge.net/
13 // Copyright (C) 2001-2012 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>
44 #include <utils/common/ToString.h>
47 #include "NBNetBuilder.h"
48 #include "NBEdgeCont.h"
49 #include "NBNodeCont.h"
50 #include "NBHelpers.h"
51 #include "NBCont.h"
53 #include "NBDistrictCont.h"
54 #include <cmath>
55 #include "NBTypeCont.h"
56 #include <iostream>
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  myEdgesSplit(0),
71  myTypeCont(tc),
72  myVehicleClasses2Keep(0),
73  myVehicleClasses2Remove(0)
74 {}
75 
76 
78  clear();
79 }
80 
81 
82 void
84  myAmLeftHanded = oc.getBool("lefthand");
85  // set edges dismiss/accept options
86  myEdgesMinSpeed = oc.isSet("keep-edges.min-speed") ? oc.getFloat("keep-edges.min-speed") : -1;
87  myRemoveEdgesAfterJoining = oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload");
88  if (oc.isSet("keep-edges.explicit")) {
89  const std::vector<std::string> edges = oc.getStringVector("keep-edges.explicit");
90  myEdges2Keep.insert(edges.begin(), edges.end());
91  }
92  if (oc.isSet("remove-edges.explicit")) {
93  const std::vector<std::string> edges = oc.getStringVector("remove-edges.explicit");
94  myEdges2Remove.insert(edges.begin(), edges.end());
95  }
96  if (oc.exists("keep-edges.by-vclass") && oc.isSet("keep-edges.by-vclass")) {
97  const std::vector<std::string> classes = oc.getStringVector("keep-edges.by-vclass");
98  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
100  }
101  }
102  if (oc.exists("remove-edges.by-vclass") && oc.isSet("remove-edges.by-vclass")) {
103  const std::vector<std::string> classes = oc.getStringVector("remove-edges.by-vclass");
104  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
106  }
107  }
108  if (oc.exists("keep-edges.by-type") && oc.isSet("keep-edges.by-type")) {
109  const std::vector<std::string> types = oc.getStringVector("keep-edges.by-type");
110  myTypes2Keep.insert(types.begin(), types.end());
111  }
112  if (oc.exists("remove-edges.by-type") && oc.isSet("remove-edges.by-type")) {
113  const std::vector<std::string> types = oc.getStringVector("remove-edges.by-type");
114  myTypes2Remove.insert(types.begin(), types.end());
115  }
116 
117  if (oc.isSet("keep-edges.in-boundary")) {
118  std::vector<std::string> polyS = oc.getStringVector("keep-edges.in-boundary");
119  // !!! throw something if length<4 || length%2!=0?
120  std::vector<SUMOReal> poly;
121  for (std::vector<std::string>::iterator i = polyS.begin(); i != polyS.end(); ++i) {
122  poly.push_back(TplConvert<char>::_2SUMOReal((*i).c_str())); // !!! may throw something anyhow...
123  }
124  if (poly.size() < 4) {
125  throw ProcessError("Invalid boundary: need at least 2 coordinates");
126  } else if (poly.size() % 2 != 0) {
127  throw ProcessError("Invalid boundary: malformed coordinate");
128  } else if (poly.size() == 4) {
129  // prunning boundary (box)
130  myPrunningBoundary.push_back(Position(poly[0], poly[1]));
131  myPrunningBoundary.push_back(Position(poly[2], poly[1]));
132  myPrunningBoundary.push_back(Position(poly[2], poly[3]));
133  myPrunningBoundary.push_back(Position(poly[0], poly[3]));
134  } else {
135  for (std::vector<SUMOReal>::iterator j = poly.begin(); j != poly.end();) {
136  SUMOReal x = *j++;
137  SUMOReal y = *j++;
139  }
140  }
141  }
142 }
143 
144 
145 void
147  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
148  delete((*i).second);
149  }
150  myEdges.clear();
151  for (EdgeCont::iterator i = myExtractedEdges.begin(); i != myExtractedEdges.end(); i++) {
152  delete((*i).second);
153  }
154  myExtractedEdges.clear();
155 }
156 
157 
158 
159 // ----- edge access methods
160 bool
161 NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
162  if (myAmLeftHanded) {
163  edge->setLeftHanded();
164  }
165  if (myEdges.count(edge->getID())) {
166  return false;
167  }
168  if (!ignorePrunning && ignoreFilterMatch(edge)) {
169  edge->getFromNode()->removeEdge(edge);
170  edge->getToNode()->removeEdge(edge);
171  myIgnoredEdges.insert(edge->getID());
172  delete edge;
173  } else {
175  if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
177  }
178  myEdges[edge->getID()] = edge;
179  }
180  return true;
181 }
182 
183 
184 bool
186  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
187  if (edge->getSpeed() < myEdgesMinSpeed) {
188  return true;
189  }
190  // check whether the edge is a named edge to keep
191  if (!myRemoveEdgesAfterJoining && myEdges2Keep.size() != 0) {
192  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) == myEdges2Keep.end()) {
193  return true;
194  }
195  }
196  // check whether the edge is a named edge to remove
197  if (myEdges2Remove.size() != 0) {
198  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
199  return true;
200  }
201  }
202  // check whether the edge shall be removed because it does not allow any of the wished classes
203  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
204  return true;
205  }
206  // check whether the edge shall be removed due to allowing unwished classes only
208  return true;
209  }
210  // check whether the edge shall be removed because it does not have one of the requested types
211  if (myTypes2Keep.size() != 0) {
212  if (myTypes2Keep.count(edge->getTypeID()) == 0) {
213  return true;
214  }
215  }
216  // check whether the edge shall be removed because it has one of the forbidden types
217  if (myTypes2Remove.size() != 0) {
218  if (myTypes2Remove.count(edge->getTypeID()) > 0) {
219  return true;
220  }
221  }
222  // check whether the edge is within the prunning boundary
223  if (myPrunningBoundary.size() != 0) {
225  return true;
226  }
227  }
229  return true;
230  }
231  return false;
232 }
233 
234 
235 NBEdge*
236 NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
237  EdgeCont::const_iterator i = myEdges.find(id);
238  if (i == myEdges.end()) {
239  if (retrieveExtracted) {
240  i = myExtractedEdges.find(id);
241  if (i == myExtractedEdges.end()) {
242  return 0;
243  }
244  } else {
245  return 0;
246  }
247  }
248  return (*i).second;
249 }
250 
251 
252 NBEdge*
254  const std::string& hint,
255  bool incoming) const {
256  // try to retrieve using the given name (iterative)
257  NBEdge* edge = retrieve(id);
258  if (edge != 0) {
259  return edge;
260  }
261  // now, we did not find it; we have to look over all possibilities
262  EdgeVector hints;
263  // check whether at least the hint was not splitted
264  NBEdge* hintedge = retrieve(hint);
265  if (hintedge == 0) {
266  hints = getGeneratedFrom(hint);
267  } else {
268  hints.push_back(hintedge);
269  }
270  EdgeVector candidates = getGeneratedFrom(id);
271  for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) {
272  NBEdge* hintedge = (*i);
273  for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) {
274  NBEdge* poss_searched = (*j);
275  NBNode* node = incoming
276  ? poss_searched->myTo : poss_searched->myFrom;
277  const EdgeVector& cont = incoming
278  ? node->getOutgoingEdges() : node->getIncomingEdges();
279  if (find(cont.begin(), cont.end(), hintedge) != cont.end()) {
280  return poss_searched;
281  }
282  }
283  }
284  return 0;
285 }
286 
287 
288 NBEdge*
289 NBEdgeCont::retrievePossiblySplitted(const std::string& id, SUMOReal pos) const {
290  // check whether the edge was not split, yet
291  NBEdge* edge = retrieve(id);
292  if (edge != 0) {
293  return edge;
294  }
295  size_t maxLength = 0;
296  std::string tid = id + "[";
297  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
298  if ((*i).first.find(tid) == 0) {
299  maxLength = MAX2(maxLength, (*i).first.length());
300  }
301  }
302  // find the part of the edge which matches the position
303  SUMOReal seen = 0;
304  std::vector<std::string> names;
305  names.push_back(id + "[1]");
306  names.push_back(id + "[0]");
307  while (names.size() > 0) {
308  // retrieve the first subelement (to follow)
309  std::string cid = names.back();
310  names.pop_back();
311  edge = retrieve(cid);
312  // The edge was splitted; check its subparts within the
313  // next step
314  if (edge == 0) {
315  if (cid.length() + 3 < maxLength) {
316  names.push_back(cid + "[1]");
317  names.push_back(cid + "[0]");
318  }
319  }
320  // an edge with the name was found,
321  // check whether the position lies within it
322  else {
323  seen += edge->getLength();
324  if (seen >= pos) {
325  return edge;
326  }
327  }
328  }
329  return 0;
330 }
331 
332 
333 void
335  extract(dc, edge);
336  delete edge;
337 }
338 
339 
340 void
341 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
342  if (remember) {
343  myExtractedEdges[edge->getID()] = edge;
344  }
345  myEdges.erase(edge->getID());
346  edge->myFrom->removeEdge(edge);
347  edge->myTo->removeEdge(edge);
348  dc.removeFromSinksAndSources(edge);
349 }
350 
351 
352 void
353 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
354  if (myEdges.count(newID) != 0) {
355  throw ProcessError("Attempt to rename edge using existing id '" + newID + "'");
356  }
357  myEdges.erase(edge->getID());
358  edge->setID(newID);
359  myEdges[newID] = edge;
360 }
361 
362 
363 // ----- explicit edge manipulation methods
364 bool
366  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
367  (unsigned int) edge->myLanes.size(), (unsigned int) edge->myLanes.size());
368 }
369 
370 
371 bool
373  const std::string& firstEdgeName,
374  const std::string& secondEdgeName,
375  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
376  SUMOReal pos;
378  if (pos <= 0) {
380  edge->myFrom->getPosition(), edge->myTo->getPosition(),
381  node->getPosition());
382  }
383  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
384  return false;
385  }
386  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
387  noLanesFirstEdge, noLanesSecondEdge);
388 }
389 
390 
391 bool
393  NBEdge* edge, SUMOReal pos, NBNode* node,
394  const std::string& firstEdgeName,
395  const std::string& secondEdgeName,
396  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
397  // build the new edges' geometries
398  std::pair<PositionVector, PositionVector> geoms =
399  edge->getGeometry().splitAt(pos);
400  if (geoms.first[-1] != node->getPosition()) {
401  geoms.first.pop_back();
402  geoms.first.push_back(node->getPosition());
403  }
404 
405  if (geoms.second[0] != node->getPosition()) {
406  geoms.second.pop_front();
407  geoms.second.push_front(node->getPosition());
408  }
409  // build and insert the edges
410  NBEdge* one = new NBEdge(firstEdgeName,
411  edge->myFrom, node, edge->myType, edge->mySpeed, noLanesFirstEdge,
412  edge->getPriority(), edge->myWidth, 0, geoms.first,
413  edge->getStreetName(), edge->myLaneSpreadFunction, true);
414  for (unsigned int i = 0; i < noLanesFirstEdge && i < edge->getNumLanes(); i++) {
415  one->setSpeed(i, edge->getLaneSpeed(i));
416  }
417  NBEdge* two = new NBEdge(secondEdgeName,
418  node, edge->myTo, edge->myType, edge->mySpeed, noLanesSecondEdge,
419  edge->getPriority(), edge->myWidth, edge->myOffset, geoms.second,
420  edge->getStreetName(), edge->myLaneSpreadFunction, true);
421  for (unsigned int i = 0; i < noLanesSecondEdge && i < edge->getNumLanes(); i++) {
422  two->setSpeed(i, edge->getLaneSpeed(i));
423  }
424  two->copyConnectionsFrom(edge);
425  // replace information about this edge within the nodes
426  edge->myFrom->replaceOutgoing(edge, one, 0);
427  edge->myTo->replaceIncoming(edge, two, 0);
428  // the edge is now occuring twice in both nodes...
429  // clean up
430  edge->myFrom->removeDoubleEdges();
431  edge->myTo->removeDoubleEdges();
432  // add connections from the first to the second edge
433  // check special case:
434  // one in, one out, the outgoing has one lane more
435  if (noLanesFirstEdge == noLanesSecondEdge - 1) {
436  for (unsigned int i = 0; i < one->getNumLanes(); i++) {
437  if (!one->addLane2LaneConnection(i, two, i + 1, NBEdge::L2L_COMPUTED)) { // !!! Bresenham, here!!!
438  throw ProcessError("Could not set connection!");
439  }
440  }
442  } else {
443  for (unsigned int i = 0; i < one->getNumLanes() && i < two->getNumLanes(); i++) {
444  if (!one->addLane2LaneConnection(i, two, i, NBEdge::L2L_COMPUTED)) {// !!! Bresenham, here!!!
445  throw ProcessError("Could not set connection!");
446  }
447  }
448  }
450  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) != myEdges2Keep.end()) {
451  myEdges2Keep.insert(one->getID());
452  myEdges2Keep.insert(two->getID());
453  }
454  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
455  myEdges2Remove.insert(one->getID());
456  myEdges2Remove.insert(two->getID());
457  }
458  }
459  // erase the splitted edge
460  erase(dc, edge);
461  insert(one, true);
462  insert(two, true);
463  myEdgesSplit++;
464  return true;
465 }
466 
467 
468 
469 // ----- container access methods
470 std::vector<std::string>
472  std::vector<std::string> ret;
473  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
474  ret.push_back((*i).first);
475  }
476  return ret;
477 }
478 
479 
480 // ----- Adapting the input
481 void
483  EdgeVector toRemove;
484  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
485  NBEdge* edge = (*i).second;
486  if (!myEdges2Keep.count(edge->getID())) {
487  edge->getFromNode()->removeEdge(edge);
488  edge->getToNode()->removeEdge(edge);
489  toRemove.push_back(edge);
490  }
491  }
492  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
493  erase(dc, *j);
494  }
495 }
496 
497 
498 void
500  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
501  if ((*i).second->getGeometry().size() < 3) {
502  continue;
503  }
504  (*i).second->splitGeometry(*this, nc);
505  }
506 }
507 
508 
509 // ----- processing methods
510 void
512  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
513  (*i).second->clearControllingTLInformation();
514  }
515 }
516 
517 
518 void
520  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
521  (*i).second->sortOutgoingConnectionsByAngle();
522  }
523 }
524 
525 
526 void
527 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
528  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
529  (*i).second->computeEdge2Edges(noLeftMovers);
530  }
531 }
532 
533 
534 void
536  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
537  (*i).second->computeLanes2Edges();
538  }
539 }
540 
541 
542 void
544  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
545  (*i).second->recheckLanes();
546  }
547 }
548 
549 
550 void
551 NBEdgeCont::appendTurnarounds(bool noTLSControlled) {
552  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
553  (*i).second->appendTurnaround(noTLSControlled);
554  }
555 }
556 
557 
558 void
559 NBEdgeCont::appendTurnarounds(const std::set<std::string> &ids, bool noTLSControlled) {
560  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
561  myEdges[*it]->appendTurnaround(noTLSControlled);
562  }
563 }
564 
565 
566 void
568  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
569  (*i).second->computeEdgeShape();
570  }
571 }
572 
573 
574 void
576  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
577  (*i).second->computeLaneShapes();
578  }
579 }
580 
581 
582 void
585  EdgeVector edges) {
586  // !!! Attention!
587  // No merging of the geometry to come is being done
588  // The connections are moved from one edge to another within
589  // the replacement where the edge is a node's incoming edge.
590 
591  // count the number of lanes, the speed and the id
592  unsigned int nolanes = 0;
593  SUMOReal speed = 0;
594  int priority = 0;
595  std::string id;
596  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
597  // retrieve the connected nodes
598  NBEdge* tpledge = *(edges.begin());
599  NBNode* from = tpledge->getFromNode();
600  NBNode* to = tpledge->getToNode();
601  EdgeVector::const_iterator i;
602  for (i = edges.begin(); i != edges.end(); i++) {
603  // some assertions
604  assert((*i)->getFromNode() == from);
605  assert((*i)->getToNode() == to);
606  // ad the number of lanes the current edge has
607  nolanes += (*i)->getNumLanes();
608  // build the id
609  if (i != edges.begin()) {
610  id += "+";
611  }
612  id += (*i)->getID();
613  // compute the speed
614  speed += (*i)->getSpeed();
615  // build the priority
616  priority = MAX2(priority, (*i)->getPriority());
617  }
618  speed /= edges.size();
619  // build the new edge
620  // @bug new edge does not know about allowed vclass of old edges
621  // @bug both the width and the offset are not regarded
622  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
624  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
625  insert(newEdge, true);
626  // replace old edge by current within the nodes
627  // and delete the old
628  from->replaceOutgoing(edges, newEdge);
629  to->replaceIncoming(edges, newEdge);
630  // patch connections
631  // add edge2edge-information
632  for (i = edges.begin(); i != edges.end(); i++) {
633  EdgeVector ev = (*i)->getConnectedEdges();
634  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
635  newEdge->addEdge2EdgeConnection(*j);
636  }
637  }
638  // move lane2lane-connections
639  unsigned int currLane = 0;
640  for (i = edges.begin(); i != edges.end(); i++) {
641  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
642  currLane += (*i)->getNumLanes();
643  }
644  // patch tl-information
645  currLane = 0;
646  for (i = edges.begin(); i != edges.end(); i++) {
647  unsigned int noLanes = (*i)->getNumLanes();
648  for (unsigned int j = 0; j < noLanes; j++, currLane++) {
649  // replace in traffic lights
650  tlc.replaceRemoved(*i, j, newEdge, currLane);
651  }
652  }
653  // delete joined edges
654  for (i = edges.begin(); i != edges.end(); i++) {
655  erase(dc, *i);
656  }
657 }
658 
659 
660 void
662  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
663  std::string oppositeID;
664  if ((*i).first[0] == '-') {
665  oppositeID = (*i).first.substr(1);
666  } else {
667  oppositeID = "-" + (*i).first;
668  }
669  if (myEdges.find(oppositeID) != myEdges.end()) {
670  (*i).second->setLaneSpreadFunction(LANESPREAD_RIGHT);
671  myEdges.find(oppositeID)->second->setLaneSpreadFunction(LANESPREAD_RIGHT);
672  } else {
673  (*i).second->setLaneSpreadFunction(LANESPREAD_CENTER);
674  }
675  }
676 }
677 
678 
679 
680 // ----- other
682 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
683  size_t len = id.length();
684  EdgeVector ret;
685  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
686  std::string curr = (*i).first;
687  // the next check makes it possibly faster - we don not have
688  // to compare the names
689  if (curr.length() <= len) {
690  continue;
691  }
692  // the name must be the same as the given id but something
693  // beginning with a '[' must be appended to it
694  if (curr.substr(0, len) == id && curr[len] == '[') {
695  ret.push_back((*i).second);
696  continue;
697  }
698  // ok, maybe the edge is a compound made during joining of edges
699  size_t pos = curr.find(id);
700  // surely not
701  if (pos == std::string::npos) {
702  continue;
703  }
704  // check leading char
705  if (pos > 0) {
706  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
707  // actually, this is another id
708  continue;
709  }
710  }
711  if (pos + id.length() < curr.length()) {
712  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
713  // actually, this is another id
714  continue;
715  }
716  }
717  ret.push_back((*i).second);
718  }
719  return ret;
720 }
721 
722 
723 void
724 NBEdgeCont::guessRoundabouts(std::vector<std::set<NBEdge*> > &marked) {
725  // step 1: keep only those edges which have no turnarounds
726  std::set<NBEdge*> candidates;
727  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
728  NBEdge* e = (*i).second;
729  NBNode* const to = e->getToNode();
730  if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) {
731  candidates.insert(e);
732  }
733  }
734  // step 2:
735  std::set<NBEdge*> visited;
736  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
737  std::set<NBEdge*> loopEdges;
738  // start with a random edge, keep it as "begin"
739  NBEdge* begin = (*i);
740  if (find(visited.begin(), visited.end(), begin) != visited.end()) {
741  // already seen
742  continue;
743  }
744  NBEdge* e = (*i);
745  // loop over connected edges (using always the leftmost one)
746  bool noLoop = false;
747  do {
748  visited.insert(e);
749  EdgeVector edges = e->getToNode()->getEdges();
750  if (edges.size() < 2) {
751  noLoop = true;
752  break;
753  }
754  EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e);
755  NBContHelper::nextCW(edges, me);
756  NBEdge* left = *me;
757  loopEdges.insert(left);
758  if (left == begin) {
759  break;
760  }
761  if (find(candidates.begin(), candidates.end(), left) == candidates.end()) {
762  noLoop = true;
763  break;
764  }
765  if (find(visited.begin(), visited.end(), left) != visited.end()) {
766  noLoop = true;
767  break;
768  }
769  e = left;
770  } while (true);
771  // mark collected edges in the case a loop (roundabout) was found
772  if (!noLoop) {
773  for (std::set<NBEdge*>::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
774 
775  // disable turnarounds on incoming edges
776  const EdgeVector& incoming = (*j)->getToNode()->getIncomingEdges();
777  const EdgeVector& outgoing = (*j)->getToNode()->getOutgoingEdges();
778  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
779  if (loopEdges.find(*k) != loopEdges.end()) {
780  continue;
781  }
782  if ((*k)->getStep() >= NBEdge::LANES2LANES_USER) {
783  continue;
784  }
785  for (EdgeVector::const_iterator l = outgoing.begin(); l != outgoing.end(); ++l) {
786  if (loopEdges.find(*l) != loopEdges.end()) {
787  (*k)->addEdge2EdgeConnection(*l);
788  } else {
789  (*k)->removeFromConnections(*l, -1);
790  }
791  }
792  }
793 
794 
795  // let the connections to succeeding roundabout edge have a higher priority
796  (*j)->setJunctionPriority((*j)->getToNode(), 1000);
797  }
798  marked.push_back(loopEdges);
799  }
800  }
801 }
802 
803 
804 /****************************************************************************/