SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBNodeCont.cpp
Go to the documentation of this file.
1 /****************************************************************************/
13 // Container for nodes during the netbuilding process
14 /****************************************************************************/
15 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
16 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
17 /****************************************************************************/
18 //
19 // This file is part of SUMO.
20 // SUMO is free software: you can redistribute it and/or modify
21 // it under the terms of the GNU General Public License as published by
22 // the Free Software Foundation, either version 3 of the License, or
23 // (at your option) any later version.
24 //
25 /****************************************************************************/
26 
27 
28 // ===========================================================================
29 // included modules
30 // ===========================================================================
31 #ifdef _MSC_VER
32 #include <windows_config.h>
33 #else
34 #include <config.h>
35 #endif
36 
37 #include <string>
38 #include <map>
39 #include <algorithm>
40 #include <cmath>
42 #include <utils/geom/Boundary.h>
43 #include <utils/geom/GeomHelper.h>
47 #include <utils/common/StdDefs.h>
48 #include <utils/common/ToString.h>
52 #include "NBDistrict.h"
53 #include "NBEdgeCont.h"
55 #include "NBJoinedEdgesMap.h"
56 #include "NBOwnTLDef.h"
57 #include "NBNodeCont.h"
58 
59 #ifdef CHECK_MEMORY_LEAKS
60 #include <foreign/nvwa/debug_new.h>
61 #endif // CHECK_MEMORY_LEAKS
62 
63 
64 // ===========================================================================
65 // method definitions
66 // ===========================================================================
68  : myInternalID(1) {}
69 
70 
72  clear();
73 }
74 
75 
76 // ----------- Insertion/removal/retrieval of nodes
77 bool
78 NBNodeCont::insert(const std::string& id, const Position& position,
79  NBDistrict* district) {
80  NodeCont::iterator i = myNodes.find(id);
81  if (i != myNodes.end()) {
82  return false;
83  }
84  NBNode* node = new NBNode(id, position, district);
85  myNodes[id] = node;
86  return true;
87 }
88 
89 
90 bool
91 NBNodeCont::insert(const std::string& id, const Position& position) {
92  NodeCont::iterator i = myNodes.find(id);
93  if (i != myNodes.end()) {
94  return false;
95  }
96  NBNode* node = new NBNode(id, position);
97  myNodes[id] = node;
98  return true;
99 }
100 
101 
102 Position
103 NBNodeCont::insert(const std::string& id) {
104  std::pair<SUMOReal, SUMOReal> ret(-1.0, -1.0);
105  NodeCont::iterator i = myNodes.find(id);
106  if (i != myNodes.end()) {
107  return (*i).second->getPosition();
108  } else {
109  NBNode* node = new NBNode(id, Position(-1.0, -1.0));
110  myNodes[id] = node;
111  }
112  return Position(-1, -1);
113 }
114 
115 
116 bool
118  std::string id = node->getID();
119  NodeCont::iterator i = myNodes.find(id);
120  if (i != myNodes.end()) {
121  return false;
122  }
123  myNodes[id] = node;
124  return true;
125 }
126 
127 
128 NBNode*
129 NBNodeCont::retrieve(const std::string& id) const {
130  NodeCont::const_iterator i = myNodes.find(id);
131  if (i == myNodes.end()) {
132  return 0;
133  }
134  return (*i).second;
135 }
136 
137 
138 NBNode*
139 NBNodeCont::retrieve(const Position& position, SUMOReal offset) const {
140  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
141  NBNode* node = (*i).second;
142  if (fabs(node->getPosition().x() - position.x()) < offset
143  &&
144  fabs(node->getPosition().y() - position.y()) < offset) {
145  return node;
146  }
147  }
148  return 0;
149 }
150 
151 
152 bool
154  if (extract(node)) {
155  delete node;
156  return true;
157  } else {
158  return false;
159  }
160 }
161 
162 
163 bool
164 NBNodeCont::extract(NBNode* node, bool remember) {
165  NodeCont::iterator i = myNodes.find(node->getID());
166  if (i == myNodes.end()) {
167  return false;
168  }
169  myNodes.erase(i);
170  node->removeTrafficLights();
171  if (remember) {
172  myExtractedNodes.insert(node);
173  }
174  return true;
175 }
176 
177 
178 // ----------- Adapting the input
179 void
181  unsigned int no = 0;
182  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
183  no += (*i).second->removeSelfLoops(dc, ec, tc);
184  }
185  if (no != 0) {
186  WRITE_WARNING(toString(no) + " self-looping edge(s) removed.");
187  }
188 }
189 
190 
191 void
193  // magic values
194  SUMOReal distanceThreshold = 7; // don't merge edges further apart
195  SUMOReal lengthThreshold = 0.05; // don't merge edges with higher relative length-difference
196 
197  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
198  // count the edges to other nodes outgoing from the current node
199  std::map<NBNode*, EdgeVector> connectionCount;
200  const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
201  for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) {
202  NBEdge* e = (*j);
203  NBNode* connected = e->getToNode();
204  if (connectionCount.find(connected) == connectionCount.end()) {
205  connectionCount[connected] = EdgeVector();
206  }
207  connectionCount[connected].push_back(e);
208  }
209  // check whether more than a single edge connect another node and join them
210  std::map<NBNode*, EdgeVector>::iterator k;
211  for (k = connectionCount.begin(); k != connectionCount.end(); k++) {
212  // possibly we do not have anything to join...
213  if ((*k).second.size() < 2) {
214  continue;
215  }
216  // for the edges that seem to be a single street,
217  // check whether the geometry is similar
218  const EdgeVector& ev = (*k).second;
219  const NBEdge* const first = ev.front();
220  EdgeVector::const_iterator jci; // join candidate iterator
221  for (jci = ev.begin() + 1; jci != ev.end(); ++jci) {
222  const SUMOReal relativeLengthDifference = fabs(first->getLoadedLength() - (*jci)->getLoadedLength()) / first->getLoadedLength();
223  if ((!first->isNearEnough2BeJoined2(*jci, distanceThreshold)) ||
224  (relativeLengthDifference > lengthThreshold) ||
225  (first->getSpeed() != (*jci)->getSpeed())
226  // @todo check vclass
227  ) {
228  break;
229  }
230  }
231  // @bug If there are 3 edges of which 2 can be joined, no joining will
232  // take place with the current implementation
233  if (jci == ev.end()) {
234  ec.joinSameNodeConnectingEdges(dc, tlc, ev);
235  }
236  }
237  }
238 }
239 
240 
241 void
243  UNUSED_PARAMETER(tc);
244  // Warn of isolated edges, i.e. a single edge with no connection to another edge
245  int edgeCounter = 0;
246  const std::vector<std::string> &edgeNames = ec.getAllNames();
247  for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
248  // Test whether this node starts at a dead end, i.e. it has only one adjacent node
249  // to which an edge exists and from which an edge may come.
250  NBEdge* e = ec.retrieve(*it);
251  if (e == 0) {
252  continue;
253  }
254  NBNode* from = e->getFromNode();
255  const EdgeVector& outgoingEdges = from->getOutgoingEdges();
256  if (outgoingEdges.size() != 1) {
257  // At this node, several edges or no edge start; so, this node is no dead end.
258  continue;
259  }
260  const EdgeVector& incomingEdges = from->getIncomingEdges();
261  if (incomingEdges.size() > 1) {
262  // At this node, several edges end; so, this node is no dead end.
263  continue;
264  } else if (incomingEdges.size() == 1) {
265  NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
266  NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
267  if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
268  // At this node, an edge ends which is not the inverse direction of
269  // the starting node.
270  continue;
271  }
272  }
273  // Now we know that the edge e starts a dead end.
274  // Next we test if the dead end is isolated, i.e. does not lead to a junction
275  bool hasJunction = false;
276  EdgeVector road;
277  NBEdge* eOld = 0;
278  NBNode* to;
279  std::set<NBNode*> adjacentNodes;
280  do {
281  road.push_back(e);
282  eOld = e;
283  from = e->getFromNode();
284  to = e->getToNode();
285  const EdgeVector& outgoingEdgesOfToNode = to->getOutgoingEdges();
286  const EdgeVector& incomingEdgesOfToNode = to->getIncomingEdges();
287  adjacentNodes.clear();
288  for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
289  if ((*itOfOutgoings)->getToNode() != from // The back path
290  && (*itOfOutgoings)->getToNode() != to // A loop / dummy edge
291  ) {
292  e = *itOfOutgoings; // Probably the next edge
293  }
294  adjacentNodes.insert((*itOfOutgoings)->getToNode());
295  }
296  for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) {
297  adjacentNodes.insert((*itOfIncomings)->getFromNode());
298  }
299  adjacentNodes.erase(to); // Omit loops
300  if (adjacentNodes.size() > 2) {
301  hasJunction = true;
302  }
303  } while (!hasJunction && eOld != e);
304  if (!hasJunction) {
305  edgeCounter += int(road.size());
306  std::string warningString = "Removed a road without junctions: ";
307  for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
308  if (roadIt == road.begin()) {
309  warningString += (*roadIt)->getID();
310  } else {
311  warningString += ", " + (*roadIt)->getID();
312  }
313 
314  NBNode* fromNode = (*roadIt)->getFromNode();
315  NBNode* toNode = (*roadIt)->getToNode();
316  ec.erase(dc, *roadIt);
317  if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) {
318  // Node is empty; can be removed
319  erase(fromNode);
320  }
321  if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) {
322  // Node is empty; can be removed
323  erase(toNode);
324  }
325  }
326  WRITE_WARNING(warningString);
327  }
328  }
329  if (edgeCounter > 0 && !OptionsCont::getOptions().getBool("remove-edges.isolated")) {
330  WRITE_WARNING("Detected isolated roads. Use the option --remove-edges.isolated to get a list of all affected edges.");
331  }
332 }
333 
334 
335 unsigned int
338  bool removeGeometryNodes) {
339  unsigned int no = 0;
340  std::vector<NBNode*> toRemove;
341  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
342  NBNode* current = (*i).second;
343  bool remove = false;
344  std::vector<std::pair<NBEdge*, NBEdge*> > toJoin;
345  // check for completely empty nodes
346  if (current->getOutgoingEdges().size() == 0 && current->getIncomingEdges().size() == 0) {
347  // remove if empty
348  remove = true;
349  }
350  // check for nodes which are only geometry nodes
351  if (removeGeometryNodes) {
352  if ((current->getOutgoingEdges().size() == 1 && current->getIncomingEdges().size() == 1)
353  ||
354  (current->getOutgoingEdges().size() == 2 && current->getIncomingEdges().size() == 2)) {
355  // ok, one in, one out or two in, two out
356  // -> ask the node whether to join
357  remove = current->checkIsRemovable();
358  if (remove) {
359  toJoin = current->getEdgesToJoin();
360  }
361  }
362  }
363  // remove the node and join the geometries when wished
364  if (!remove) {
365  continue;
366  }
367  for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j = toJoin.begin(); j != toJoin.end(); j++) {
368  NBEdge* begin = (*j).first;
369  NBEdge* continuation = (*j).second;
370  begin->append(continuation);
371  continuation->getToNode()->replaceIncoming(continuation, begin, 0);
372  tlc.replaceRemoved(continuation, -1, begin, -1);
373  je.appended(begin->getID(), continuation->getID());
374  ec.erase(dc, continuation);
375  }
376  toRemove.push_back(current);
377  no++;
378  }
379  // erase all
380  for (std::vector<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
381  erase(*j);
382  }
383  return no;
384 }
385 
386 
387 // ----------- (Helper) methods for joining nodes
388 void
390  std::set<NBNode*> visited;
391  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
392  std::vector<NBNode*> toProc;
393  if (visited.find((*i).second) != visited.end()) {
394  continue;
395  }
396  toProc.push_back((*i).second);
397  std::set<NBNode*> c;
398  while (!toProc.empty()) {
399  NBNode* n = toProc.back();
400  toProc.pop_back();
401  if (visited.find(n) != visited.end()) {
402  continue;
403  }
404  c.insert(n);
405  visited.insert(n);
406  const EdgeVector& edges = n->getEdges();
407  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
408  NBEdge* e = *j;
409  NBNode* s = 0;
410  if (n->hasIncoming(e)) {
411  s = e->getFromNode();
412  } else {
413  s = e->getToNode();
414  }
415  if (visited.find(s) != visited.end()) {
416  continue;
417  }
418  if (n->getPosition().distanceTo(s->getPosition()) < maxDist) {
419  toProc.push_back(s);
420  }
421  }
422  }
423  if (c.size() < 2) {
424  continue;
425  }
426  into.push_back(c);
427  }
428 }
429 
430 
431 void
432 NBNodeCont::addJoinExclusion(const std::vector<std::string> &ids, bool check) {
433  for (std::vector<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
434  // error handling has to take place here since joinExclusions could be
435  // loaded from multiple files / command line
436  if (myJoined.count(*it) > 0) {
437  WRITE_WARNING("Ignoring join exclusion for node '" + *it + "' since it already occured in a list of nodes to be joined");
438  } else if (check && retrieve(*it) == 0) {
439  WRITE_WARNING("Ignoring join exclusion for unknown node '" + *it + "'");
440  } else {
441  myJoinExclusions.insert(*it);
442  }
443  }
444 }
445 
446 
447 void
448 NBNodeCont::addCluster2Join(std::set<std::string> cluster) {
449  // error handling has to take place here since joins could be loaded from multiple files
450  for (std::set<std::string>::const_iterator it = cluster.begin(); it != cluster.end(); it++) {
451  if (myJoinExclusions.count(*it) > 0) {
452  WRITE_WARNING("Ignoring join-cluster because node '" + *it + "' was already excluded from joining");
453  return;
454  } else if (myJoined.count(*it) > 0) {
455  WRITE_WARNING("Ignoring join-cluster because node '" + *it + "' already occured in another join-cluster");
456  return;
457  } else {
458  myJoined.insert(*it);
459  }
460  }
461  myClusters2Join.push_back(cluster);
462 }
463 
464 
465 unsigned int
467  NodeClusters clusters;
468  for (std::vector<std::set<std::string> >::iterator it = myClusters2Join.begin(); it != myClusters2Join.end(); it++) {
469  // verify loaded cluster
470  std::set<NBNode*> cluster;
471  for (std::set<std::string>::iterator it_id = it->begin(); it_id != it->end(); it_id++) {
472  NBNode* node = retrieve(*it_id);
473  if (node == 0) {
474  WRITE_WARNING("Ignoring unknown node '" + *it_id + "' while joining");
475  } else {
476  cluster.insert(node);
477  }
478  }
479  if (cluster.size() > 1) {
480  clusters.push_back(cluster);
481  }
482  }
483  joinNodeClusters(clusters, dc, ec, tlc);
484  myClusters2Join.clear(); // make save for recompute
485  return (int)clusters.size();
486 }
487 
488 
489 unsigned int
491  NodeClusters cands;
492  NodeClusters clusters;
493  generateNodeClusters(maxdist, cands);
494  for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
495  std::set<NBNode*> cluster = (*i);
496  // remove join exclusions
497  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
498  std::set<NBNode*>::iterator check = j;
499  ++j;
500  if (myJoinExclusions.count((*check)->getID()) > 0) {
501  cluster.erase(check);
502  }
503  }
504  // iteratively remove the fringe
505  bool pruneFringe = true;
506  while(pruneFringe) {
507  pruneFringe = false;
508  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
509  std::set<NBNode*>::iterator check = j;
510  NBNode* n = *check;
511  ++j;
512  // remove nodes with degree <= 2 at fringe of the cluster (at least one edge leads to a non-cluster node)
513  if (
514  (n->getIncomingEdges().size() <= 1 && n->getOutgoingEdges().size() <= 1 ) &&
515  ((n->getIncomingEdges().size() == 0 ||
516  (n->getIncomingEdges().size() == 1) && cluster.count(n->getIncomingEdges()[0]->getFromNode()) == 0) ||
517  (n->getOutgoingEdges().size() == 0 ||
518  (n->getOutgoingEdges().size() == 1) && cluster.count(n->getOutgoingEdges()[0]->getToNode()) == 0))
519  ) {
520  cluster.erase(check);
521  pruneFringe = true; // other nodes could belong to the fringe now
522  }
523  }
524  }
525  if (cluster.size() > 1) {
526  clusters.push_back(cluster);
527  }
528  }
529  joinNodeClusters(clusters, dc, ec, tlc);
530  return (int)clusters.size();
531 }
532 
533 
534 void
537  for (NodeClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) {
538  std::set<NBNode*> cluster = *i;
539  assert(cluster.size() > 1);
540  Position pos;
541  bool setTL;
542  std::string id;
543  analyzeCluster(cluster, id, pos, setTL);
544  if (!insert(id, pos)) {
545  // should not fail
546  WRITE_WARNING("Could not join junctions " + id);
547  continue;
548  }
549  NBNode* newNode = retrieve(id);
550  if (setTL) {
551  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode);
552  if (!tlc.insert(tlDef)) {
553  // actually, nothing should fail here
554  delete tlDef;
555  throw ProcessError("Could not allocate tls '" + id + "'.");
556  }
557  }
558  // collect edges
559  std::set<NBEdge*> allEdges;
560  for (std::set<NBNode*>::const_iterator j=cluster.begin(); j!=cluster.end(); ++j) {
561  const std::vector<NBEdge*> &edges = (*j)->getEdges();
562  allEdges.insert(edges.begin(), edges.end());
563  }
564 
565  // remap and remove edges which are completely within the new intersection
566  for(std::set<NBEdge*>::iterator j=allEdges.begin(); j!=allEdges.end();) {
567  NBEdge *e = (*j);
568  NBNode *from = e->getFromNode();
569  NBNode *to = e->getToNode();
570  if(cluster.count(from) > 0 && cluster.count(to) > 0) {
571  for(std::set<NBEdge*>::iterator l=allEdges.begin(); l!=allEdges.end(); ++l) {
572  if(e != *l) {
573  (*l)->replaceInConnections(e, e->getConnections());
574  }
575  }
576  ec.erase(dc, e);
577  allEdges.erase(j++); // erase does not invalidate the other iterators
578  } else {
579  ++j;
580  }
581  }
582 
583  // remap edges which are incoming / outgoing
584  for(std::set<NBEdge*>::iterator j=allEdges.begin(); j!=allEdges.end(); ++j) {
585  NBEdge *e = (*j);
586  std::vector<NBEdge::Connection> conns = e->getConnections();
587  PositionVector g = e->getGeometry();
588  const bool outgoing = cluster.count(e->getFromNode()) > 0;
589  NBNode *from = outgoing ? newNode : e->getFromNode();
590  NBNode *to = outgoing ? e->getToNode() : newNode;
591  e->reinit(from, to, e->getTypeID(), e->getSpeed(),
592  e->getNumLanes(), e->getPriority(), e->getGeometry(),
593  e->getWidth(), e->getOffset(), e->getStreetName(), e->getLaneSpreadFunction());
594  e->setGeometry(g);
595  for(std::vector<NBEdge::Connection>::iterator k=conns.begin(); k!=conns.end(); ++k) {
596  e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass);
597  }
598  }
599  registerJoinedCluster(cluster);
600  }
601 }
602 
603 
604 void
605 NBNodeCont::registerJoinedCluster(const std::set<NBNode*>& cluster) {
606  std::set<std::string> ids;
607  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
608  ids.insert((*j)->getID());
609  }
610  myJoinedClusters.push_back(ids);
611 }
612 
613 
614 void
615 NBNodeCont::analyzeCluster(std::set<NBNode*> cluster, std::string& id, Position& pos, bool& hasTLS) {
616  id = "cluster";
617  hasTLS = false;
618  std::vector<std::string> member_ids;
619  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
620  member_ids.push_back((*j)->getID());
621  pos.add((*j)->getPosition());
622  // add a traffic light if any of the cluster members was controlled
623  if ((*j)->isTLControlled()) {
624  hasTLS = true;
625  }
626  }
627  pos.mul(1.0 / cluster.size());
628  // need to sort the member names to make the output deterministic
629  sort(member_ids.begin(), member_ids.end());
630  for (std::vector<std::string>::iterator j = member_ids.begin(); j != member_ids.end(); j++) {
631  id = id + "_" + (*j);
632  }
633 }
634 
635 
636 // ----------- (Helper) methods for guessing/computing traffic lights
637 bool
638 NBNodeCont::shouldBeTLSControlled(const std::set<NBNode*> &c) const {
639  unsigned int noIncoming = 0;
640  unsigned int noOutgoing = 0;
641  bool tooFast = false;
642  SUMOReal f = 0;
643  std::set<NBEdge*> seen;
644  for (std::set<NBNode*>::const_iterator j = c.begin(); j != c.end(); ++j) {
645  const EdgeVector& edges = (*j)->getEdges();
646  for (EdgeVector::const_iterator k = edges.begin(); k != edges.end(); ++k) {
647  if (c.find((*k)->getFromNode()) != c.end() && c.find((*k)->getToNode()) != c.end()) {
648  continue;
649  }
650  if ((*j)->hasIncoming(*k)) {
651  ++noIncoming;
652  f += (SUMOReal)(*k)->getNumLanes() * (*k)->getLaneSpeed(0);
653  } else {
654  ++noOutgoing;
655  }
656  if ((*k)->getLaneSpeed(0) * 3.6 > 79) {
657  tooFast = true;
658  }
659  }
660  }
661  return !tooFast && f >= 150. / 3.6 && c.size() != 0;
662 }
663 
664 
665 void
667  // build list of definitely not tls-controlled junctions
668  std::vector<NBNode*> ncontrolled;
669  if (oc.isSet("tls.unset")) {
670  std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset");
671  for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
672  NBNode* n = NBNodeCont::retrieve(*i);
673  if (n == 0) {
674  throw ProcessError(" The node '" + *i + "' to set as not-controlled is not known.");
675  }
676  std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS();
677  for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
678  (*j)->removeNode(n);
679  }
680  n->removeTrafficLights();
681  ncontrolled.push_back(n);
682  }
683  }
684 
685  // loop#1 checking whether the node shall be tls controlled,
686  // because it is assigned to a district
687  if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) {
688  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
689  NBNode* cur = (*i).second;
690  if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) {
691  setAsTLControlled(cur, tlc);
692  }
693  }
694  }
695 
696  // maybe no tls shall be guessed
697  if (!oc.getBool("tls.guess")) {
698  return;
699  }
700 
701  // guess joined tls first, if wished
702  if (oc.getBool("tls-guess.joining")) {
703  // get node clusters
704  SUMOReal MAXDIST = 25;
705  std::vector<std::set<NBNode*> > cands;
706  generateNodeClusters(MAXDIST, cands);
707  // check these candidates (clusters) whether they should be controlled by a tls
708  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end();) {
709  std::set<NBNode*> &c = (*i);
710  // regard only junctions which are not yet controlled and are not
711  // forbidden to be controlled
712  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) {
713  if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) {
714  c.erase(j++);
715  } else {
716  ++j;
717  }
718  }
719  // check whether the cluster should be controlled
720  if (!shouldBeTLSControlled(c)) {
721  i = cands.erase(i);
722  } else {
723  ++i;
724  }
725  }
726  // cands now only contain sets of junctions that shall be joined into being tls-controlled
727  unsigned int index = 0;
728  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) {
729  std::vector<NBNode*> nodes;
730  for (std::set<NBNode*>::iterator j = (*i).begin(); j != (*i).end(); j++) {
731  nodes.push_back(*j);
732  }
733  std::string id = "joinedG_" + toString(index++);
734  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes);
735  if (!tlc.insert(tlDef)) {
736  // actually, nothing should fail here
737  WRITE_WARNING("Could not build guessed, joined tls");
738  delete tlDef;
739  return;
740  }
741  }
742  }
743 
744  // guess tls
745  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
746  NBNode* cur = (*i).second;
747  // do nothing if already is tl-controlled
748  if (cur->isTLControlled()) {
749  continue;
750  }
751  // do nothing if in the list of explicit non-controlled junctions
752  if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) {
753  continue;
754  }
755  std::set<NBNode*> c;
756  c.insert(cur);
757  if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) {
758  continue;
759  }
760  setAsTLControlled((*i).second, tlc);
761  }
762 }
763 
764 
765 void
767  SUMOReal MAXDIST = 25;
768  std::vector<std::set<NBNode*> > cands;
769  generateNodeClusters(MAXDIST, cands);
770  unsigned int index = 0;
771  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) {
772  std::set<NBNode*> &c = (*i);
773  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) {
774  if (!(*j)->isTLControlled()) {
775  c.erase(j++);
776  } else {
777  ++j;
778  }
779  }
780  if (c.size() < 2) {
781  continue;
782  }
783  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); ++j) {
784  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
785  (*j)->removeTrafficLights();
786  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
787  tlc.removeFully((*j)->getID());
788  }
789  }
790  std::string id = "joinedS_" + toString(index++);
791  std::vector<NBNode*> nodes;
792  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); j++) {
793  nodes.push_back(*j);
794  }
795  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes);
796  if (!tlc.insert(tlDef)) {
797  // actually, nothing should fail here
798  WRITE_WARNING("Could not build a joined tls.");
799  delete tlDef;
800  return;
801  }
802  }
803 }
804 
805 
806 void
808  if (id == "") {
809  id = node->getID();
810  }
811  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node);
812  if (!tlc.insert(tlDef)) {
813  // actually, nothing should fail here
814  WRITE_WARNING("Building a tl-logic for node '" + id + "' twice is not possible.");
815  delete tlDef;
816  return;
817  }
818 }
819 
820 
821 // -----------
822 void
824  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
825  (*i).second->computeLanes2Lanes();
826  }
827 }
828 
829 
830 // computes the "wheel" of incoming and outgoing edges for every node
831 void
833  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
834  (*i).second->computeLogic(ec, oc);
835  }
836 }
837 
838 
839 void
841  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
842  delete((*i).second);
843  }
844  myNodes.clear();
845  for (std::set<NBNode*>::iterator i = myExtractedNodes.begin(); i != myExtractedNodes.end(); i++) {
846  delete(*i);
847  }
848  myExtractedNodes.clear();
849 }
850 
851 
852 std::string
854  // !!! not guaranteed to be free
855  std::string ret = "SUMOGenerated" + toString<int>(size());
856  assert(retrieve(ret) == 0);
857  return ret;
858 }
859 
860 
861 void
863  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
864  (*i).second->computeNodeShape(leftHand);
865  }
866 }
867 
868 
869 bool
871  if (cur->getIncomingEdges().size() == 2 && cur->getOutgoingEdges().size() == 1) {
872  // may be an on-ramp
873  NBEdge* pot_highway = cur->getIncomingEdges()[0];
874  NBEdge* pot_ramp = cur->getIncomingEdges()[1];
875  NBEdge* cont = cur->getOutgoingEdges()[0];
876 
877  // do not build ramps on connectors
878  if (pot_highway->isMacroscopicConnector() || pot_ramp->isMacroscopicConnector() || cont->isMacroscopicConnector()) {
879  return false;
880  }
881 
882  // check whether a lane is missing
883  if (pot_highway->getNumLanes() + pot_ramp->getNumLanes() <= cont->getNumLanes()) {
884  return false;
885  }
886 
887  // assign highway/ramp properly
888  if (pot_highway->getSpeed() < pot_ramp->getSpeed()) {
889  std::swap(pot_highway, pot_ramp);
890  } else if (pot_highway->getSpeed() == pot_ramp->getSpeed()
891  &&
892  pot_highway->getNumLanes() < pot_ramp->getNumLanes()) {
893 
894  std::swap(pot_highway, pot_ramp);
895  }
896 
897  // check conditions
898  // is it really a highway?
899  SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
900  if (pot_highway->getSpeed() < minHighwaySpeed || cont->getSpeed() < minHighwaySpeed) {
901  return false;
902  }
903  // is it really a ramp?
904  SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
905  if (maxRampSpeed > 0 && maxRampSpeed < pot_ramp->getSpeed()) {
906  return false;
907  }
908 
909  // ok, may be
910  return true;
911  }
912  return false;
913 }
914 
915 
916 bool
918  NBEdgeCont& ec, NBDistrictCont& dc,
919  EdgeVector& incremented) {
920  NBEdge* pot_highway = cur->getIncomingEdges()[0];
921  NBEdge* pot_ramp = cur->getIncomingEdges()[1];
922  NBEdge* cont = cur->getOutgoingEdges()[0];
923  bool bEdgeDeleted = false;
924 
925  // assign highway/ramp properly
926  if (pot_highway->getSpeed() < pot_ramp->getSpeed()) {
927  std::swap(pot_highway, pot_ramp);
928  } else if (pot_highway->getSpeed() == pot_ramp->getSpeed()
929  &&
930  pot_highway->getNumLanes() < pot_ramp->getNumLanes()) {
931 
932  std::swap(pot_highway, pot_ramp);
933  }
934 
935  // compute the number of lanes to append
936  int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - cont->getNumLanes();
937  if (toAdd <= 0) {
938  return false;
939  }
940 
941  //
942  if (cont->getGeometry().length() - POSITION_EPS <= oc.getFloat("ramps.ramp-length")) {
943  // the edge is shorter than the wished ramp
944  // append a lane only
945  if (find(incremented.begin(), incremented.end(), cont) == incremented.end()) {
946  cont->incLaneNo(toAdd);
947  incremented.push_back(cont);
948  if (!pot_highway->addLane2LaneConnections(0, cont, pot_ramp->getNumLanes(),
949  MIN2(cont->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true, true)) {
950  throw ProcessError("Could not set connection!");
951  }
952  if (!pot_ramp->addLane2LaneConnections(0, cont, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) {
953  throw ProcessError("Could not set connection!");
954  }
955  //
956  cont->invalidateConnections(true);
957  const EdgeVector& o1 = cont->getToNode()->getOutgoingEdges();
958  if (o1.size() == 1 && o1[0]->getNumLanes() < cont->getNumLanes()) {
959  cont->addLane2LaneConnections(cont->getNumLanes() - o1[0]->getNumLanes(),
960  o1[0], 0, o1[0]->getNumLanes(), NBEdge::L2L_VALIDATED);
961  }
962  //
963  if (cont->getLaneSpreadFunction() == LANESPREAD_CENTER) {
964  try {
965  PositionVector g = cont->getGeometry();
967  cont->setGeometry(g);
968  } catch (InvalidArgument&) {
969  WRITE_WARNING("For edge '" + cont->getID() + "': could not compute shape.");
970  }
971  }
972  }
973  PositionVector p = pot_ramp->getGeometry();
974  p.pop_back();
975  p.push_back(cont->getFromNode()->getPosition());
976  pot_ramp->setGeometry(p);
977  } else {
978  bEdgeDeleted = true;
979  // there is enough place to build a ramp; do it
980  NBNode* rn =
981  new NBNode(cont->getID() + "-AddedOnRampNode",
983  oc.getFloat("ramps.ramp-length")));
984  if (!insert(rn)) {
985  throw ProcessError("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!");
986  }
987  std::string name = cont->getID();
988  bool ok = ec.splitAt(dc, cont, rn,
989  cont->getID() + "-AddedOnRampEdge", cont->getID(),
990  cont->getNumLanes() + toAdd, cont->getNumLanes());
991  if (!ok) {
992  WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!");
993  return true;
994  } else {
995  NBEdge* added_ramp = ec.retrieve(name + "-AddedOnRampEdge");
996  NBEdge* added = ec.retrieve(name);
997  incremented.push_back(added_ramp);
998  if (added_ramp->getNumLanes() != added->getNumLanes()) {
999  int off = added_ramp->getNumLanes() - added->getNumLanes();
1000  if (!added_ramp->addLane2LaneConnections(off, added, 0, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
1001  throw ProcessError("Could not set connection!");
1002  }
1003  if (added_ramp->getLaneSpreadFunction() == LANESPREAD_CENTER) {
1004  try {
1005  PositionVector g = added_ramp->getGeometry();
1006  SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd - 1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd % 2);
1007  g.move2side(factor);
1008  added_ramp->setGeometry(g);
1009  } catch (InvalidArgument&) {
1010  WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape.");
1011  }
1012  }
1013  } else {
1014  if (!added_ramp->addLane2LaneConnections(0, added, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
1015  throw ProcessError("Could not set connection!");
1016  }
1017  }
1018  if (!pot_highway->addLane2LaneConnections(0, added_ramp, pot_ramp->getNumLanes(),
1019  MIN2(added_ramp->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, false, true)) {
1020  throw ProcessError("Could not set connection!");
1021 
1022  }
1023  if (!pot_ramp->addLane2LaneConnections(0, added_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) {
1024  throw ProcessError("Could not set connection!");
1025  }
1026  PositionVector p = pot_ramp->getGeometry();
1027  p.pop_back();
1028  p.push_back(added_ramp->getFromNode()->getPosition());//added_ramp->getLaneShape(0).at(0));
1029  pot_ramp->setGeometry(p);
1030  }
1031  }
1032  return bEdgeDeleted;
1033 }
1034 
1035 
1036 void
1038  NBEdgeCont& ec, NBDistrictCont& dc,
1039  EdgeVector& incremented) {
1040  NBEdge* pot_highway = cur->getOutgoingEdges()[0];
1041  NBEdge* pot_ramp = cur->getOutgoingEdges()[1];
1042  NBEdge* prev = cur->getIncomingEdges()[0];
1043  // assign highway/ramp properly
1044  if (pot_highway->getSpeed() < pot_ramp->getSpeed()) {
1045  std::swap(pot_highway, pot_ramp);
1046  } else if (pot_highway->getSpeed() == pot_ramp->getSpeed()
1047  &&
1048  pot_highway->getNumLanes() < pot_ramp->getNumLanes()) {
1049 
1050  std::swap(pot_highway, pot_ramp);
1051  }
1052  // compute the number of lanes to append
1053  int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - prev->getNumLanes();
1054  if (toAdd <= 0) {
1055  return;
1056  }
1057  // append on-ramp
1058  if (prev->getGeometry().length() - POSITION_EPS <= oc.getFloat("ramps.ramp-length")) {
1059  // the edge is shorter than the wished ramp
1060  // append a lane only
1061  if (find(incremented.begin(), incremented.end(), prev) == incremented.end()) {
1062  incremented.push_back(prev);
1063  prev->incLaneNo(toAdd);
1064  prev->invalidateConnections(true);
1065  if (!prev->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0,
1066  MIN2(prev->getNumLanes() - 1, pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) {
1067 
1068  throw ProcessError("Could not set connection!");
1069 
1070  }
1071  if (!prev->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) {
1072  throw ProcessError("Could not set connection!");
1073 
1074  }
1075  if (prev->getLaneSpreadFunction() == LANESPREAD_CENTER) {
1076  try {
1077  PositionVector g = prev->getGeometry();
1079  prev->setGeometry(g);
1080  } catch (InvalidArgument&) {
1081  WRITE_WARNING("For edge '" + prev->getID() + "': could not compute shape.");
1082  }
1083  }
1084  }
1085  PositionVector p = pot_ramp->getGeometry();
1086  p.pop_front();
1087  p.push_front(prev->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1));
1088  pot_ramp->setGeometry(p);
1089  } else {
1090  Position pos =
1092  prev->getGeometry().length() - oc.getFloat("ramps.ramp-length"));
1093  NBNode* rn = new NBNode(prev->getID() + "-AddedOffRampNode", pos);
1094  if (!insert(rn)) {
1095  throw ProcessError("Ups - could not build off-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!");
1096 
1097  }
1098  std::string name = prev->getID();
1099  bool ok = ec.splitAt(dc, prev, rn,
1100  prev->getID(), prev->getID() + "-AddedOffRampEdge",
1101  prev->getNumLanes(), prev->getNumLanes() + toAdd);
1102  if (!ok) {
1103  WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!");
1104  return;
1105  } else {
1106  NBEdge* added_ramp = ec.retrieve(name + "-AddedOffRampEdge");
1107  NBEdge* added = ec.retrieve(name);
1108  if (added_ramp->getNumLanes() != added->getNumLanes()) {
1109  incremented.push_back(added_ramp);
1110  int off = added_ramp->getNumLanes() - added->getNumLanes();
1111  if (!added->addLane2LaneConnections(0, added_ramp, off, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
1112  throw ProcessError("Could not set connection!");
1113 
1114  }
1115  if (added_ramp->getLaneSpreadFunction() == LANESPREAD_CENTER) {
1116  try {
1117  PositionVector g = added_ramp->getGeometry();
1118  SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd - 1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd % 2);
1119  g.move2side(factor);
1120  added_ramp->setGeometry(g);
1121  } catch (InvalidArgument&) {
1122  WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape.");
1123  }
1124  }
1125  } else {
1126  if (!added->addLane2LaneConnections(0, added_ramp, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
1127  throw ProcessError("Could not set connection!");
1128  }
1129  }
1130  if (!added_ramp->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0,
1131  MIN2(added_ramp->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) {
1132  throw ProcessError("Could not set connection!");
1133  }
1134  if (!added_ramp->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) {
1135  throw ProcessError("Could not set connection!");
1136 
1137  }
1138  PositionVector p = pot_ramp->getGeometry();
1139  p.pop_front();
1140  p.push_front(added_ramp->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1));
1141  pot_ramp->setGeometry(p);
1142  }
1143  }
1144 }
1145 
1146 
1147 bool
1149  if (cur->getIncomingEdges().size() == 1 && cur->getOutgoingEdges().size() == 2) {
1150  // may be an off-ramp
1151  NBEdge* pot_highway = cur->getOutgoingEdges()[0];
1152  NBEdge* pot_ramp = cur->getOutgoingEdges()[1];
1153  NBEdge* prev = cur->getIncomingEdges()[0];
1154 
1155  // do not build ramps on connectors
1156  if (pot_highway->isMacroscopicConnector() || pot_ramp->isMacroscopicConnector() || prev->isMacroscopicConnector()) {
1157  return false;
1158  }
1159 
1160  // check whether a lane is missing
1161  if (pot_highway->getNumLanes() + pot_ramp->getNumLanes() <= prev->getNumLanes()) {
1162  return false;
1163  }
1164 
1165  // assign highway/ramp properly
1166  if (pot_highway->getSpeed() < pot_ramp->getSpeed()) {
1167  std::swap(pot_highway, pot_ramp);
1168  } else if (pot_highway->getSpeed() == pot_ramp->getSpeed()
1169  &&
1170  pot_highway->getNumLanes() < pot_ramp->getNumLanes()) {
1171 
1172  std::swap(pot_highway, pot_ramp);
1173  }
1174 
1175  // check conditions
1176  // is it really a highway?
1177  SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
1178  if (pot_highway->getSpeed() < minHighwaySpeed || prev->getSpeed() < minHighwaySpeed) {
1179  return false;
1180  }
1181  // is it really a ramp?
1182  SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
1183  if (maxRampSpeed > 0 && maxRampSpeed < pot_ramp->getSpeed()) {
1184  return false;
1185  }
1186 
1187  return true;
1188  }
1189  return false;
1190 }
1191 
1192 
1193 void
1195  if (pot_highway->getSpeed() < pot_ramp->getSpeed()) {
1196  std::swap(pot_highway, pot_ramp);
1197  } else if (pot_highway->getSpeed() == pot_ramp->getSpeed()
1198  &&
1199  pot_highway->getNumLanes() < pot_ramp->getNumLanes()) {
1200 
1201  std::swap(pot_highway, pot_ramp);
1202  }
1203 }
1204 
1205 
1206 void
1208  NBDistrictCont& dc) {
1209  EdgeVector incremented;
1210  bool bEdgeDeleted = false;
1211  // check whether on-off ramps shall be guessed
1212  if (oc.getBool("ramps.guess")) {
1213  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1214  NBNode* cur = (*i).second;
1215  if (mayNeedOnRamp(oc, cur)) {
1216  buildOnRamp(oc, cur, ec, dc, incremented);
1217  }
1218  if (mayNeedOffRamp(oc, cur)) {
1219  buildOffRamp(oc, cur, ec, dc, incremented);
1220  }
1221  }
1222  }
1223  // check whether on-off ramps shall be guessed
1224  if (oc.isSet("ramps.set")) {
1225  std::vector<std::string> edges = oc.getStringVector("ramps.set");
1226  for (std::vector<std::string>::iterator i = edges.begin(); i != edges.end(); ++i) {
1227  NBEdge* e = ec.retrieve(*i);
1228  if (e == 0) {
1229  WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known.");
1230  continue;
1231  }
1232  NBNode* from = e->getFromNode();
1233  if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) {
1234  bEdgeDeleted = buildOnRamp(oc, from, ec, dc, incremented);
1235  }
1236  // load edge again to check offramps
1237  e = ec.retrieve(*i);
1238  if (e == 0) {
1239  WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known.");
1240  continue;
1241  }
1242  NBNode* to = e->getToNode();
1243  if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) {
1244  buildOffRamp(oc, to, ec, dc, incremented);
1245  }
1246  }
1247  }
1248 }
1249 
1250 
1251 void
1253  int numUnregulatedJunctions = 0;
1254  int numDeadEndJunctions = 0;
1255  int numPriorityJunctions = 0;
1256  int numRightBeforeLeftJunctions = 0;
1257  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1258  switch ((*i).second->getType()) {
1259  case NODETYPE_NOJUNCTION:
1260  ++numUnregulatedJunctions;
1261  break;
1262  case NODETYPE_DEAD_END:
1263  ++numDeadEndJunctions;
1264  break;
1267  ++numPriorityJunctions;
1268  break;
1270  ++numRightBeforeLeftJunctions;
1271  break;
1272  case NODETYPE_DISTRICT:
1273  ++numRightBeforeLeftJunctions;
1274  break;
1275  case NODETYPE_UNKNOWN:
1276  break;
1277  default:
1278  break;
1279  }
1280  }
1281  WRITE_MESSAGE(" Node type statistics:");
1282  WRITE_MESSAGE(" Unregulated junctions : " + toString(numUnregulatedJunctions));
1283  if (numDeadEndJunctions > 0) {
1284  WRITE_MESSAGE(" Dead-end junctions : " + toString(numDeadEndJunctions));
1285  }
1286  WRITE_MESSAGE(" Priority junctions : " + toString(numPriorityJunctions));
1287  WRITE_MESSAGE(" Right-before-left junctions : " + toString(numRightBeforeLeftJunctions));
1288 }
1289 
1290 
1291 std::vector<std::string>
1293  std::vector<std::string> ret;
1294  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1295  ret.push_back((*i).first);
1296  }
1297  return ret;
1298 }
1299 
1300 
1301 void
1302 NBNodeCont::rename(NBNode* node, const std::string& newID) {
1303  if (myNodes.count(newID) != 0) {
1304  throw ProcessError("Attempt to rename node using existing id '" + newID + "'");
1305  }
1306  myNodes.erase(node->getID());
1307  node->setID(newID);
1308  myNodes[newID] = node;
1309 }
1310 
1311 
1312 /****************************************************************************/
1313