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