SUMO - Simulation of Urban MObility
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.dlr.de/
16 // Copyright (C) 2001-2017 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>
54 #include "NBHelpers.h"
55 #include "NBDistrict.h"
56 #include "NBEdgeCont.h"
58 #include "NBOwnTLDef.h"
59 #include "NBNodeCont.h"
60 
61 
62 // ===========================================================================
63 // method definitions
64 // ===========================================================================
66  : myInternalID(1) {
67 }
68 
69 
71  clear();
72 }
73 
74 
75 // ----------- Insertion/removal/retrieval of nodes
76 bool
77 NBNodeCont::insert(const std::string& id, const Position& position,
78  NBDistrict* district) {
79  NodeCont::iterator i = myNodes.find(id);
80  if (i != myNodes.end()) {
81  return false;
82  }
83  NBNode* node = new NBNode(id, position, district);
84  myNodes[id] = node;
85  const float pos[2] = {(float)position.x(), (float)position.y()};
86  myRTree.Insert(pos, pos, node);
87  return true;
88 }
89 
90 
91 bool
93  std::string id = node->getID();
94  NodeCont::iterator i = myNodes.find(id);
95  if (i != myNodes.end()) {
96  return false;
97  }
98  myNodes[id] = node;
99  const float pos[2] = {(float)node->getPosition().x(), (float)node->getPosition().y()};
100  myRTree.Insert(pos, pos, node);
101  return true;
102 }
103 
104 
105 NBNode*
106 NBNodeCont::retrieve(const std::string& id) const {
107  NodeCont::const_iterator i = myNodes.find(id);
108  if (i == myNodes.end()) {
109  return 0;
110  }
111  return (*i).second;
112 }
113 
114 
115 NBNode*
116 NBNodeCont::retrieve(const Position& position, const double offset) const {
117  const double extOffset = offset + POSITION_EPS;
118  const float cmin[2] = {(float)(position.x() - extOffset), (float)(position.y() - extOffset)};
119  const float cmax[2] = {(float)(position.x() + extOffset), (float)(position.y() + extOffset)};
120  std::set<std::string> into;
121  Named::StoringVisitor sv(into);
122  myRTree.Search(cmin, cmax, sv);
123  for (std::set<std::string>::const_iterator i = into.begin(); i != into.end(); i++) {
124  NBNode* const node = myNodes.find(*i)->second;
125  if (fabs(node->getPosition().x() - position.x()) <= offset
126  &&
127  fabs(node->getPosition().y() - position.y()) <= offset) {
128  return node;
129  }
130  }
131  return 0;
132 }
133 
134 
135 bool
137  if (extract(node)) {
138  delete node;
139  return true;
140  } else {
141  return false;
142  }
143 }
144 
145 
146 bool
147 NBNodeCont::extract(NBNode* node, bool remember) {
148  NodeCont::iterator i = myNodes.find(node->getID());
149  if (i == myNodes.end()) {
150  return false;
151  }
152  myNodes.erase(i);
153  const float pos[2] = {(float)node->getPosition().x(), (float)node->getPosition().y()};
154  myRTree.Remove(pos, pos, node);
155  node->removeTrafficLights();
156  if (remember) {
157  myExtractedNodes.insert(node);
158  }
159  return true;
160 }
161 
162 
163 // ----------- Adapting the input
164 void
166  int no = 0;
167  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
168  no += (*i).second->removeSelfLoops(dc, ec, tc);
169  }
170  if (no != 0) {
171  WRITE_WARNING(toString(no) + " self-looping edge(s) removed.");
172  }
173 }
174 
175 
176 void
178  // magic values
179  const double distanceThreshold = 7.; // don't merge edges further apart
180  const double lengthThreshold = 0.10; // don't merge edges with higher relative length-difference
181 
182  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
183  // count the edges to other nodes outgoing from the current node
184  std::map<NBNode*, EdgeVector> connectionCount;
185  const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
186  for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) {
187  connectionCount[(*j)->getToNode()].push_back(*j);
188  }
189  // check whether more than a single edge connect another node and join them
190  std::map<NBNode*, EdgeVector>::iterator k;
191  for (k = connectionCount.begin(); k != connectionCount.end(); k++) {
192  // possibly we do not have anything to join...
193  if ((*k).second.size() < 2) {
194  continue;
195  }
196  // for the edges that seem to be a single street,
197  // check whether the geometry is similar
198  const EdgeVector& ev = (*k).second;
199  const NBEdge* const first = ev.front();
200  EdgeVector::const_iterator jci; // join candidate iterator
201  for (jci = ev.begin() + 1; jci != ev.end(); ++jci) {
202  const double relativeLengthDifference = fabs(first->getLoadedLength() - (*jci)->getLoadedLength()) / first->getLoadedLength();
203  if ((!first->isNearEnough2BeJoined2(*jci, distanceThreshold)) ||
204  (relativeLengthDifference > lengthThreshold) ||
205  (fabs(first->getSpeed() - (*jci)->getSpeed()) >= 0.01) || // output accuracy
206  (first->getPermissions() != (*jci)->getPermissions())
207  ) {
208  break;
209  }
210  }
211  // @bug If there are 3 edges of which 2 can be joined, no joining will
212  // take place with the current implementation
213  if (jci == ev.end()) {
214  ec.joinSameNodeConnectingEdges(dc, tlc, ev);
215  }
216  }
217  }
218 }
219 
220 
221 void
223  // Warn of isolated edges, i.e. a single edge with no connection to another edge
224  const std::vector<std::string>& edgeNames = ec.getAllNames();
225  for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
226  // Test whether this node starts at a dead end, i.e. it has only one adjacent node
227  // to which an edge exists and from which an edge may come.
228  NBEdge* e = ec.retrieve(*it);
229  if (e == 0) {
230  continue;
231  }
232  NBNode* from = e->getFromNode();
233  const EdgeVector& outgoingEdges = from->getOutgoingEdges();
234  if (outgoingEdges.size() != 1) {
235  // At this node, several edges or no edge start; so, this node is no dead end.
236  continue;
237  }
238  const EdgeVector& incomingEdges = from->getIncomingEdges();
239  if (incomingEdges.size() > 1) {
240  // At this node, several edges end; so, this node is no dead end.
241  continue;
242  } else if (incomingEdges.size() == 1) {
243  NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
244  NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
245  if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
246  // At this node, an edge ends which is not the inverse direction of
247  // the starting node.
248  continue;
249  }
250  }
251  // Now we know that the edge e starts a dead end.
252  // Next we test if the dead end is isolated, i.e. does not lead to a junction
253  bool hasJunction = false;
254  EdgeVector road;
255  NBEdge* eOld = 0;
256  NBNode* to;
257  std::set<NBNode*> adjacentNodes;
258  do {
259  road.push_back(e);
260  eOld = e;
261  from = e->getFromNode();
262  to = e->getToNode();
263  const EdgeVector& outgoingEdgesOfToNode = to->getOutgoingEdges();
264  const EdgeVector& incomingEdgesOfToNode = to->getIncomingEdges();
265  adjacentNodes.clear();
266  for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
267  if ((*itOfOutgoings)->getToNode() != from // The back path
268  && (*itOfOutgoings)->getToNode() != to // A loop / dummy edge
269  ) {
270  e = *itOfOutgoings; // Probably the next edge
271  }
272  adjacentNodes.insert((*itOfOutgoings)->getToNode());
273  }
274  for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) {
275  adjacentNodes.insert((*itOfIncomings)->getFromNode());
276  }
277  adjacentNodes.erase(to); // Omit loops
278  if (adjacentNodes.size() > 2) {
279  hasJunction = true;
280  }
281  } while (!hasJunction && eOld != e);
282  if (!hasJunction) {
283  std::string warningString = "Removed a road without junctions: ";
284  for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
285  if (roadIt == road.begin()) {
286  warningString += (*roadIt)->getID();
287  } else {
288  warningString += ", " + (*roadIt)->getID();
289  }
290 
291  NBNode* fromNode = (*roadIt)->getFromNode();
292  NBNode* toNode = (*roadIt)->getToNode();
293  ec.erase(dc, *roadIt);
294  if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) {
295  // Node is empty; can be removed
296  erase(fromNode);
297  }
298  if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) {
299  // Node is empty; can be removed
300  erase(toNode);
301  }
302  }
303  WRITE_WARNING(warningString);
304  }
305  }
306 }
307 
308 
309 void
311  std::vector<std::set<NBEdge*> > components;
312  std::set<NBEdge*> edgesLeft;
313  for (std::map<std::string, NBEdge*>::const_iterator edgeIt = ec.begin(); edgeIt != ec.end(); ++edgeIt) {
314  edgesLeft.insert(edgeIt->second);
315  }
316  EdgeVector queue;
317  std::set<NBEdge*> toRemove;
318  while (!edgesLeft.empty()) {
319  queue.push_back(*edgesLeft.begin());
320  std::set<NBEdge*> component;
321  while (!queue.empty()) {
322  NBEdge* const e = queue.back();
323  queue.pop_back();
324  component.insert(e);
325  std::vector<EdgeVector> edgeLists;
326  edgeLists.push_back(e->getFromNode()->getOutgoingEdges());
327  edgeLists.push_back(e->getFromNode()->getIncomingEdges());
328  edgeLists.push_back(e->getToNode()->getOutgoingEdges());
329  edgeLists.push_back(e->getToNode()->getIncomingEdges());
330  for (std::vector<EdgeVector>::const_iterator listIt = edgeLists.begin(); listIt != edgeLists.end(); ++listIt) {
331  for (EdgeVector::const_iterator edgeIt = listIt->begin(); edgeIt != listIt->end(); ++edgeIt) {
332  std::set<NBEdge*>::iterator leftIt = edgesLeft.find(*edgeIt);
333  if (leftIt != edgesLeft.end()) {
334  queue.push_back(*edgeIt);
335  edgesLeft.erase(leftIt);
336  }
337  }
338  }
339  }
340  std::vector<std::set<NBEdge*> >::iterator cIt;
341  for (cIt = components.begin(); cIt != components.end(); ++cIt) {
342  if (cIt->size() < component.size()) {
343  break;
344  }
345  }
346  components.insert(cIt, component);
347  if ((int)components.size() > numKeep) {
348  toRemove.insert(components.back().begin(), components.back().end());
349  components.pop_back();
350  }
351  }
352  for (std::set<NBEdge*>::iterator edgeIt = toRemove.begin(); edgeIt != toRemove.end(); ++edgeIt) {
353  NBNode* const fromNode = (*edgeIt)->getFromNode();
354  NBNode* const toNode = (*edgeIt)->getToNode();
355  ec.erase(dc, *edgeIt);
356  if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) {
357  erase(fromNode);
358  }
359  if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) {
360  erase(toNode);
361  }
362  }
363 }
364 
365 
366 int
369  bool removeGeometryNodes) {
370  // load edges that shall not be modified
371  std::set<std::string> edges2keep;
372  if (removeGeometryNodes) {
373  const OptionsCont& oc = OptionsCont::getOptions();
374  if (oc.isSet("geometry.remove.keep-edges.input-file")) {
375  NBHelpers::loadEdgesFromFile(oc.getString("geometry.remove.keep-edges.input-file"), edges2keep);
376  }
377  if (oc.isSet("geometry.remove.keep-edges.explicit")) {
378  const std::vector<std::string> edges = oc.getStringVector("geometry.remove.keep-edges.explicit");
379  edges2keep.insert(edges.begin(), edges.end());
380  }
381  }
382  int no = 0;
383  std::vector<NBNode*> toRemove;
384  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
385  NBNode* current = (*i).second;
386  bool remove = false;
387  std::vector<std::pair<NBEdge*, NBEdge*> > toJoin;
388  // check for completely empty nodes
389  if (current->getOutgoingEdges().size() == 0 && current->getIncomingEdges().size() == 0) {
390  // remove if empty
391  remove = true;
392  }
393  // check for nodes which are only geometry nodes
394  if (removeGeometryNodes && mySplit.count(current) == 0) {
395  if ((current->getOutgoingEdges().size() == 1 && current->getIncomingEdges().size() == 1)
396  ||
397  (current->getOutgoingEdges().size() == 2 && current->getIncomingEdges().size() == 2)) {
398  // ok, one in, one out or two in, two out
399  // -> ask the node whether to join
400  remove = current->checkIsRemovable();
401  // check whether any of the edges must be kept
402  for (EdgeVector::const_iterator it_edge = current->getEdges().begin(); it_edge != current->getEdges().end(); ++it_edge) {
403  if (edges2keep.find((*it_edge)->getID()) != edges2keep.end()) {
404  remove = false;
405  break;
406  }
407  }
408  if (remove) {
409  toJoin = current->getEdgesToJoin();
410  }
411  }
412  }
413  // remove the node and join the geometries when wished
414  if (!remove) {
415  continue;
416  }
417  for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j = toJoin.begin(); j != toJoin.end(); j++) {
418  NBEdge* begin = (*j).first;
419  NBEdge* continuation = (*j).second;
420  begin->append(continuation);
421  continuation->getToNode()->replaceIncoming(continuation, begin, 0);
422  tlc.replaceRemoved(continuation, -1, begin, -1);
423  ec.extract(dc, continuation, true);
424  }
425  toRemove.push_back(current);
426  no++;
427  }
428  // erase all
429  for (std::vector<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
430  extract(*j, true);
431  }
432  return no;
433 }
434 
435 
436 void
438  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
439  (*i).second->avoidOverlap();
440  }
441 }
442 
443 // ----------- (Helper) methods for joining nodes
444 void
445 NBNodeCont::generateNodeClusters(double maxDist, NodeClusters& into) const {
446  std::set<NBNode*> visited;
447  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
448  std::vector<NodeAndDist> toProc;
449  if (visited.find((*i).second) != visited.end()) {
450  continue;
451  }
452  toProc.push_back(std::make_pair((*i).second, 0));
453  std::set<NBNode*> c;
454  while (!toProc.empty()) {
455  NodeAndDist nodeAndDist = toProc.back();
456  NBNode* n = nodeAndDist.first;
457  double dist = nodeAndDist.second;
458  toProc.pop_back();
459  if (visited.find(n) != visited.end()) {
460  continue;
461  }
462  c.insert(n);
463  visited.insert(n);
464  const EdgeVector& edges = n->getEdges();
465  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
466  NBEdge* e = *j;
467  NBNode* s = 0;
468  if (e->getPermissions() == SVC_PEDESTRIAN) {
469  continue; // do not join pedestrian stuff
470  }
471  if (n->hasIncoming(e)) {
472  s = e->getFromNode();
473  } else {
474  s = e->getToNode();
475  }
476  if (visited.find(s) != visited.end()) {
477  continue;
478  }
479  if (e->getLoadedLength() + dist < maxDist) {
480  if (s->geometryLike()) {
481  toProc.push_back(std::make_pair(s, dist + e->getLoadedLength()));
482  } else {
483  toProc.push_back(std::make_pair(s, 0));
484  }
485  }
486  }
487  }
488  if (c.size() < 2) {
489  continue;
490  }
491  into.push_back(c);
492  }
493 }
494 
495 
496 void
497 NBNodeCont::addJoinExclusion(const std::vector<std::string>& ids, bool check) {
498  for (std::vector<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
499  // error handling has to take place here since joinExclusions could be
500  // loaded from multiple files / command line
501  if (myJoined.count(*it) > 0) {
502  WRITE_WARNING("Ignoring join exclusion for junction '" + *it + "' since it already occured in a list of nodes to be joined");
503  } else if (check && retrieve(*it) == 0) {
504  WRITE_WARNING("Ignoring join exclusion for unknown junction '" + *it + "'");
505  } else {
506  myJoinExclusions.insert(*it);
507  }
508  }
509 }
510 
511 
512 void
513 NBNodeCont::addCluster2Join(std::set<std::string> cluster) {
514  // error handling has to take place here since joins could be loaded from multiple files
515  for (std::set<std::string>::const_iterator it = cluster.begin(); it != cluster.end(); it++) {
516  if (myJoinExclusions.count(*it) > 0) {
517  WRITE_WARNING("Ignoring join-cluster because junction '" + *it + "' was already excluded from joining");
518  return;
519  } else if (myJoined.count(*it) > 0) {
520  WRITE_WARNING("Ignoring join-cluster because junction '" + *it + "' already occured in another join-cluster");
521  return;
522  } else {
523  myJoined.insert(*it);
524  }
525  }
526  myClusters2Join.push_back(cluster);
527 }
528 
529 
530 int
532  NodeClusters clusters;
533  for (std::vector<std::set<std::string> >::iterator it = myClusters2Join.begin(); it != myClusters2Join.end(); it++) {
534  // verify loaded cluster
535  std::set<NBNode*> cluster;
536  for (std::set<std::string>::iterator it_id = it->begin(); it_id != it->end(); it_id++) {
537  NBNode* node = retrieve(*it_id);
538  if (node == 0) {
539  WRITE_WARNING("Ignoring unknown junction '" + *it_id + "' while joining");
540  } else {
541  cluster.insert(node);
542  }
543  }
544  if (cluster.size() > 1) {
545  clusters.push_back(cluster);
546  }
547  }
548  joinNodeClusters(clusters, dc, ec, tlc);
549  myClusters2Join.clear(); // make save for recompute
550  return (int)clusters.size();
551 }
552 
553 
554 int
556  NodeClusters cands;
557  NodeClusters clusters;
558  generateNodeClusters(maxDist, cands);
559  for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
560  std::set<NBNode*> cluster = (*i);
561  // remove join exclusions
562  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
563  std::set<NBNode*>::iterator check = j;
564  ++j;
565  if (myJoinExclusions.count((*check)->getID()) > 0) {
566  cluster.erase(check);
567  }
568  }
569  // iteratively remove the fringe
570  bool pruneFringe = true;
571  while (pruneFringe) {
572  pruneFringe = false;
573  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
574  std::set<NBNode*>::iterator check = j;
575  NBNode* n = *check;
576  ++j;
577 
578  // compute clusterDist for node (length of shortest edge which connects this node to the cluster)
579  double clusterDist = std::numeric_limits<double>::max();
580  for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
581  NBNode* neighbor = (*it_edge)->getToNode();
582  if (cluster.count(neighbor) != 0) {
583  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
584  }
585  }
586  for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
587  NBNode* neighbor = (*it_edge)->getFromNode();
588  if (cluster.count(neighbor) != 0) {
589  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
590  }
591  }
592  // remove geometry-like nodes at fringe of the cluster
593  // (they have 1 neighbor in the cluster and at most 1 neighbor outside the cluster)
594  std::set<NBNode*> neighbors;
595  std::set<NBNode*> clusterNeigbors;
596  const double pedestrianFringeThreshold = 1.0;
597  for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
598  NBNode* neighbor = (*it_edge)->getToNode();
599  if (cluster.count(neighbor) == 0) {
600  if ((*it_edge)->getPermissions() != SVC_PEDESTRIAN || clusterDist < pedestrianFringeThreshold) {
601  neighbors.insert(neighbor);
602  }
603  } else {
604  clusterNeigbors.insert(neighbor);
605  }
606  }
607  for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
608  NBNode* neighbor = (*it_edge)->getFromNode();
609  if (cluster.count(neighbor) == 0) {
610  if ((*it_edge)->getPermissions() != SVC_PEDESTRIAN || clusterDist < pedestrianFringeThreshold) {
611  neighbors.insert(neighbor);
612  }
613  } else {
614  clusterNeigbors.insert(neighbor);
615  }
616  }
617  if (neighbors.size() <= 1 && clusterNeigbors.size() == 1) {
618  cluster.erase(check);
619  pruneFringe = true; // other nodes could belong to the fringe now
620  }
621  }
622  }
623  // exclude the fromNode of a long edge if the toNode is in the cluster (and they were both added via an alternative path).
624  std::set<NBNode*> toRemove;
625  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
626  NBNode* n = *j;
627  const EdgeVector& edges = n->getOutgoingEdges();
628  for (EdgeVector::const_iterator it_edge = edges.begin(); it_edge != edges.end(); ++it_edge) {
629  NBEdge* edge = *it_edge;
630  if (cluster.count(edge->getToNode()) != 0 && edge->getLoadedLength() > maxDist) {
631  //std::cout << "long edge " << edge->getID() << " (" << edge->getLoadedLength() << ", max=" << maxDist << ")\n";
632  toRemove.insert(n);
633  toRemove.insert(edge->getToNode());
634  }
635  }
636  }
637  for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
638  cluster.erase(*j);
639  }
640  if (cluster.size() < 2) {
641  continue;
642  }
643  // check for clusters which are to complex and probably won't work very well
644  // we count the incoming edges of the final junction
645  std::map<std::string, double> finalIncomingAngles;
646  std::map<std::string, double> finalOutgoingAngles;
647  std::vector<std::string> nodeIDs;
648  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
649  nodeIDs.push_back((*j)->getID());
650  for (EdgeVector::const_iterator it_edge = (*j)->getIncomingEdges().begin(); it_edge != (*j)->getIncomingEdges().end(); ++it_edge) {
651  NBEdge* edge = *it_edge;
652  if (cluster.count(edge->getFromNode()) == 0 && edge->getPermissions() != SVC_PEDESTRIAN) {
653  // incoming edge, does not originate in the cluster
654  finalIncomingAngles[edge->getID()] = edge->getAngleAtNode(edge->getToNode());
655  }
656  }
657  for (EdgeVector::const_iterator it_edge = (*j)->getOutgoingEdges().begin(); it_edge != (*j)->getOutgoingEdges().end(); ++it_edge) {
658  NBEdge* edge = *it_edge;
659  if (cluster.count(edge->getToNode()) == 0 && edge->getPermissions() != SVC_PEDESTRIAN) {
660  // outgoing edge, does not end in the cluster
661  finalOutgoingAngles[edge->getID()] = edge->getAngleAtNode(edge->getFromNode());
662  }
663  }
664 
665  }
666  if (finalIncomingAngles.size() > 4) {
667  std::sort(nodeIDs.begin(), nodeIDs.end());
668  WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (" + toString(finalIncomingAngles.size()) + " incoming edges)");
669  continue;
670  }
671  // check for incoming parallel edges
672  const double PARALLEL_INCOMING_THRESHOLD = 10.0;
673  bool foundParallel = false;
674  for (std::map<std::string, double>::const_iterator j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
675  std::map<std::string, double>::const_iterator k = j;
676  for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
677  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
678  WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel incoming "
679  + j->first + "," + k->first + ")");
680  foundParallel = true;
681  }
682  }
683  }
684  // check for outgoing parallel edges
685  for (std::map<std::string, double>::const_iterator j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
686  std::map<std::string, double>::const_iterator k = j;
687  for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
688  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
689  WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel outgoing "
690  + j->first + "," + k->first + ")");
691  foundParallel = true;
692  }
693  }
694  }
695  if (foundParallel) {
696  continue;
697  }
698  // compute all connected components of this cluster
699  // (may be more than 1 if intermediate nodes were removed)
700  NodeClusters components;
701  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
702  // merge all connected components into newComp
703  std::set<NBNode*> newComp;
704  NBNode* current = *j;
705  //std::cout << "checking connectivity for " << current->getID() << "\n";
706  newComp.insert(current);
707  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
708  NodeClusters::iterator check = it_comp;
709  //std::cout << " connected with " << toString(*check) << "?\n";
710  bool connected = false;
711  for (std::set<NBNode*>::iterator k = (*check).begin(); k != (*check).end(); ++k) {
712  if (current->getConnectionTo(*k) != 0 || (*k)->getConnectionTo(current) != 0) {
713  //std::cout << "joining with connected component " << toString(*check) << "\n";
714  newComp.insert((*check).begin(), (*check).end());
715  it_comp = components.erase(check);
716  connected = true;
717  break;
718  }
719  }
720  if (!connected) {
721  it_comp++;
722  }
723  }
724  //std::cout << "adding new component " << toString(newComp) << "\n";
725  components.push_back(newComp);
726  }
727  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
728  if ((*it_comp).size() > 1) {
729  //std::cout << "adding cluster " << toString(*it_comp) << "\n";
730  clusters.push_back(*it_comp);
731  }
732  }
733  }
734  joinNodeClusters(clusters, dc, ec, tlc);
735  return (int)clusters.size();
736 }
737 
738 
739 void
742  for (NodeClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) {
743  std::set<NBNode*> cluster = *i;
744  assert(cluster.size() > 1);
745  Position pos;
746  bool setTL;
747  std::string id;
748  TrafficLightType type;
749  analyzeCluster(cluster, id, pos, setTL, type);
750  if (!insert(id, pos)) {
751  // should not fail
752  WRITE_WARNING("Could not join junctions " + id);
753  continue;
754  }
755  NBNode* newNode = retrieve(id);
756  if (setTL) {
757  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode, 0, type);
758  if (!tlc.insert(tlDef)) {
759  // actually, nothing should fail here
760  delete tlDef;
761  throw ProcessError("Could not allocate tls '" + id + "'.");
762  }
763  }
764  // collect edges
765  std::set<NBEdge*> allEdges;
766  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
767  const EdgeVector& edges = (*j)->getEdges();
768  allEdges.insert(edges.begin(), edges.end());
769  }
770 
771  // remap and remove edges which are completely within the new intersection
772  for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end();) {
773  NBEdge* e = (*j);
774  NBNode* from = e->getFromNode();
775  NBNode* to = e->getToNode();
776  if (cluster.count(from) > 0 && cluster.count(to) > 0) {
777  for (std::set<NBEdge*>::iterator l = allEdges.begin(); l != allEdges.end(); ++l) {
778  if (e != *l) {
779  (*l)->replaceInConnections(e, e->getConnections());
780  }
781  }
782  ec.extract(dc, e, true);
783  allEdges.erase(j++); // erase does not invalidate the other iterators
784  } else {
785  ++j;
786  }
787  }
788 
789  // remap edges which are incoming / outgoing
790  for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end(); ++j) {
791  NBEdge* e = (*j);
792  std::vector<NBEdge::Connection> conns = e->getConnections();
793  const bool outgoing = cluster.count(e->getFromNode()) > 0;
794  NBNode* from = outgoing ? newNode : e->getFromNode();
795  NBNode* to = outgoing ? e->getToNode() : newNode;
796  e->reinitNodes(from, to);
797  // re-add connections which previously existed and may still valid.
798  // connections to removed edges will be ignored
799  for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
800  e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass);
801  if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
802  // @note (see NIImporter_DlrNavteq::ConnectedLanesHandler)
804  }
805  }
806  }
807  // remove original nodes
808  registerJoinedCluster(cluster);
809  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
810  erase(*j);
811  }
812  }
813 }
814 
815 
816 void
817 NBNodeCont::registerJoinedCluster(const std::set<NBNode*>& cluster) {
818  std::set<std::string> ids;
819  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
820  ids.insert((*j)->getID());
821  }
822  myJoinedClusters.push_back(ids);
823 }
824 
825 
826 void
827 NBNodeCont::analyzeCluster(std::set<NBNode*> cluster, std::string& id, Position& pos,
828  bool& hasTLS, TrafficLightType& type) {
829  id = "cluster";
830  hasTLS = false;
831  std::vector<std::string> member_ids;
832  bool ambiguousType = false;
833  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
834  member_ids.push_back((*j)->getID());
835  pos.add((*j)->getPosition());
836  // add a traffic light if any of the cluster members was controlled
837  if ((*j)->isTLControlled()) {
838  if (!hasTLS) {
839  // init type
840  type = (*(*j)->getControllingTLS().begin())->getType();
841  } else if (type != (*(*j)->getControllingTLS().begin())->getType()) {
842  ambiguousType = true;
843  }
844  hasTLS = true;
845  }
846  }
847  pos.mul(1.0 / cluster.size());
848  // need to sort the member names to make the output deterministic
849  sort(member_ids.begin(), member_ids.end());
850  for (std::vector<std::string>::iterator j = member_ids.begin(); j != member_ids.end(); j++) {
851  id = id + "_" + (*j);
852  }
853  if (ambiguousType) {
854  type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
855  WRITE_WARNING("Ambiguous traffic light type for node cluster '" + id + "' set to '" + toString(type) + "'");
856  }
857 }
858 
859 
860 // ----------- (Helper) methods for guessing/computing traffic lights
861 bool
862 NBNodeCont::shouldBeTLSControlled(const std::set<NBNode*>& c) const {
863  int noIncoming = 0;
864  int noOutgoing = 0;
865  bool tooFast = false;
866  double f = 0;
867  std::set<NBEdge*> seen;
868  for (std::set<NBNode*>::const_iterator j = c.begin(); j != c.end(); ++j) {
869  const EdgeVector& edges = (*j)->getEdges();
870  for (EdgeVector::const_iterator k = edges.begin(); k != edges.end(); ++k) {
871  if (c.find((*k)->getFromNode()) != c.end() && c.find((*k)->getToNode()) != c.end()) {
872  continue;
873  }
874  if ((*j)->hasIncoming(*k)) {
875  ++noIncoming;
876  f += (double)(*k)->getNumLanes() * (*k)->getLaneSpeed(0);
877  } else {
878  ++noOutgoing;
879  }
880  if ((*k)->getLaneSpeed(0) * 3.6 > 79) {
881  tooFast = true;
882  }
883  }
884  }
885  return !tooFast && f >= 150. / 3.6 && c.size() != 0;
886 }
887 
888 
889 void
891  // build list of definitely not tls-controlled junctions
892  std::vector<NBNode*> ncontrolled;
893  if (oc.isSet("tls.unset")) {
894  std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset");
895  for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
896  NBNode* n = NBNodeCont::retrieve(*i);
897  if (n == 0) {
898  throw ProcessError(" The junction '" + *i + "' to set as not-controlled is not known.");
899  }
900  std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS();
901  for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
902  (*j)->removeNode(n);
903  }
904  n->removeTrafficLights();
905  ncontrolled.push_back(n);
906  }
907  }
908 
910  // loop#1 checking whether the node shall be tls controlled,
911  // because it is assigned to a district
912  if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) {
913  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
914  NBNode* cur = (*i).second;
915  if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) {
916  setAsTLControlled(cur, tlc, type);
917  }
918  }
919  }
920 
921  // figure out which nodes mark the locations of TLS signals
922  // This assumes nodes are already joined
923  if (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals")) {
924  // prepare candidate edges
925  const double signalDist = oc.getFloat("tls.guess-signals.dist");
926  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
927  NBNode* node = (*i).second;
928  if (node->isTLControlled() && node->geometryLike()) {
929  const EdgeVector& outgoing = node->getOutgoingEdges();
930  for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) {
931  (*it_o)->setSignalOffset((*it_o)->getLength());
932  }
933  }
934  }
935  // check which nodes should be controlled
936  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
937  NBNode* node = i->second;
938  if (find(ncontrolled.begin(), ncontrolled.end(), node) != ncontrolled.end()) {
939  continue;
940  }
941  const EdgeVector& incoming = node->getIncomingEdges();
942  const EdgeVector& outgoing = node->getOutgoingEdges();
943  if (!node->isTLControlled() && incoming.size() > 1 && !node->geometryLike()) {
944  std::vector<NBNode*> signals;
945  bool isTLS = true;
946  for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
947  const NBEdge* inEdge = *it_i;
948  if (inEdge->getSignalOffset() == NBEdge::UNSPECIFIED_SIGNAL_OFFSET || inEdge->getSignalOffset() > signalDist) {
949  isTLS = false;
950  break;
951  }
952  if (inEdge->getSignalOffset() == inEdge->getLength()) {
953  signals.push_back(inEdge->getFromNode());
954  }
955  }
956  // outgoing edges may be tagged with pedestrian crossings. These
957  // should also be morged into the main TLS
958  for (EdgeVector::const_iterator it_i = outgoing.begin(); it_i != outgoing.end(); ++it_i) {
959  const NBEdge* outEdge = *it_i;
960  NBNode* cand = outEdge->getToNode();
961  if (cand->isTLControlled() && cand->geometryLike() && outEdge->getLength() <= signalDist) {
962  signals.push_back(cand);
963  }
964  }
965  if (isTLS) {
966  for (std::vector<NBNode*>::iterator j = signals.begin(); j != signals.end(); ++j) {
967  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
968  (*j)->reinit((*j)->getPosition(), NODETYPE_PRIORITY);
969  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
970  tlc.removeFully((*j)->getID());
971  }
972  }
973  NBTrafficLightDefinition* tlDef = new NBOwnTLDef("GS_" + node->getID(), node, 0, TLTYPE_STATIC);
974  // @todo patch endOffset for all incoming lanes according to the signal positions
975  if (!tlc.insert(tlDef)) {
976  // actually, nothing should fail here
977  WRITE_WARNING("Could not build joined tls '" + node->getID() + "'.");
978  delete tlDef;
979  return;
980  }
981  }
982  }
983  }
984  }
985 
986  // maybe no tls shall be guessed
987  if (!oc.getBool("tls.guess")) {
988  return;
989  }
990 
991  // guess joined tls first, if wished
992  if (oc.getBool("tls.join")) {
993  // get node clusters
994  std::vector<std::set<NBNode*> > cands;
995  generateNodeClusters(oc.getFloat("tls.join-dist"), cands);
996  // check these candidates (clusters) whether they should be controlled by a tls
997  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end();) {
998  std::set<NBNode*>& c = (*i);
999  // regard only junctions which are not yet controlled and are not
1000  // forbidden to be controlled
1001  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) {
1002  if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) {
1003  c.erase(j++);
1004  } else {
1005  ++j;
1006  }
1007  }
1008  // check whether the cluster should be controlled
1009  if (!shouldBeTLSControlled(c)) {
1010  i = cands.erase(i);
1011  } else {
1012  ++i;
1013  }
1014  }
1015  // cands now only contain sets of junctions that shall be joined into being tls-controlled
1016  int index = 0;
1017  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) {
1018  std::vector<NBNode*> nodes;
1019  for (std::set<NBNode*>::iterator j = (*i).begin(); j != (*i).end(); j++) {
1020  nodes.push_back(*j);
1021  }
1022  std::string id = "joinedG_" + toString(index++);
1023  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1024  if (!tlc.insert(tlDef)) {
1025  // actually, nothing should fail here
1026  WRITE_WARNING("Could not build guessed, joined tls");
1027  delete tlDef;
1028  return;
1029  }
1030  }
1031  }
1032 
1033  // guess tls
1034  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1035  NBNode* cur = (*i).second;
1036  // do nothing if already is tl-controlled
1037  if (cur->isTLControlled()) {
1038  continue;
1039  }
1040  // do nothing if in the list of explicit non-controlled junctions
1041  if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) {
1042  continue;
1043  }
1044  std::set<NBNode*> c;
1045  c.insert(cur);
1046  if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) {
1047  continue;
1048  }
1049  setAsTLControlled((*i).second, tlc, type);
1050  }
1051 }
1052 
1053 
1054 void
1056  std::vector<std::set<NBNode*> > cands;
1057  generateNodeClusters(maxdist, cands);
1058  int index = 0;
1059  for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) {
1060  std::set<NBNode*>& c = (*i);
1061  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) {
1062  if (!(*j)->isTLControlled()) {
1063  c.erase(j++);
1064  } else {
1065  ++j;
1066  }
1067  }
1068  if (c.size() < 2) {
1069  continue;
1070  }
1071  // figure out type of the joined TLS
1072  Position dummyPos;
1073  bool dummySetTL;
1074  std::string dummyId;
1075  TrafficLightType type;
1076  analyzeCluster(c, dummyId, dummyPos, dummySetTL, type);
1077  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); ++j) {
1078  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
1079  (*j)->removeTrafficLights();
1080  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
1081  tlc.removeFully((*j)->getID());
1082  }
1083  }
1084  std::string id = "joinedS_" + toString(index++);
1085  std::vector<NBNode*> nodes;
1086  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); j++) {
1087  nodes.push_back(*j);
1088  }
1089  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1090  if (!tlc.insert(tlDef)) {
1091  // actually, nothing should fail here
1092  WRITE_WARNING("Could not build a joined tls.");
1093  delete tlDef;
1094  return;
1095  }
1096  }
1097 }
1098 
1099 
1100 void
1102  TrafficLightType type, std::string id) {
1103  if (id == "") {
1104  id = node->getID();
1105  }
1106  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node, 0, type);
1107  if (!tlc.insert(tlDef)) {
1108  // actually, nothing should fail here
1109  WRITE_WARNING("Building a tl-logic for junction '" + id + "' twice is not possible.");
1110  delete tlDef;
1111  return;
1112  }
1113 }
1114 
1115 
1116 // -----------
1117 void
1119  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1120  (*i).second->computeLanes2Lanes();
1121  }
1122 }
1123 
1124 
1125 // computes the "wheel" of incoming and outgoing edges for every node
1126 void
1128  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1129  (*i).second->computeLogic(ec, oc);
1130  }
1131 }
1132 
1133 
1134 void
1136  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1137  delete((*i).second);
1138  }
1139  myNodes.clear();
1140  for (std::set<NBNode*>::iterator i = myExtractedNodes.begin(); i != myExtractedNodes.end(); i++) {
1141  delete(*i);
1142  }
1143  myExtractedNodes.clear();
1144 }
1145 
1146 
1147 std::string
1149  int counter = 0;
1150  std::string freeID = "SUMOGenerated" + toString<int>(counter);
1151  // While there is a node with id equal to freeID
1152  while (retrieve(freeID) != 0) {
1153  // update counter and generate a new freeID
1154  counter++;
1155  freeID = "SUMOGenerated" + toString<int>(counter);
1156  }
1157  return freeID;
1158 }
1159 
1160 
1161 void
1162 NBNodeCont::computeNodeShapes(double mismatchThreshold) {
1163  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1164  (*i).second->computeNodeShape(mismatchThreshold);
1165  }
1166 }
1167 
1168 
1169 void
1171  int numUnregulatedJunctions = 0;
1172  int numDeadEndJunctions = 0;
1173  int numPriorityJunctions = 0;
1174  int numRightBeforeLeftJunctions = 0;
1175  int numAllWayStopJunctions = 0;
1176  int numZipperJunctions = 0;
1177  int numRailSignals = 0;
1178  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1179  switch ((*i).second->getType()) {
1180  case NODETYPE_NOJUNCTION:
1182  ++numUnregulatedJunctions;
1183  break;
1184  case NODETYPE_DEAD_END:
1185  ++numDeadEndJunctions;
1186  break;
1187  case NODETYPE_PRIORITY:
1192  ++numPriorityJunctions;
1193  break;
1195  ++numRightBeforeLeftJunctions;
1196  break;
1197  case NODETYPE_ALLWAY_STOP:
1198  ++numAllWayStopJunctions;
1199  break;
1200  case NODETYPE_ZIPPER:
1201  ++numZipperJunctions;
1202  break;
1203  case NODETYPE_DISTRICT:
1204  ++numRightBeforeLeftJunctions;
1205  break;
1206  case NODETYPE_UNKNOWN:
1207  break;
1208  case NODETYPE_RAIL_SIGNAL:
1209  ++numRailSignals;
1210  break;
1211  default:
1212  break;
1213  }
1214  }
1215  WRITE_MESSAGE(" Node type statistics:");
1216  WRITE_MESSAGE(" Unregulated junctions : " + toString(numUnregulatedJunctions));
1217  if (numDeadEndJunctions > 0) {
1218  WRITE_MESSAGE(" Dead-end junctions : " + toString(numDeadEndJunctions));
1219  }
1220  WRITE_MESSAGE(" Priority junctions : " + toString(numPriorityJunctions));
1221  WRITE_MESSAGE(" Right-before-left junctions : " + toString(numRightBeforeLeftJunctions));
1222  if (numAllWayStopJunctions > 0) {
1223  WRITE_MESSAGE(" All-way stop junctions : " + toString(numAllWayStopJunctions));
1224  }
1225  if (numZipperJunctions > 0) {
1226  WRITE_MESSAGE(" Zipper-merge junctions : " + toString(numZipperJunctions));
1227  }
1228  if (numRailSignals > 0) {
1229  WRITE_MESSAGE(" Rail signal junctions : " + toString(numRailSignals));
1230  }
1231 }
1232 
1233 
1234 std::vector<std::string>
1236  std::vector<std::string> ret;
1237  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1238  ret.push_back((*i).first);
1239  }
1240  return ret;
1241 }
1242 
1243 
1244 void
1245 NBNodeCont::rename(NBNode* node, const std::string& newID) {
1246  if (myNodes.count(newID) != 0) {
1247  throw ProcessError("Attempt to rename node using existing id '" + newID + "'");
1248  }
1249  myNodes.erase(node->getID());
1250  node->setID(newID);
1251  myNodes[newID] = node;
1252 }
1253 
1254 
1255 void
1256 NBNodeCont::discardTrafficLights(NBTrafficLightLogicCont& tlc, bool geometryLike, bool guessSignals) {
1257  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1258  NBNode* node = i->second;
1259  if (!geometryLike || node->geometryLike()) {
1260  // make a copy of tldefs
1261  const std::set<NBTrafficLightDefinition*> tldefs = node->getControllingTLS();
1262  if (guessSignals && node->isTLControlled() && node->geometryLike()) {
1263  // record signal location
1264  const EdgeVector& outgoing = node->getOutgoingEdges();
1265  for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) {
1266  (*it_o)->setSignalOffset((*it_o)->getLength());
1267  }
1268  }
1269  for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
1270  NBTrafficLightDefinition* tlDef = *it;
1271  node->removeTrafficLight(tlDef);
1272  tlc.extract(tlDef);
1273  }
1274  node->reinit(node->getPosition(), NODETYPE_UNKNOWN);
1275  }
1276  }
1277 }
1278 
1279 
1280 int
1281 NBNodeCont::remapIDs(bool numericaIDs, bool reservedIDs) {
1282  std::vector<std::string> avoid = getAllNames();
1283  std::set<std::string> reserve;
1284  if (reservedIDs) {
1285  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "node:", reserve);
1286  avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1287  }
1288  IDSupplier idSupplier("", avoid);
1289  std::set<NBNode*, Named::ComparatorIdLess> toChange;
1290  for (NodeCont::iterator it = myNodes.begin(); it != myNodes.end(); it++) {
1291  if (numericaIDs) {
1292  try {
1293  TplConvert::_str2long(it->first);
1294  } catch (NumberFormatException&) {
1295  toChange.insert(it->second);
1296  }
1297  }
1298  if (reservedIDs && reserve.count(it->first) > 0) {
1299  toChange.insert(it->second);
1300  }
1301  }
1302  for (std::set<NBNode*, Named::ComparatorIdLess>::iterator it = toChange.begin(); it != toChange.end(); ++it) {
1303  NBNode* node = *it;
1304  myNodes.erase(node->getID());
1305  node->setID(idSupplier.getNext());
1306  myNodes[node->getID()] = node;
1307  }
1308  return (int)toChange.size();
1309 }
1310 
1311 /****************************************************************************/
1312 
std::string getFreeID()
generates a new node ID
std::set< std::string > myJoinExclusions
set of node ids which should not be joined
Definition: NBNodeCont.h:337
NodeCont myNodes
The map of names to nodes.
Definition: NBNodeCont.h:331
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:90
void joinSimilarEdges(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins edges connecting the same nodes.
Definition: NBNodeCont.cpp:177
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:243
void removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes self-loop edges (edges where the source and the destination node are the same) ...
Definition: NBNodeCont.cpp:165
is a pedestrian
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
Definition: NBEdgeCont.cpp:542
void addJoinExclusion(const std::vector< std::string > &ids, bool check=false)
Definition: NBNodeCont.cpp:497
static void loadPrefixedIDsFomFile(const std::string &file, const std::string prefix, std::set< std::string > &into)
Add prefixed ids defined in file.
Definition: NBHelpers.cpp:111
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:133
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1595
int removeUnwishedNodes(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, bool removeGeometryNodes)
Removes "unwished" nodes.
Definition: NBNodeCont.cpp:367
void removeIsolatedRoads(NBDistrictCont &dc, NBEdgeCont &ec)
Removes sequences of edges that are not connected with a junction. Simple roads without junctions som...
Definition: NBNodeCont.cpp:222
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
Definition: NBEdge.cpp:2758
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn&#39;t set.
Definition: NBEdge.h:491
A container for traffic light definitions and built programs.
void joinTLS(NBTrafficLightLogicCont &tlc, double maxdist)
Builds clusters of tls-controlled junctions and joins the control if possible.
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:264
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:291
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
double x() const
Returns the x-position.
Definition: Position.h:63
std::vector< std::set< std::string > > myJoinedClusters
sets of node ids which were joined
Definition: NBNodeCont.h:343
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
void reinitNodes(NBNode *from, NBNode *to)
Resets nodes but keeps all other values the same (used when joining)
Definition: NBEdge.cpp:376
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:274
A container for districts.
The base class for traffic light logic definitions.
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.h:559
int joinLoadedClusters(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins loaded junction clusters (see NIXMLNodesHandler)
Definition: NBNodeCont.cpp:531
NamedRTree myRTree
node positions for faster lookup
Definition: NBNodeCont.h:352
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:508
static long long int _str2long(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter, which
Definition: TplConvert.h:244
void guessTLs(OptionsCont &oc, NBTrafficLightLogicCont &tlc)
Guesses which junctions or junction clusters shall be controlled by tls.
Definition: NBNodeCont.cpp:890
bool connectionsDone
Whether connection information for this lane is already completed.
Definition: NBEdge.h:155
void avoidOverlap()
fix overlap
Definition: NBNodeCont.cpp:437
bool checkIsRemovable() const
check if node is removable
Definition: NBNode.cpp:1634
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1161
static void loadEdgesFromFile(const std::string &file, std::set< std::string > &into)
Add edge ids defined in file (either ID or edge:ID per line) into the given set.
Definition: NBHelpers.cpp:93
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:322
void extract(NBTrafficLightDefinition *definition)
Extracts a traffic light definition from myDefinitions but keeps it in myExtracted for eventual * del...
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1208
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:65
The edge has been loaded, nothing is computed yet.
Definition: NBEdge.h:92
void computeLogics(const NBEdgeCont &ec, OptionsCont &oc)
build the list of outgoing edges and lanes
A class representing a single district.
Definition: NBDistrict.h:72
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:248
const std::string & getID() const
Returns the id.
Definition: Named.h:66
void Remove(const float a_min[2], const float a_max[2], Named *const &a_data)
Remove entry.
Definition: NamedRTree.h:101
const Position & getPosition() const
Definition: NBNode.h:235
void generateNodeClusters(double maxDist, NodeClusters &into) const
Builds node clusters.
Definition: NBNodeCont.cpp:445
#define max(a, b)
Definition: polyfonts.c:65
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:198
std::string getNext()
Returns the next id.
Definition: IDSupplier.cpp:59
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node) ...
Definition: NBNode.h:296
void computeLanes2Lanes()
divides the incoming lanes on outgoing lanes
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
~NBNodeCont()
Destructor.
Definition: NBNodeCont.cpp:70
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
void extract(NBDistrictCont &dc, NBEdge *edge, bool remember=false)
Removes the given edge from the container like erase but does not delete it.
Definition: NBEdgeCont.cpp:392
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBNodeCont()
Constructor.
Definition: NBNodeCont.cpp:65
std::pair< NBNode *, double > NodeAndDist
Definition: NBNodeCont.h:295
double y() const
Returns the y-position.
Definition: Position.h:68
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2564
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:414
void removeTrafficLights()
Removes all references to traffic lights that control this tls.
Definition: NBNode.cpp:329
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node) ...
Definition: NBNode.h:253
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:68
void computeNodeShapes(double mismatchThreshold=-1)
Compute the junction shape for this node.
#define POSITION_EPS
Definition: config.h:176
void joinNodeClusters(NodeClusters clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
joins the given node clusters
Definition: NBNodeCont.cpp:740
std::set< NBNode * > myExtractedNodes
The extracted nodes which are kept for reference.
Definition: NBNodeCont.h:334
int joinJunctions(double maxDist, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins junctions that are very close together.
Definition: NBNodeCont.cpp:555
std::vector< std::string > getAllNames() const
get all node names
The connection was given by the user.
Definition: NBEdge.h:113
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:1754
bool shouldBeTLSControlled(const std::set< NBNode * > &c) const
Returns whethe the given node cluster should be controlled by a tls.
Definition: NBNodeCont.cpp:862
void rename(NBNode *node, const std::string &newID)
Renames the node. Throws exception if newID already exists.
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
Definition: NBNode.cpp:1703
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
Definition: NBEdgeCont.cpp:704
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:190
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2988
void setAsTLControlled(NBNode *node, NBTrafficLightLogicCont &tlc, TrafficLightType type, std::string id="")
Sets the given node as being controlled by a tls.
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:100
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:435
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:482
bool isNearDistrict() const
if node is near district
Definition: NBNode.cpp:1765
void setID(const std::string &newID)
resets the id
Definition: Named.h:74
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:251
void addCluster2Join(std::set< std::string > cluster)
add ids of nodes which shall be joined into a single node
Definition: NBNodeCont.cpp:513
int remapIDs(bool numericaIDs, bool reservedIDs)
remap node IDs accoring to options –numerical-ids and –reserved-ids
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurences of the first edge within the list of incoming by the second Connections are remap...
Definition: NBNode.cpp:1102
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:41
void analyzeCluster(std::set< NBNode * > cluster, std::string &id, Position &pos, bool &hasTLS, TrafficLightType &type)
Definition: NBNodeCont.cpp:827
std::set< std::string > myJoined
ids found in loaded join clusters used for error checking
Definition: NBNodeCont.h:346
A storage for options typed value containers)
Definition: OptionsCont.h:99
std::vector< std::set< NBNode * > > NodeClusters
Definition of a node cluster container.
Definition: NBNodeCont.h:294
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:253
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:385
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:77
void clear()
deletes all nodes
void append(NBEdge *continuation)
append another edge
Definition: NBEdge.cpp:2696
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:913
std::vector< std::set< std::string > > myClusters2Join
loaded sets of node ids to join (cleared after use)
Definition: NBNodeCont.h:340
void discardTrafficLights(NBTrafficLightLogicCont &tlc, bool geometryLike, bool guessSignals)
void declareConnectionsAsLoaded(EdgeBuildingStep step=LANES2LANES_USER)
declares connections as fully loaded. This is needed to avoid recomputing connections if an edge has ...
Definition: NBEdge.h:1175
Represents a single node (junction) during network building.
Definition: NBNode.h:75
T get(const std::string &str) const
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
std::set< const NBNode * > mySplit
nodes that were created when splitting an edge
Definition: NBNodeCont.h:349
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:106
void mul(double val)
Multiplies both positions with the given value.
Definition: Position.h:113
void printBuiltNodesStatistics() const
Prints statistics about built nodes.
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane)
Replaces occurences of the removed edge/lane in all definitions by the given edge.
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
bool extract(NBNode *node, bool remember=false)
Removes the given node but does not delete it.
Definition: NBNodeCont.cpp:147
int Search(const float a_min[2], const float a_max[2], const Named::StoringVisitor &c) const
Find all within search rectangle.
Definition: NamedRTree.h:123
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:201
bool erase(NBNode *node)
Removes the given node, deleting it.
Definition: NBNodeCont.cpp:136
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:835
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:114
bool exists(const std::string &name) const
Returns the information whether the named option is known.
TrafficLightType
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
void registerJoinedCluster(const std::set< NBNode * > &cluster)
gets all joined clusters (see doc for myClusters2Join)
Definition: NBNodeCont.cpp:817
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:428
void removeComponents(NBDistrictCont &dc, NBEdgeCont &ec, const int numKeep)
Checks the network for weak connectivity and removes all but the largest components. The connectivity check is done regardless of edge direction and vclass.
Definition: NBNodeCont.cpp:310