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"
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;
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->myWidth, 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->myWidth, 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 // ----- processing methods
507 void
509  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
510  (*i).second->clearControllingTLInformation();
511  }
512 }
513 
514 
515 void
517  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
518  (*i).second->sortOutgoingConnectionsByAngle();
519  }
520 }
521 
522 
523 void
524 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
525  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
526  (*i).second->computeEdge2Edges(noLeftMovers);
527  }
528 }
529 
530 
531 void
533  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
534  (*i).second->computeLanes2Edges();
535  }
536 }
537 
538 
539 void
541  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
542  (*i).second->recheckLanes();
543  }
544 }
545 
546 
547 void
548 NBEdgeCont::appendTurnarounds(bool noTLSControlled) {
549  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
550  (*i).second->appendTurnaround(noTLSControlled);
551  }
552 }
553 
554 
555 void
556 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
557  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
558  myEdges[*it]->appendTurnaround(noTLSControlled);
559  }
560 }
561 
562 
563 void
565  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
566  (*i).second->computeEdgeShape();
567  }
568 }
569 
570 
571 void
573  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
574  (*i).second->computeLaneShapes();
575  }
576 }
577 
578 
579 void
582  EdgeVector edges) {
583  // !!! Attention!
584  // No merging of the geometry to come is being done
585  // The connections are moved from one edge to another within
586  // the replacement where the edge is a node's incoming edge.
587 
588  // count the number of lanes, the speed and the id
589  unsigned int nolanes = 0;
590  SUMOReal speed = 0;
591  int priority = 0;
592  std::string id;
593  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
594  // retrieve the connected nodes
595  NBEdge* tpledge = *(edges.begin());
596  NBNode* from = tpledge->getFromNode();
597  NBNode* to = tpledge->getToNode();
598  EdgeVector::const_iterator i;
599  for (i = edges.begin(); i != edges.end(); i++) {
600  // some assertions
601  assert((*i)->getFromNode() == from);
602  assert((*i)->getToNode() == to);
603  // ad the number of lanes the current edge has
604  nolanes += (*i)->getNumLanes();
605  // build the id
606  if (i != edges.begin()) {
607  id += "+";
608  }
609  id += (*i)->getID();
610  // compute the speed
611  speed += (*i)->getSpeed();
612  // build the priority
613  priority = MAX2(priority, (*i)->getPriority());
614  }
615  speed /= edges.size();
616  // build the new edge
617  // @bug new edge does not know about allowed vclass of old edges
618  // @bug both the width and the offset are not regarded
619  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
621  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
622  insert(newEdge, true);
623  // replace old edge by current within the nodes
624  // and delete the old
625  from->replaceOutgoing(edges, newEdge);
626  to->replaceIncoming(edges, newEdge);
627  // patch connections
628  // add edge2edge-information
629  for (i = edges.begin(); i != edges.end(); i++) {
630  EdgeVector ev = (*i)->getConnectedEdges();
631  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
632  newEdge->addEdge2EdgeConnection(*j);
633  }
634  }
635  // move lane2lane-connections
636  unsigned int currLane = 0;
637  for (i = edges.begin(); i != edges.end(); i++) {
638  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
639  currLane += (*i)->getNumLanes();
640  }
641  // patch tl-information
642  currLane = 0;
643  for (i = edges.begin(); i != edges.end(); i++) {
644  unsigned int noLanes = (*i)->getNumLanes();
645  for (unsigned int j = 0; j < noLanes; j++, currLane++) {
646  // replace in traffic lights
647  tlc.replaceRemoved(*i, j, newEdge, currLane);
648  }
649  }
650  // delete joined edges
651  for (i = edges.begin(); i != edges.end(); i++) {
652  erase(dc, *i);
653  }
654 }
655 
656 
657 void
659  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
660  std::string oppositeID;
661  if ((*i).first[0] == '-') {
662  oppositeID = (*i).first.substr(1);
663  } else {
664  oppositeID = "-" + (*i).first;
665  }
666  if (myEdges.find(oppositeID) != myEdges.end()) {
667  (*i).second->setLaneSpreadFunction(LANESPREAD_RIGHT);
668  myEdges.find(oppositeID)->second->setLaneSpreadFunction(LANESPREAD_RIGHT);
669  } else {
670  (*i).second->setLaneSpreadFunction(LANESPREAD_CENTER);
671  }
672  }
673 }
674 
675 
676 
677 // ----- other
678 void
679 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass) {
680  myConnections.push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass));
681 }
682 
683 
684 void
686  for (std::vector<PostProcessConnection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
687  NBEdge* from = retrieve((*i).from);
688  NBEdge* to = retrieve((*i).to);
689  if (from != 0 && to != 0) {
690  if (!from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::L2L_USER, false, (*i).mayDefinitelyPass)) {
691  WRITE_WARNING("Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.");
692  }
693  }
694  }
695  // during loading we also kept some ambiguous connections in hope they might be valid after processing
696  // we need to make sure that all invalid connections are removed now
697  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
698  NBEdge* edge = it->second;
699  NBNode* to = edge->getToNode();
700  // make a copy because we may delete connections
701  std::vector<NBEdge::Connection> connections = edge->getConnections();
702  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
703  NBEdge::Connection& c = *it_con;
704  if (c.toEdge != 0 && c.toEdge->getFromNode() != to) {
705  WRITE_WARNING("Found and removed invalid connection from " + edge->getID() +
706  " to " + c.toEdge->getID() + " via " + to->getID());
707  edge->removeFromConnections(c.toEdge);
708  }
709  }
710  }
711 }
712 
713 
715 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
716  size_t len = id.length();
717  EdgeVector ret;
718  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
719  std::string curr = (*i).first;
720  // the next check makes it possibly faster - we don not have
721  // to compare the names
722  if (curr.length() <= len) {
723  continue;
724  }
725  // the name must be the same as the given id but something
726  // beginning with a '[' must be appended to it
727  if (curr.substr(0, len) == id && curr[len] == '[') {
728  ret.push_back((*i).second);
729  continue;
730  }
731  // ok, maybe the edge is a compound made during joining of edges
732  size_t pos = curr.find(id);
733  // surely not
734  if (pos == std::string::npos) {
735  continue;
736  }
737  // check leading char
738  if (pos > 0) {
739  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
740  // actually, this is another id
741  continue;
742  }
743  }
744  if (pos + id.length() < curr.length()) {
745  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
746  // actually, this is another id
747  continue;
748  }
749  }
750  ret.push_back((*i).second);
751  }
752  return ret;
753 }
754 
755 
756 void
757 NBEdgeCont::guessRoundabouts(std::vector<std::set<NBEdge*> >& marked) {
758  // step 1: keep only those edges which have no turnarounds
759  std::set<NBEdge*> candidates;
760  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
761  NBEdge* e = (*i).second;
762  NBNode* const to = e->getToNode();
763  if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) {
764  candidates.insert(e);
765  }
766  }
767 
768  // step 2:
769  std::set<NBEdge*> visited;
770  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
771  EdgeVector loopEdges;
772  // start with a random edge (this doesn't have to be a roundabout edge)
773  // loop over connected edges (using always the leftmost one)
774  // and keep the list in loopEdges
775  // continue until we loop back onto a loopEdges and extract the loop
776  NBEdge* e = (*i);
777  if (visited.count(e) > 0) {
778  // already seen
779  continue;
780  }
781  loopEdges.push_back(e);
782  bool doLoop = true;
783  do {
784  visited.insert(e);
785  const EdgeVector& edges = e->getToNode()->getEdges();
786  if (edges.size() < 2) {
787  doLoop = false;
788  break;
789  }
790  EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e);
791  NBContHelper::nextCW(edges, me);
792  NBEdge* left = *me;
793  EdgeVector::const_iterator loopClosed = find(loopEdges.begin(), loopEdges.end(), left);
794  const size_t loopSize = loopEdges.end() - loopClosed;
795  if (loopSize > 0) {
796  // loop found
797  if (loopSize < 3) {
798  doLoop = false; // need at least 3 edges for a roundabout
799  } else if (loopSize < loopEdges.size()) {
800  // remove initial edges not belonging to the loop
801  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
802  }
803  break;
804  }
805  if (visited.count(left) > 0) {
806  doLoop = false;
807  } else {
808  // keep going
809  loopEdges.push_back(left);
810  e = left;
811  }
812  } while (doLoop);
813  // mark collected edges in the case a loop (roundabout) was found
814  if (doLoop) {
815  std::set<NBEdge*> loopEdgesSet(loopEdges.begin(), loopEdges.end());
816  for (std::set<NBEdge*>::const_iterator j = loopEdgesSet.begin(); j != loopEdgesSet.end(); ++j) {
817  // disable turnarounds on incoming edges
818  NBNode* node = (*j)->getToNode();
819  const EdgeVector& incoming = node->getIncomingEdges();
820  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
821  NBEdge* inEdge = *k;
822  if (loopEdgesSet.count(inEdge) > 0) {
823  continue;
824  }
825  if ((inEdge)->getStep() >= NBEdge::LANES2LANES_USER) {
826  continue;
827  }
828  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
829  }
830  // let the connections to succeeding roundabout edge have a higher priority
831  (*j)->setJunctionPriority(node, 1000);
832  }
833  marked.push_back(loopEdgesSet);
834  }
835  }
836 }
837 
838 
839 void
841  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
842  NBEdge* e = i->second;
843  // is this a "real" junction?
844  // XXX nyi
845  //continue
846  const SUMOReal offset = e->getLength() - 3;
847  switch (e->getToNode()->getType()) {
849  // yield or major?
850  if (e->getJunctionPriority(e->getToNode()) > 0) {
852  } else {
854  }
855  break;
858  break;
859  default:
860  break;
861  }
862  }
863 }
864 
865 /****************************************************************************/