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