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