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