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-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>
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"
59 
60 #ifdef CHECK_MEMORY_LEAKS
61 #include <foreign/nvwa/debug_new.h>
62 #endif // CHECK_MEMORY_LEAKS
63 
64 
65 // ===========================================================================
66 // method definitions
67 // ===========================================================================
69  myEdgesSplit(0),
70  myVehicleClasses2Keep(0),
71  myVehicleClasses2Remove(0),
72  myTypeCont(tc)
73 {}
74 
75 
77  clear();
78 }
79 
80 
81 void
83  myAmLeftHanded = oc.getBool("lefthand");
84  // set edges dismiss/accept options
85  myEdgesMinSpeed = oc.isSet("keep-edges.min-speed") ? oc.getFloat("keep-edges.min-speed") : -1;
86  myRemoveEdgesAfterJoining = oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload");
87  if (oc.isSet("keep-edges.explicit")) {
88  const std::vector<std::string> edges = oc.getStringVector("keep-edges.explicit");
89  myEdges2Keep.insert(edges.begin(), edges.end());
90  }
91  if (oc.isSet("remove-edges.explicit")) {
92  const std::vector<std::string> edges = oc.getStringVector("remove-edges.explicit");
93  myEdges2Remove.insert(edges.begin(), edges.end());
94  }
95  if (oc.exists("keep-edges.by-vclass") && oc.isSet("keep-edges.by-vclass")) {
96  const std::vector<std::string> classes = oc.getStringVector("keep-edges.by-vclass");
97  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
99  }
100  }
101  if (oc.exists("remove-edges.by-vclass") && oc.isSet("remove-edges.by-vclass")) {
102  const std::vector<std::string> classes = oc.getStringVector("remove-edges.by-vclass");
103  for (std::vector<std::string>::const_iterator i = classes.begin(); i != classes.end(); ++i) {
105  }
106  }
107  if (oc.exists("keep-edges.by-type") && oc.isSet("keep-edges.by-type")) {
108  const std::vector<std::string> types = oc.getStringVector("keep-edges.by-type");
109  myTypes2Keep.insert(types.begin(), types.end());
110  }
111  if (oc.exists("remove-edges.by-type") && oc.isSet("remove-edges.by-type")) {
112  const std::vector<std::string> types = oc.getStringVector("remove-edges.by-type");
113  myTypes2Remove.insert(types.begin(), types.end());
114  }
115 
116  if (oc.isSet("keep-edges.in-boundary")) {
117  std::vector<std::string> polyS = oc.getStringVector("keep-edges.in-boundary");
118  // !!! throw something if length<4 || length%2!=0?
119  std::vector<SUMOReal> poly;
120  for (std::vector<std::string>::iterator i = polyS.begin(); i != polyS.end(); ++i) {
121  poly.push_back(TplConvert::_2SUMOReal((*i).c_str())); // !!! may throw something anyhow...
122  }
123  if (poly.size() < 4) {
124  throw ProcessError("Invalid boundary: need at least 2 coordinates");
125  } else if (poly.size() % 2 != 0) {
126  throw ProcessError("Invalid boundary: malformed coordinate");
127  } else if (poly.size() == 4) {
128  // prunning boundary (box)
129  myPrunningBoundary.push_back(Position(poly[0], poly[1]));
130  myPrunningBoundary.push_back(Position(poly[2], poly[1]));
131  myPrunningBoundary.push_back(Position(poly[2], poly[3]));
132  myPrunningBoundary.push_back(Position(poly[0], poly[3]));
133  } else {
134  for (std::vector<SUMOReal>::iterator j = poly.begin(); j != poly.end();) {
135  SUMOReal x = *j++;
136  SUMOReal y = *j++;
138  }
139  }
140  }
141 }
142 
143 
144 void
146  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
147  delete((*i).second);
148  }
149  myEdges.clear();
150  for (EdgeCont::iterator i = myExtractedEdges.begin(); i != myExtractedEdges.end(); i++) {
151  delete((*i).second);
152  }
153  myExtractedEdges.clear();
154 }
155 
156 
157 
158 // ----- edge access methods
159 bool
160 NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
161  if (myAmLeftHanded) {
162  edge->setLeftHanded();
163  }
164  if (myEdges.count(edge->getID())) {
165  return false;
166  }
167  if (!ignorePrunning && ignoreFilterMatch(edge)) {
168  edge->getFromNode()->removeEdge(edge);
169  edge->getToNode()->removeEdge(edge);
170  myIgnoredEdges.insert(edge->getID());
171  delete edge;
172  } else {
174  if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
176  }
177  myEdges[edge->getID()] = edge;
178  }
179  return true;
180 }
181 
182 
183 bool
185  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
186  if (edge->getSpeed() < myEdgesMinSpeed) {
187  return true;
188  }
189  // check whether the edge is a named edge to keep
190  if (!myRemoveEdgesAfterJoining && myEdges2Keep.size() != 0) {
191  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) == myEdges2Keep.end()) {
192  return true;
193  }
194  }
195  // check whether the edge is a named edge to remove
196  if (myEdges2Remove.size() != 0) {
197  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
198  return true;
199  }
200  }
201  // check whether the edge shall be removed because it does not allow any of the wished classes
202  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
203  return true;
204  }
205  // check whether the edge shall be removed due to allowing unwished classes only
207  return true;
208  }
209  // check whether the edge shall be removed because it does not have one of the requested types
210  if (myTypes2Keep.size() != 0) {
211  if (myTypes2Keep.count(edge->getTypeID()) == 0) {
212  return true;
213  }
214  }
215  // check whether the edge shall be removed because it has one of the forbidden types
216  if (myTypes2Remove.size() != 0) {
217  if (myTypes2Remove.count(edge->getTypeID()) > 0) {
218  return true;
219  }
220  }
221  // check whether the edge is within the prunning boundary
222  if (myPrunningBoundary.size() != 0) {
224  return true;
225  }
226  }
228  return true;
229  }
230  return false;
231 }
232 
233 
234 NBEdge*
235 NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
236  EdgeCont::const_iterator i = myEdges.find(id);
237  if (i == myEdges.end()) {
238  if (retrieveExtracted) {
239  i = myExtractedEdges.find(id);
240  if (i == myExtractedEdges.end()) {
241  return 0;
242  }
243  } else {
244  return 0;
245  }
246  }
247  return (*i).second;
248 }
249 
250 
251 NBEdge*
252 NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
253  // try to retrieve using the given name (iterative)
254  NBEdge* edge = retrieve(id);
255  if (edge != 0) {
256  return edge;
257  }
258  // now, we did not find it; we have to look over all possibilities
259  EdgeVector hints;
260  // check whether at least the hint was not splitted
261  NBEdge* hintedge = retrieve(hint);
262  if (hintedge == 0) {
263  hints = getGeneratedFrom(hint);
264  } else {
265  hints.push_back(hintedge);
266  }
267  EdgeVector candidates = getGeneratedFrom(id);
268  for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) {
269  NBEdge* hintedge = (*i);
270  for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) {
271  NBEdge* poss_searched = (*j);
272  NBNode* node = incoming
273  ? poss_searched->myTo : poss_searched->myFrom;
274  const EdgeVector& cont = incoming
275  ? node->getOutgoingEdges() : node->getIncomingEdges();
276  if (find(cont.begin(), cont.end(), hintedge) != cont.end()) {
277  return poss_searched;
278  }
279  }
280  }
281  return 0;
282 }
283 
284 
285 NBEdge*
286 NBEdgeCont::retrievePossiblySplit(const std::string& id, SUMOReal pos) const {
287  // check whether the edge was not split, yet
288  NBEdge* edge = retrieve(id);
289  if (edge != 0) {
290  return edge;
291  }
292  size_t maxLength = 0;
293  std::string tid = id + "[";
294  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
295  if ((*i).first.find(tid) == 0) {
296  maxLength = MAX2(maxLength, (*i).first.length());
297  }
298  }
299  // find the part of the edge which matches the position
300  SUMOReal seen = 0;
301  std::vector<std::string> names;
302  names.push_back(id + "[1]");
303  names.push_back(id + "[0]");
304  while (names.size() > 0) {
305  // retrieve the first subelement (to follow)
306  std::string cid = names.back();
307  names.pop_back();
308  edge = retrieve(cid);
309  // The edge was splitted; check its subparts within the
310  // next step
311  if (edge == 0) {
312  if (cid.length() + 3 < maxLength) {
313  names.push_back(cid + "[1]");
314  names.push_back(cid + "[0]");
315  }
316  }
317  // an edge with the name was found,
318  // check whether the position lies within it
319  else {
320  seen += edge->getLength();
321  if (seen >= pos) {
322  return edge;
323  }
324  }
325  }
326  return 0;
327 }
328 
329 
330 void
332  extract(dc, edge);
333  delete edge;
334 }
335 
336 
337 void
338 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
339  if (remember) {
340  myExtractedEdges[edge->getID()] = edge;
341  }
342  myEdges.erase(edge->getID());
343  edge->myFrom->removeEdge(edge);
344  edge->myTo->removeEdge(edge);
345  dc.removeFromSinksAndSources(edge);
346 }
347 
348 
349 void
350 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
351  if (myEdges.count(newID) != 0) {
352  throw ProcessError("Attempt to rename edge using existing id '" + newID + "'");
353  }
354  myEdges.erase(edge->getID());
355  edge->setID(newID);
356  myEdges[newID] = edge;
357 }
358 
359 
360 // ----- explicit edge manipulation methods
361 bool
363  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
364  (unsigned int) edge->myLanes.size(), (unsigned int) edge->myLanes.size());
365 }
366 
367 
368 bool
370  const std::string& firstEdgeName,
371  const std::string& secondEdgeName,
372  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
373  SUMOReal pos;
374  pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
375  if (pos <= 0) {
377  edge->myFrom->getPosition(), edge->myTo->getPosition(),
378  node->getPosition());
379  }
380  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
381  return false;
382  }
383  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
384  noLanesFirstEdge, noLanesSecondEdge);
385 }
386 
387 
388 bool
390  NBEdge* edge, SUMOReal pos, NBNode* node,
391  const std::string& firstEdgeName,
392  const std::string& secondEdgeName,
393  unsigned int noLanesFirstEdge, unsigned int noLanesSecondEdge) {
394  // build the new edges' geometries
395  std::pair<PositionVector, PositionVector> geoms =
396  edge->getGeometry().splitAt(pos);
397  if (geoms.first[-1] != node->getPosition()) {
398  geoms.first.pop_back();
399  geoms.first.push_back(node->getPosition());
400  }
401 
402  if (geoms.second[0] != node->getPosition()) {
403  geoms.second.pop_front();
404  geoms.second.push_front(node->getPosition());
405  }
406  // build and insert the edges
407  NBEdge* one = new NBEdge(firstEdgeName,
408  edge->myFrom, node, edge->myType, edge->mySpeed, noLanesFirstEdge,
409  edge->getPriority(), edge->myLaneWidth, 0, geoms.first,
410  edge->getStreetName(), edge->myLaneSpreadFunction, true);
411  for (unsigned int i = 0; i < noLanesFirstEdge && i < edge->getNumLanes(); i++) {
412  one->setSpeed(i, edge->getLaneSpeed(i));
413  }
414  NBEdge* two = new NBEdge(secondEdgeName,
415  node, edge->myTo, edge->myType, edge->mySpeed, noLanesSecondEdge,
416  edge->getPriority(), edge->myLaneWidth, edge->myOffset, geoms.second,
417  edge->getStreetName(), edge->myLaneSpreadFunction, true);
418  for (unsigned int i = 0; i < noLanesSecondEdge && i < edge->getNumLanes(); i++) {
419  two->setSpeed(i, edge->getLaneSpeed(i));
420  }
421  two->copyConnectionsFrom(edge);
422  // replace information about this edge within the nodes
423  edge->myFrom->replaceOutgoing(edge, one, 0);
424  edge->myTo->replaceIncoming(edge, two, 0);
425  // the edge is now occuring twice in both nodes...
426  // clean up
427  edge->myFrom->removeDoubleEdges();
428  edge->myTo->removeDoubleEdges();
429  // add connections from the first to the second edge
430  // check special case:
431  // one in, one out, the outgoing has one lane more
432  if (noLanesFirstEdge == noLanesSecondEdge - 1) {
433  for (unsigned int i = 0; i < one->getNumLanes(); i++) {
434  if (!one->addLane2LaneConnection(i, two, i + 1, NBEdge::L2L_COMPUTED)) { // !!! Bresenham, here!!!
435  throw ProcessError("Could not set connection!");
436  }
437  }
439  } else {
440  for (unsigned int i = 0; i < one->getNumLanes() && i < two->getNumLanes(); i++) {
441  if (!one->addLane2LaneConnection(i, two, i, NBEdge::L2L_COMPUTED)) {// !!! Bresenham, here!!!
442  throw ProcessError("Could not set connection!");
443  }
444  }
445  }
447  if (find(myEdges2Keep.begin(), myEdges2Keep.end(), edge->getID()) != myEdges2Keep.end()) {
448  myEdges2Keep.insert(one->getID());
449  myEdges2Keep.insert(two->getID());
450  }
451  if (find(myEdges2Remove.begin(), myEdges2Remove.end(), edge->getID()) != myEdges2Remove.end()) {
452  myEdges2Remove.insert(one->getID());
453  myEdges2Remove.insert(two->getID());
454  }
455  }
456  // erase the splitted edge
457  erase(dc, edge);
458  insert(one, true);
459  insert(two, true);
460  myEdgesSplit++;
461  return true;
462 }
463 
464 
465 
466 // ----- container access methods
467 std::vector<std::string>
469  std::vector<std::string> ret;
470  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
471  ret.push_back((*i).first);
472  }
473  return ret;
474 }
475 
476 
477 // ----- Adapting the input
478 void
480  EdgeVector toRemove;
481  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
482  NBEdge* edge = (*i).second;
483  if (!myEdges2Keep.count(edge->getID())) {
484  edge->getFromNode()->removeEdge(edge);
485  edge->getToNode()->removeEdge(edge);
486  toRemove.push_back(edge);
487  }
488  }
489  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
490  erase(dc, *j);
491  }
492 }
493 
494 
495 void
497  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
498  if ((*i).second->getGeometry().size() < 3) {
499  continue;
500  }
501  (*i).second->splitGeometry(*this, nc);
502  }
503 }
504 
505 
506 void
508  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
509  (*i).second->reduceGeometry(minDist);
510  }
511 }
512 
513 
514 // ----- processing methods
515 void
517  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
518  (*i).second->clearControllingTLInformation();
519  }
520 }
521 
522 
523 void
525  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
526  (*i).second->sortOutgoingConnectionsByAngle();
527  }
528 }
529 
530 
531 void
532 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
533  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
534  (*i).second->computeEdge2Edges(noLeftMovers);
535  }
536 }
537 
538 
539 void
541  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
542  (*i).second->computeLanes2Edges();
543  }
544 }
545 
546 
547 void
549  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
550  (*i).second->recheckLanes();
551  }
552 }
553 
554 
555 void
556 NBEdgeCont::appendTurnarounds(bool noTLSControlled) {
557  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
558  (*i).second->appendTurnaround(noTLSControlled);
559  }
560 }
561 
562 
563 void
564 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
565  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
566  myEdges[*it]->appendTurnaround(noTLSControlled);
567  }
568 }
569 
570 
571 void
573  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
574  (*i).second->computeEdgeShape();
575  }
576 }
577 
578 
579 void
581  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
582  (*i).second->computeLaneShapes();
583  }
584 }
585 
586 
587 void
590  EdgeVector edges) {
591  // !!! Attention!
592  // No merging of the geometry to come is being done
593  // The connections are moved from one edge to another within
594  // the replacement where the edge is a node's incoming edge.
595 
596  // count the number of lanes, the speed and the id
597  unsigned int nolanes = 0;
598  SUMOReal speed = 0;
599  int priority = 0;
600  std::string id;
601  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
602  // retrieve the connected nodes
603  NBEdge* tpledge = *(edges.begin());
604  NBNode* from = tpledge->getFromNode();
605  NBNode* to = tpledge->getToNode();
606  EdgeVector::const_iterator i;
607  for (i = edges.begin(); i != edges.end(); i++) {
608  // some assertions
609  assert((*i)->getFromNode() == from);
610  assert((*i)->getToNode() == to);
611  // ad the number of lanes the current edge has
612  nolanes += (*i)->getNumLanes();
613  // build the id
614  if (i != edges.begin()) {
615  id += "+";
616  }
617  id += (*i)->getID();
618  // compute the speed
619  speed += (*i)->getSpeed();
620  // build the priority
621  priority = MAX2(priority, (*i)->getPriority());
622  }
623  speed /= edges.size();
624  // build the new edge
625  // @bug new edge does not know about allowed vclass of old edges
626  // @bug both the width and the offset are not regarded
627  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
629  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
630  insert(newEdge, true);
631  // replace old edge by current within the nodes
632  // and delete the old
633  from->replaceOutgoing(edges, newEdge);
634  to->replaceIncoming(edges, newEdge);
635  // patch connections
636  // add edge2edge-information
637  for (i = edges.begin(); i != edges.end(); i++) {
638  EdgeVector ev = (*i)->getConnectedEdges();
639  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
640  newEdge->addEdge2EdgeConnection(*j);
641  }
642  }
643  // move lane2lane-connections
644  unsigned int currLane = 0;
645  for (i = edges.begin(); i != edges.end(); i++) {
646  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
647  currLane += (*i)->getNumLanes();
648  }
649  // patch tl-information
650  currLane = 0;
651  for (i = edges.begin(); i != edges.end(); i++) {
652  unsigned int noLanes = (*i)->getNumLanes();
653  for (unsigned int j = 0; j < noLanes; j++, currLane++) {
654  // replace in traffic lights
655  tlc.replaceRemoved(*i, j, newEdge, currLane);
656  }
657  }
658  // delete joined edges
659  for (i = edges.begin(); i != edges.end(); i++) {
660  erase(dc, *i);
661  }
662 }
663 
664 
665 void
667  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
668  std::string oppositeID;
669  if ((*i).first[0] == '-') {
670  oppositeID = (*i).first.substr(1);
671  } else {
672  oppositeID = "-" + (*i).first;
673  }
674  if (myEdges.find(oppositeID) != myEdges.end()) {
675  (*i).second->setLaneSpreadFunction(LANESPREAD_RIGHT);
676  myEdges.find(oppositeID)->second->setLaneSpreadFunction(LANESPREAD_RIGHT);
677  } else {
678  (*i).second->setLaneSpreadFunction(LANESPREAD_CENTER);
679  }
680  }
681 }
682 
683 
684 
685 // ----- other
686 void
687 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass) {
688  myConnections.push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass));
689 }
690 
691 
692 void
694  for (std::vector<PostProcessConnection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
695  NBEdge* from = retrieve((*i).from);
696  NBEdge* to = retrieve((*i).to);
697  if (from != 0 && to != 0) {
698  if (!from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::L2L_USER, false, (*i).mayDefinitelyPass)) {
699  WRITE_WARNING("Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.");
700  }
701  }
702  }
703  // during loading we also kept some ambiguous connections in hope they might be valid after processing
704  // we need to make sure that all invalid connections are removed now
705  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
706  NBEdge* edge = it->second;
707  NBNode* to = edge->getToNode();
708  // make a copy because we may delete connections
709  std::vector<NBEdge::Connection> connections = edge->getConnections();
710  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
711  NBEdge::Connection& c = *it_con;
712  if (c.toEdge != 0 && c.toEdge->getFromNode() != to) {
713  WRITE_WARNING("Found and removed invalid connection from " + edge->getID() +
714  " to " + c.toEdge->getID() + " via " + to->getID());
715  edge->removeFromConnections(c.toEdge);
716  }
717  }
718  }
719 }
720 
721 
723 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
724  size_t len = id.length();
725  EdgeVector ret;
726  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
727  std::string curr = (*i).first;
728  // the next check makes it possibly faster - we don not have
729  // to compare the names
730  if (curr.length() <= len) {
731  continue;
732  }
733  // the name must be the same as the given id but something
734  // beginning with a '[' must be appended to it
735  if (curr.substr(0, len) == id && curr[len] == '[') {
736  ret.push_back((*i).second);
737  continue;
738  }
739  // ok, maybe the edge is a compound made during joining of edges
740  size_t pos = curr.find(id);
741  // surely not
742  if (pos == std::string::npos) {
743  continue;
744  }
745  // check leading char
746  if (pos > 0) {
747  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
748  // actually, this is another id
749  continue;
750  }
751  }
752  if (pos + id.length() < curr.length()) {
753  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
754  // actually, this is another id
755  continue;
756  }
757  }
758  ret.push_back((*i).second);
759  }
760  return ret;
761 }
762 
763 
764 void
765 NBEdgeCont::guessRoundabouts(std::vector<EdgeVector>& marked) {
766  // step 1: keep only those edges which have no turnarounds
767  std::set<NBEdge*> candidates;
768  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
769  NBEdge* e = (*i).second;
770  NBNode* const to = e->getToNode();
771  if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) {
772  candidates.insert(e);
773  }
774  }
775 
776  // step 2:
777  std::set<NBEdge*> visited;
778  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
779  EdgeVector loopEdges;
780  // start with a random edge (this doesn't have to be a roundabout edge)
781  // loop over connected edges (using always the leftmost one)
782  // and keep the list in loopEdges
783  // continue until we loop back onto a loopEdges and extract the loop
784  NBEdge* e = (*i);
785  if (visited.count(e) > 0) {
786  // already seen
787  continue;
788  }
789  loopEdges.push_back(e);
790  bool doLoop = true;
791  do {
792  visited.insert(e);
793  const EdgeVector& edges = e->getToNode()->getEdges();
794  if (edges.size() < 2) {
795  doLoop = false;
796  break;
797  }
798  if (e->getTurnDestination() != 0 || e->getToNode()->getConnectionTo(e->getFromNode()) != 0) {
799  // do not follow turn-arounds while in a (tentative) loop
800  doLoop = false;
801  break;
802  }
803  EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e);
804  NBContHelper::nextCW(edges, me);
805  NBEdge* left = *me;
806  SUMOReal angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
807  if (angle >= 90) {
808  // roundabouts do not have sharp turns (or they wouldn't be called 'round')
809  doLoop = false;
810  break;
811  }
812  EdgeVector::const_iterator loopClosed = find(loopEdges.begin(), loopEdges.end(), left);
813  const size_t loopSize = loopEdges.end() - loopClosed;
814  if (loopSize > 0) {
815  // loop found
816  if (loopSize < 3) {
817  doLoop = false; // need at least 3 edges for a roundabout
818  } else if (loopSize < loopEdges.size()) {
819  // remove initial edges not belonging to the loop
820  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
821  }
822  // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
823  int attachments = 0;
824  for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
825  if ((*j)->getToNode()->getEdges().size() > 2) {
826  attachments++;
827  }
828  }
829  if (attachments < 3) {
830  doLoop = false;
831  }
832  break;
833  }
834  if (visited.count(left) > 0) {
835  doLoop = false;
836  } else {
837  // keep going
838  loopEdges.push_back(left);
839  e = left;
840  }
841  } while (doLoop);
842  // mark collected edges in the case a loop (roundabout) was found
843  if (doLoop) {
844  std::set<NBEdge*> loopEdgesSet(loopEdges.begin(), loopEdges.end());
845  for (std::set<NBEdge*>::const_iterator j = loopEdgesSet.begin(); j != loopEdgesSet.end(); ++j) {
846  // disable turnarounds on incoming edges
847  NBNode* node = (*j)->getToNode();
848  const EdgeVector& incoming = node->getIncomingEdges();
849  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
850  NBEdge* inEdge = *k;
851  if (loopEdgesSet.count(inEdge) > 0) {
852  continue;
853  }
854  if ((inEdge)->getStep() >= NBEdge::LANES2LANES_USER) {
855  continue;
856  }
857  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
858  }
859  // let the connections to succeeding roundabout edge have a higher priority
860  (*j)->setJunctionPriority(node, 1000);
861  }
862  marked.push_back(loopEdges);
863  }
864  }
865 }
866 
867 
868 void
870  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
871  NBEdge* e = i->second;
872  // is this a "real" junction?
873  // XXX nyi
874  //continue
875  const SUMOReal offset = e->getLength() - 3;
876  switch (e->getToNode()->getType()) {
878  // yield or major?
879  if (e->getJunctionPriority(e->getToNode()) > 0) {
881  } else {
883  }
884  break;
887  break;
888  default:
889  break;
890  }
891  }
892 }
893 
894 /****************************************************************************/