Eclipse 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-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
21 // Container for nodes during the netbuilding process
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #include <config.h>
29 
30 #include <string>
31 #include <map>
32 #include <algorithm>
33 #include <cmath>
35 #include <utils/geom/Boundary.h>
36 #include <utils/geom/GeomHelper.h>
41 #include <utils/common/StdDefs.h>
42 #include <utils/common/ToString.h>
48 #include "NBHelpers.h"
49 #include "NBAlgorithms.h"
50 #include "NBDistrict.h"
51 #include "NBEdgeCont.h"
53 #include "NBOwnTLDef.h"
54 #include "NBNodeCont.h"
55 #include "NBPTStopCont.h"
56 #include "NBPTLineCont.h"
57 #include "NBParking.h"
58 
59 //#define DEBUG_JOINJUNCTIONS
60 #define DEBUGNODEID "C1"
61 //#define DEBUGNODEID "5548037023"
62 #define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID))
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 nullptr;
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 nullptr;
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[node->getID()] = 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 == nullptr) {
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 = nullptr;
258  NBNode* to;
259  NodeSet 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  // need to use ids here to have the same ordering on all platforms
315  std::set<std::string> edgesLeft;
316  for (std::map<std::string, NBEdge*>::const_iterator edgeIt = ec.begin(); edgeIt != ec.end(); ++edgeIt) {
317  edgesLeft.insert(edgeIt->first);
318  }
319  EdgeVector queue;
320  std::set<NBEdge*> toRemove;
321  while (!edgesLeft.empty()) {
322  queue.push_back(ec.getByID(*edgesLeft.begin()));
323  std::set<NBEdge*> component;
324  while (!queue.empty()) {
325  NBEdge* const e = queue.back();
326  queue.pop_back();
327  component.insert(e);
328  std::vector<EdgeVector> edgeLists;
329  edgeLists.push_back(e->getFromNode()->getOutgoingEdges());
330  edgeLists.push_back(e->getFromNode()->getIncomingEdges());
331  edgeLists.push_back(e->getToNode()->getOutgoingEdges());
332  edgeLists.push_back(e->getToNode()->getIncomingEdges());
333  for (std::vector<EdgeVector>::const_iterator listIt = edgeLists.begin(); listIt != edgeLists.end(); ++listIt) {
334  for (EdgeVector::const_iterator edgeIt = listIt->begin(); edgeIt != listIt->end(); ++edgeIt) {
335  std::set<std::string>::iterator leftIt = edgesLeft.find((*edgeIt)->getID());
336  if (leftIt != edgesLeft.end()) {
337  queue.push_back(*edgeIt);
338  edgesLeft.erase(leftIt);
339  }
340  }
341  }
342  }
343  std::vector<std::set<NBEdge*> >::iterator cIt;
344  for (cIt = components.begin(); cIt != components.end(); ++cIt) {
345  if (cIt->size() < component.size()) {
346  break;
347  }
348  }
349  components.insert(cIt, component);
350  if ((int)components.size() > numKeep) {
351  toRemove.insert(components.back().begin(), components.back().end());
352  components.pop_back();
353  }
354  }
355  for (std::set<NBEdge*>::iterator edgeIt = toRemove.begin(); edgeIt != toRemove.end(); ++edgeIt) {
356  NBNode* const fromNode = (*edgeIt)->getFromNode();
357  NBNode* const toNode = (*edgeIt)->getToNode();
358  ec.erase(dc, *edgeIt);
359  if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) {
360  erase(fromNode);
361  }
362  if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) {
363  erase(toNode);
364  }
365  }
366 }
367 
368 
369 int
372  NBParkingCont& pc,
373  bool removeGeometryNodes) {
374  // load edges that shall not be modified
375  std::set<std::string> edges2keep;
376  if (removeGeometryNodes) {
377  const OptionsCont& oc = OptionsCont::getOptions();
378  if (oc.isSet("geometry.remove.keep-edges.input-file")) {
379  NBHelpers::loadEdgesFromFile(oc.getString("geometry.remove.keep-edges.input-file"), edges2keep);
380  }
381  if (oc.isSet("geometry.remove.keep-edges.explicit")) {
382  const std::vector<std::string> edges = oc.getStringVector("geometry.remove.keep-edges.explicit");
383  edges2keep.insert(edges.begin(), edges.end());
384  }
385  sc.addEdges2Keep(oc, edges2keep);
386  lc.addEdges2Keep(oc, edges2keep);
387  pc.addEdges2Keep(oc, edges2keep);
388  }
389  int no = 0;
390  std::vector<NBNode*> toRemove;
391  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
392  NBNode* current = (*i).second;
393  bool remove = false;
394  std::vector<std::pair<NBEdge*, NBEdge*> > toJoin;
395  // check for completely empty nodes
396  if (current->getOutgoingEdges().size() == 0 && current->getIncomingEdges().size() == 0) {
397  // remove if empty
398  remove = true;
399  }
400  // check for nodes which are only geometry nodes
401  if (removeGeometryNodes && mySplit.count(current) == 0) {
402  if ((current->getOutgoingEdges().size() == 1 && current->getIncomingEdges().size() == 1)
403  ||
404  (current->getOutgoingEdges().size() == 2 && current->getIncomingEdges().size() == 2)) {
405  // ok, one in, one out or two in, two out
406  // -> ask the node whether to join
407  remove = current->checkIsRemovable();
408  // check whether any of the edges must be kept
409  for (EdgeVector::const_iterator it_edge = current->getEdges().begin(); it_edge != current->getEdges().end(); ++it_edge) {
410  if (edges2keep.find((*it_edge)->getID()) != edges2keep.end()) {
411  remove = false;
412  break;
413  }
414  }
415  if (remove) {
416  toJoin = current->getEdgesToJoin();
417  }
418  }
419  }
420  // remove the node and join the geometries when wished
421  if (!remove) {
422  continue;
423  }
424  for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j = toJoin.begin(); j != toJoin.end(); j++) {
425  NBEdge* begin = (*j).first;
426  NBEdge* continuation = (*j).second;
427  begin->append(continuation);
428  continuation->getToNode()->replaceIncoming(continuation, begin, 0);
429  tlc.replaceRemoved(continuation, -1, begin, -1);
430  ec.extract(dc, continuation, true);
431  }
432  toRemove.push_back(current);
433  no++;
434  }
435  // erase all
436  for (std::vector<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
437  extract(*j, true);
438  }
439  return no;
440 }
441 
442 
443 void
445  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
446  (*i).second->avoidOverlap();
447  }
448 }
449 
450 // ----------- (Helper) methods for joining nodes
451 void
452 NBNodeCont::generateNodeClusters(double maxDist, NodeClusters& into) const {
453  std::set<NBNode*> visited;
454  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
455  std::vector<NodeAndDist> toProc;
456  if (visited.find((*i).second) != visited.end()) {
457  continue;
458  }
459  toProc.push_back(std::make_pair((*i).second, 0));
460  NodeSet c;
461  while (!toProc.empty()) {
462  NodeAndDist nodeAndDist = toProc.back();
463  NBNode* n = nodeAndDist.first;
464  double dist = nodeAndDist.second;
465  toProc.pop_back();
466  if (visited.find(n) != visited.end()) {
467  continue;
468  }
469  visited.insert(n);
470  bool pureRail = true;
471  bool railAndPeds = true;
472  for (NBEdge* e : n->getEdges()) {
473  if ((e->getPermissions() & ~(SVC_RAIL_CLASSES | SVC_PEDESTRIAN)) != 0) {
474  railAndPeds = false;
475  pureRail = false;
476  break;
477  }
478  if ((e->getPermissions() & ~(SVC_RAIL_CLASSES)) != 0) {
479  pureRail = false;
480  }
481  }
482  if (pureRail) {
483  // do not join pure rail nodes
484  continue;
485  }
486  c.insert(n);
487  for (NBEdge* e : n->getEdges()) {
488  NBNode* s = n->hasIncoming(e) ? e->getFromNode() : e->getToNode();
489  const double length = e->getLoadedLength();
490 #ifdef DEBUG_JOINJUNCTIONS
491  if (DEBUGCOND(s)) {
492  std::cout << "generateNodeClusters: consider s=" << s->getID()
493  << " clusterNode=" << n->getID() << " edge=" << e->getID() << " length=" << length << " with cluster " << joinNamedToString(c, ' ') << "\n";
494  }
495 #endif
496  if (railAndPeds && n->getType() != NODETYPE_RAIL_CROSSING) {
497  bool railAndPeds2 = true;
498  for (NBEdge* e : n->getEdges()) {
499  if ((e->getPermissions() & ~(SVC_RAIL_CLASSES | SVC_PEDESTRIAN)) != 0) {
500  railAndPeds2 = false;
501  break;
502  }
503  }
504  if (railAndPeds2 && s->getType() != NODETYPE_RAIL_CROSSING) {
505  // do not join rail/ped nodes unless at a rail crossing
506  // (neither nodes nor the traffic lights)
507  continue;
508  }
509  }
510  const bool bothCrossing = n->getType() == NODETYPE_RAIL_CROSSING && s->getType() == NODETYPE_RAIL_CROSSING;
511  const bool joinPedCrossings = bothCrossing && e->getPermissions() == SVC_PEDESTRIAN;
512  if ( // never join pedestrian stuff (unless at a rail crossing
513  !joinPedCrossings && (
514  e->getPermissions() == SVC_PEDESTRIAN
515  // only join edges for regular passenger traffic or edges that are extremely short
516  || (length > 3 * POSITION_EPS
517  && (e->getPermissions() & (SVC_PASSENGER | SVC_TRAM)) == 0
519  continue;
520  }
521  // never join rail_crossings with other node types unless the crossing is only for tram
524  const SVCPermissions railNoTram = (SVC_RAIL_CLASSES & ~SVC_TRAM);
525  bool foundRail = false;
526  NBNode* crossingNode = n->getType() == NODETYPE_RAIL_CROSSING ? n : s;
527  for (NBEdge* e2 : crossingNode->getIncomingEdges()) {
528  if ((e2->getPermissions() & railNoTram) != 0) {
529  foundRail = true;
530  break;
531  }
532  }
533  if (foundRail) {
534  continue;
535  }
536  }
537  // never join rail_crossings via a rail edge
538  if (bothCrossing && (e->getPermissions() & ~SVC_RAIL_CLASSES) == 0) {
539  continue;
540  }
541  if (visited.find(s) != visited.end()) {
542  continue;
543  }
544  if (length + dist < maxDist) {
545  if (s->geometryLike()) {
546  toProc.push_back(std::make_pair(s, dist + length));
547  } else {
548  toProc.push_back(std::make_pair(s, 0));
549  }
550  }
551  }
552  }
553  if (c.size() < 2) {
554  continue;
555  }
556 #ifdef DEBUG_JOINJUNCTIONS
557  std::cout << " DEBUG: consider cluster " << joinNamedToString(c, ' ') << "\n";
558 #endif
559  into.push_back(c);
560  }
561 }
562 
563 
564 void
565 NBNodeCont::addJoinExclusion(const std::vector<std::string>& ids, bool check) {
566  for (std::vector<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
567  // error handling has to take place here since joinExclusions could be
568  // loaded from multiple files / command line
569  if (myJoined.count(*it) > 0) {
570  WRITE_WARNING("Ignoring join exclusion for junction '" + *it + "' since it already occurred in a list of nodes to be joined");
571  } else if (check && retrieve(*it) == nullptr) {
572  WRITE_WARNING("Ignoring join exclusion for unknown junction '" + *it + "'");
573  } else {
574  myJoinExclusions.insert(*it);
575  }
576  }
577 }
578 
579 
580 void
581 NBNodeCont::addCluster2Join(std::set<std::string> cluster, NBNode* node) {
582  // error handling has to take place here since joins could be loaded from multiple files
583  std::set<std::string> validCluster;
584  for (std::string nodeID : cluster) {
585  if (myJoinExclusions.count(nodeID) > 0) {
586  WRITE_WARNING("Ignoring join-cluster because junction '" + nodeID + "' was already excluded from joining");
587  return;
588  } else if (myJoined.count(nodeID) > 0) {
589  WRITE_WARNING("Ignoring join-cluster because junction '" + nodeID + "' already occurred in another join-cluster");
590  return;
591  } else {
592  NBNode* node = retrieve(nodeID);
593  if (node != nullptr) {
594  validCluster.insert(nodeID);
595  } else {
596  if (StringUtils::startsWith(nodeID, "cluster_")) {
597  // assume join directive came from a pre-processed network. try to use component IDs
598  std::set<std::string> subIDs;
599  for (std::string nID : StringTokenizer(nodeID.substr(8), "_").getVector()) {
600  NBNode* node = retrieve(nID);
601  if (node != nullptr) {
602  validCluster.insert(nID);
603  } else {
604  WRITE_ERROR("Unknown junction '" + nodeID + "' in join-cluster (componentID)");
605  }
606  }
607  } else {
608  WRITE_ERROR("Unknown junction '" + nodeID + "' in join-cluster");
609  }
610  }
611  }
612  }
613  for (std::string nodeID : validCluster) {
614  myJoined.insert(nodeID);
615  }
616  myClusters2Join.push_back(std::make_pair(validCluster, node));
617 }
618 
619 
620 int
622  int numJoined = 0;
623  for (auto& item : myClusters2Join) {
624  // verify loaded cluster
625  NodeSet cluster;
626  for (std::string nodeID : item.first) {
627  NBNode* node = retrieve(nodeID);
628  if (node == nullptr) {
629  WRITE_ERROR("unknown junction '" + nodeID + "' while joining");
630  } else {
631  cluster.insert(node);
632  }
633  }
634  if (cluster.size() > 1) {
635  joinNodeCluster(cluster, dc, ec, tlc, item.second);
636  numJoined++;
637  myJoinExclusions.insert(item.second->getID());
638  }
639  }
640  myClusters2Join.clear(); // make save for recompute
641  return numJoined;
642 }
643 
644 
645 int
647 #ifdef DEBUG_JOINJUNCTIONS
648  std::cout << "joinJunctions...\n";
649 #endif
650  NodeClusters cands;
651  NodeClusters clusters;
652  generateNodeClusters(maxDist, cands);
653  for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
654  NodeSet cluster = (*i);
655  // remove join exclusions
656  for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
657  NodeSet::iterator check = j;
658  ++j;
659  if (myJoinExclusions.count((*check)->getID()) > 0) {
660  cluster.erase(check);
661  }
662  }
663  // remove nodes that can be eliminated by geometry.remove
664  pruneClusterFringe(cluster);
665  // avoid removal of long edges (must have been added via an alternative path).
666  std::set<NBNode*> toRemove;
667  for (NBNode* n : cluster) {
668  for (NBEdge* edge : n->getOutgoingEdges()) {
669  if (cluster.count(edge->getToNode()) != 0 && edge->getLoadedLength() > maxDist /*&& (edge->getPermissions() & SVC_PASSENGER) != 0*/) {
670 #ifdef DEBUG_JOINJUNCTIONS
671  if (DEBUGCOND(n) || DEBUGCOND(edge->getToNode())) {
672  std::cout << "long edge " << edge->getID() << " (" << edge->getLoadedLength() << ", max=" << maxDist << ")\n";
673  }
674 #endif
675  toRemove.insert(n);
676  toRemove.insert(edge->getToNode());
677  }
678  }
679  }
680  for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
681  cluster.erase(*j);
682  }
683  if (cluster.size() < 2) {
684  continue;
685  }
686  std::string reason;
687  bool feasible = feasibleCluster(cluster, ec, sc, reason);
688  //if (!feasible) std::cout << "\ntry to reduce cluster " << joinNamedToString(cluster, ',') << "\n";
689  if (!feasible) {
690  std::string origCluster = joinNamedToString(cluster, ',');
691  if (reduceToCircle(cluster, 4, cluster)) {
692  pruneClusterFringe(cluster);
693  feasible = feasibleCluster(cluster, ec, sc, reason);
694  if (feasible) {
695  WRITE_WARNING("Reducing junction cluster " + origCluster + " (" + reason + ")");
696  }
697  }
698  }
699  if (!feasible) {
700  std::string origCluster = joinNamedToString(cluster, ',');
701  if (reduceToCircle(cluster, 2, cluster)) {
702  pruneClusterFringe(cluster);
703  feasible = feasibleCluster(cluster, ec, sc, reason);
704  if (feasible) {
705  WRITE_WARNING("Reducing junction cluster " + origCluster + " (" + reason + ")");
706  }
707  }
708  }
709  if (!feasible) {
710  WRITE_WARNING("Not joining junctions " + joinNamedToString(cluster, ',') + " (" + reason + ")");
711  continue;
712  }
713  // compute all connected components of this cluster
714  // (may be more than 1 if intermediate nodes were removed)
715  NodeClusters components;
716  for (NBNode* current : cluster) {
717  // merge all connected components into newComp
718  NodeSet newComp;
719  //std::cout << "checking connectivity for " << current->getID() << "\n";
720  newComp.insert(current);
721  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
722  NodeClusters::iterator check = it_comp;
723  //std::cout << " connected with " << toString(*check) << "?\n";
724  bool connected = false;
725  for (NBNode* k : *check) {
726  if (current->getConnectionTo(k) != nullptr || k->getConnectionTo(current) != nullptr) {
727  //std::cout << "joining with connected component " << toString(*check) << "\n";
728  newComp.insert((*check).begin(), (*check).end());
729  it_comp = components.erase(check);
730  connected = true;
731  break;
732  }
733  }
734  if (!connected) {
735  it_comp++;
736  }
737  }
738  //std::cout << "adding new component " << toString(newComp) << "\n";
739  components.push_back(newComp);
740  }
741  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
742  if ((*it_comp).size() > 1) {
743  //std::cout << "adding cluster " << toString(*it_comp) << "\n";
744  clusters.push_back(*it_comp);
745  }
746  }
747  }
748  joinNodeClusters(clusters, dc, ec, tlc);
749  return (int)clusters.size();
750 }
751 
752 
753 void
755 #ifdef DEBUG_JOINJUNCTIONS
756  if (true) {
757  std::cout << "pruning cluster=" << joinNamedToString(cluster, ' ') << "\n";
758  }
759 #endif
760  // iteratively remove the fringe
761  bool pruneFringe = true;
762  // collect nodes that shall be joined due to distance but are not connected
763  // to the cluster for passenger traffic
764  while (pruneFringe) {
765  pruneFringe = false;
766  for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
767  NodeSet::iterator check = j;
768  NBNode* n = *check;
769  ++j;
770 
771  // compute clusterDist for node (length of shortest edge which connects this node to the cluster)
772  double clusterDist = std::numeric_limits<double>::max();
773  bool touchingCluster = false;
774  for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
775  NBNode* neighbor = (*it_edge)->getToNode();
776  if (cluster.count(neighbor) != 0) {
777  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
778  touchingCluster |= n->getPosition().distanceTo2D(neighbor->getPosition()) <= SUMO_const_laneWidth;
779  }
780  }
781  for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
782  NBNode* neighbor = (*it_edge)->getFromNode();
783  if (cluster.count(neighbor) != 0) {
784  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
785  touchingCluster |= n->getPosition().distanceTo2D(neighbor->getPosition()) <= SUMO_const_laneWidth;
786  }
787  }
788  // remove geometry-like nodes at fringe of the cluster
789  // (they have 1 neighbor in the cluster and at most 1 neighbor outside the cluster)
790  std::set<NBNode*> outsideNeighbors;
791  std::set<NBNode*> clusterNeighbors;
792  const double pedestrianFringeThreshold = 0.3;
793  for (NBEdge* e : n->getEdges()) {
794  NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
795  if (cluster.count(neighbor) == 0) {
796  if ((e->getPermissions() & SVC_PASSENGER) != 0
797  || isRailway(e->getPermissions()) // join railway crossings
798  || clusterDist <= pedestrianFringeThreshold
799  || touchingCluster) {
800  outsideNeighbors.insert(neighbor);
801  }
802  } else {
803  clusterNeighbors.insert(neighbor);
804  }
805  }
806 #ifdef DEBUG_JOINJUNCTIONS
807  if (DEBUGCOND(n)) std::cout << " check n=" << n->getID()
808  << " clusterDist=" << clusterDist
809  << " cd<th=" << (clusterDist <= pedestrianFringeThreshold)
810  << " touching=" << touchingCluster
811  << " out=" << joinNamedToString(outsideNeighbors, ',')
812  << " in=" << joinNamedToString(clusterNeighbors, ',')
813  << "\n";
814 #endif
815  if (outsideNeighbors.size() <= 1
816  && clusterNeighbors.size() == 1
817  && !n->isTLControlled()) {
818  cluster.erase(check);
819  pruneFringe = true; // other nodes could belong to the fringe now
820 #ifdef DEBUG_JOINJUNCTIONS
821  if (DEBUGCOND(n)) {
822  std::cout << " pruned n=" << n->getID() << "\n";
823  }
824 #endif
825  }
826  }
827  }
828 }
829 
830 
831 bool
832 NBNodeCont::feasibleCluster(const NodeSet& cluster, const NBEdgeCont& ec, const NBPTStopCont& sc, std::string& reason) const {
833  // check for clusters which are to complex and probably won't work very well
834  // we count the incoming edges of the final junction
835  std::map<std::string, double> finalIncomingAngles;
836  std::map<std::string, double> finalOutgoingAngles;
837  for (NodeSet::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
838  for (EdgeVector::const_iterator it_edge = (*j)->getIncomingEdges().begin(); it_edge != (*j)->getIncomingEdges().end(); ++it_edge) {
839  NBEdge* edge = *it_edge;
840  if (cluster.count(edge->getFromNode()) == 0 && (edge->getPermissions() & SVC_PASSENGER) != 0) {
841  // incoming edge, does not originate in the cluster
842  finalIncomingAngles[edge->getID()] = edge->getAngleAtNode(edge->getToNode());
843  }
844  }
845  for (EdgeVector::const_iterator it_edge = (*j)->getOutgoingEdges().begin(); it_edge != (*j)->getOutgoingEdges().end(); ++it_edge) {
846  NBEdge* edge = *it_edge;
847  if (cluster.count(edge->getToNode()) == 0 && (edge->getPermissions() & SVC_PASSENGER) != 0) {
848  // outgoing edge, does not end in the cluster
849  finalOutgoingAngles[edge->getID()] = edge->getAngleAtNode(edge->getFromNode());
850  }
851  }
852 
853  }
854 #ifdef DEBUG_JOINJUNCTIONS
855  for (NBNode* n : cluster) {
856  if (DEBUGCOND(n)) {
857  std::cout << "feasibleCluster c=" << joinNamedToString(cluster, ',')
858  << "\n inAngles=" << joinToString(finalIncomingAngles, ' ', ':')
859  << "\n outAngles=" << joinToString(finalOutgoingAngles, ' ', ':')
860  << "\n";
861  }
862  }
863 #endif
864  if (finalIncomingAngles.size() > 4) {
865  reason = toString(finalIncomingAngles.size()) + " incoming edges";
866  return false;
867  }
868  // check for incoming parallel edges
869  const double PARALLEL_INCOMING_THRESHOLD = 10.0;
870  bool foundParallel = false;
871  for (std::map<std::string, double>::const_iterator j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
872  std::map<std::string, double>::const_iterator k = j;
873  for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
874  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
875  reason = "parallel incoming " + j->first + "," + k->first;
876  return false;
877  }
878  }
879  }
880  // check for outgoing parallel edges
881  for (std::map<std::string, double>::const_iterator j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
882  std::map<std::string, double>::const_iterator k = j;
883  for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
884  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
885  reason = "parallel outgoing " + j->first + "," + k->first;
886  return false;
887  }
888  }
889  }
890  // check for stop edges within the cluster
891  if (OptionsCont::getOptions().isSet("ptstop-output")) {
892  for (auto it = sc.begin(); it != sc.end(); it++) {
893  NBEdge* edge = ec.retrieve(it->second->getEdgeId());
894  if (edge != nullptr && cluster.count(edge->getFromNode()) != 0 && cluster.count(edge->getToNode()) != 0) {
895  reason = "it contains stop '" + it->first + "'";
896  return false;
897  }
898  }
899  }
900  int numTLS = 0;
901  for (NBNode* n : cluster) {
902  if (n->isTLControlled()) {
903  numTLS++;
904  };
905  }
906  const bool hasTLS = numTLS > 0;
907  // prevent removal of long edges unless there is weak circle or a traffic light
908  if (cluster.size() > 2) {
909  // find the nodes with the biggests physical distance between them
910  double maxDist = -1;
911  NBEdge* maxEdge = nullptr;
912  for (NBNode* n1 : cluster) {
913  for (NBNode* n2 : cluster) {
914  NBEdge* e1 = n1->getConnectionTo(n2);
915  NBEdge* e2 = n2->getConnectionTo(n1);
916  if (e1 != nullptr && e1->getLoadedLength() > maxDist) {
917  maxDist = e1->getLoadedLength();
918  maxEdge = e1;
919  }
920  if (e2 != nullptr && e2->getLoadedLength() > maxDist) {
921  maxDist = e2->getLoadedLength();
922  maxEdge = e2;
923  }
924  }
925  }
926 #ifdef DEBUG_JOINJUNCTIONS
927  for (NBNode* n : cluster) {
928  if (DEBUGCOND(n)) {
929  std::cout << "feasible hasTLS=" << hasTLS << " maxDist=" << maxDist << " maxEdge=" << maxEdge->getID() << "\n";
930  }
931  }
932 #endif
933  if (!hasTLS && maxDist > 5) {
934  // find a weak circle within cluster that does not use maxEdge
935  std::vector<NBNode*> toCheck;
936  std::set<NBNode*> visited;
937  toCheck.push_back(maxEdge->getToNode());
938  bool foundCircle = false;
939  while (!toCheck.empty()) {
940  NBNode* n = toCheck.back();
941  if (n == maxEdge->getFromNode()) {
942  foundCircle = true;
943  break;
944  }
945  toCheck.pop_back();
946  visited.insert(n);
947  for (NBEdge* e : n->getEdges()) {
948  if (e != maxEdge) {
949  NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
950  if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
951  toCheck.push_back(cand);
952  }
953  }
954  }
955  }
956  if (!foundCircle) {
957  reason = "not compact (maxEdge=" + maxEdge->getID() + " length=" + toString(maxDist) + ")";
958  return false;
959  }
960  }
961  }
962  // prevent joining of simple merging/spreading structures
963  if (!hasTLS && cluster.size() >= 2) {
964  int entryNodes = 0;
965  int exitNodes = 0;
966  int outsideIncoming = 0;
967  int outsideOutgoing = 0;
968  int edgesWithin = 0;
969  for (NBNode* n : cluster) {
970  bool foundOutsideIncoming = false;
971  for (NBEdge* e : n->getIncomingEdges()) {
972  if (cluster.count(e->getFromNode()) == 0) {
973  // edge entering from outside the cluster
974  outsideIncoming++;
975  foundOutsideIncoming = true;
976  } else {
977  edgesWithin++;
978  }
979  }
980  if (foundOutsideIncoming) {
981  entryNodes++;
982  }
983  bool foundOutsideOutgoing = false;
984  for (NBEdge* e : n->getOutgoingEdges()) {
985  if (cluster.count(e->getToNode()) == 0) {
986  // edge leaving cluster
987  outsideOutgoing++;
988  foundOutsideOutgoing = true;
989  }
990  }
991  if (foundOutsideOutgoing) {
992  exitNodes++;
993  }
994  }
995  if (entryNodes < 2) {
996  reason = "only 1 entry node";
997  return false;
998  }
999  if (exitNodes < 2) {
1000  reason = "only 1 exit node";
1001  return false;
1002  }
1003  if (cluster.size() == 2) {
1004  if (edgesWithin == 1 && outsideIncoming < 3 && outsideOutgoing < 3) {
1005  reason = "only 1 edge within and no cross-traffic";
1006  return false;
1007  }
1008  }
1009  }
1010  return true;
1011 }
1012 
1013 
1014 bool
1015 NBNodeCont::reduceToCircle(NodeSet& cluster, int circleSize, NodeSet startNodes, std::vector<NBNode*> cands) const {
1016  //std::cout << " cs=" << circleSize << " cands=" << toString(cands) << " startNodes=" << toString(startNodes) << "\n";
1017  assert(circleSize >= 2);
1018  if ((int)cands.size() == circleSize) {
1019  if (cands.back()->getConnectionTo(cands.front()) != nullptr) {
1020  // cluster found
1021  cluster.clear();
1022  cluster.insert(cands.begin(), cands.end());
1023  return true;
1024  } else {
1025  return false;
1026  }
1027  }
1028  if ((int)cluster.size() <= circleSize || startNodes.size() == 0) {
1029  // no reduction possible
1030  return false;
1031  }
1032  if (cands.size() == 0) {
1033  // try to find a circle starting from another start node
1034  NBEdge* e = shortestEdge(cluster, startNodes, cands);
1035  if (e != nullptr) {
1036  cands.push_back(e->getFromNode());
1037  startNodes.erase(e->getFromNode());
1038  if (reduceToCircle(cluster, circleSize, startNodes, cands)) {
1039  return true;
1040  } else {
1041  // try another start node
1042  return reduceToCircle(cluster, circleSize, startNodes);
1043  }
1044  }
1045  } else {
1046  NodeSet singleStart;
1047  singleStart.insert(cands.back());
1048  NBEdge* e = shortestEdge(cluster, singleStart, cands);
1049  if (e != nullptr) {
1050  std::vector<NBNode*> cands2(cands);
1051  cands2.push_back(e->getToNode());
1052  if (reduceToCircle(cluster, circleSize, startNodes, cands2)) {
1053  return true;
1054  }
1055  }
1056  }
1057  return false;
1058 }
1059 
1060 
1061 NBEdge*
1062 NBNodeCont::shortestEdge(const NodeSet& cluster, const NodeSet& startNodes, const std::vector<NBNode*>& exclude) const {
1063  double minDist = std::numeric_limits<double>::max();
1064  NBEdge* result = nullptr;
1065  for (NBNode* n : startNodes) {
1066  for (NBEdge* e : n->getOutgoingEdges()) {
1067  NBNode* neigh = e->getToNode();
1068  if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
1069  const double dist = n->getPosition().distanceTo2D(neigh->getPosition());
1070  //std::cout << " e=" << e->getID() << " dist=" << dist << " minD=" << minDist << "\n";
1071  if (dist < minDist) {
1072  minDist = dist;
1073  result = e;
1074  }
1075  }
1076  }
1077  }
1078  //std::cout << "closestNeighbor startNodes=" << toString(startNodes) << " result=" << Named::getIDSecure(result) << "\n";
1079  return result;
1080 }
1081 
1082 void
1085  for (NodeSet cluster : clusters) {
1086  joinNodeCluster(cluster, dc, ec, tlc);
1087  }
1088 }
1089 
1090 
1091 void
1093  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1094  assert(cluster.size() > 1);
1095  Position pos;
1096  bool setTL;
1097  std::string id = "cluster";
1098  TrafficLightType type;
1099  SumoXMLNodeType nodeType = NODETYPE_UNKNOWN;
1100  analyzeCluster(cluster, id, pos, setTL, type, nodeType);
1101  NBNode* newNode = nullptr;
1102  if (predefined != nullptr) {
1103  newNode = predefined;
1104  } else {
1105  if (!insert(id, pos)) {
1106  // should not fail
1107  WRITE_WARNING("Could not join junctions " + id);
1108  return;;
1109  }
1110  newNode = retrieve(id);
1111  }
1112  std::string tlID = id;
1113  if (predefined != nullptr) {
1114  if (predefined->getType() != NODETYPE_UNKNOWN) {
1115  nodeType = predefined->getType();
1116  }
1117  Position ppos = predefined->getPosition();
1118  if (ppos.x() != Position::INVALID.x()) {
1119  pos.setx(ppos.x());
1120  }
1121  if (ppos.y() != Position::INVALID.y()) {
1122  pos.sety(ppos.y());
1123  }
1124  if (ppos.z() != Position::INVALID.z()) {
1125  pos.setz(ppos.z());
1126  }
1127  }
1128  newNode->reinit(pos, nodeType);
1129  if (setTL && !newNode->isTLControlled()) {
1130  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(tlID, newNode, 0, type);
1131  if (!tlc.insert(tlDef)) {
1132  // actually, nothing should fail here
1133  delete tlDef;
1134  throw ProcessError("Could not allocate tls '" + id + "'.");
1135  }
1136  }
1137  // collect edges
1138  EdgeSet allEdges;
1139  for (NBNode* n : cluster) {
1140  const EdgeVector& edges = n->getEdges();
1141  allEdges.insert(edges.begin(), edges.end());
1142  }
1143  // determine edges with are incoming or fully inside
1144  EdgeSet clusterIncoming;
1145  EdgeSet inside;
1146  for (NBEdge* e : allEdges) {
1147  if (cluster.count(e->getToNode()) > 0) {
1148  if (cluster.count(e->getFromNode()) > 0) {
1149  inside.insert(e);
1150  } else {
1151  clusterIncoming.insert(e);
1152  }
1153  }
1154  }
1155 #ifdef DEBUG_JOINJUNCTIONS
1156  std::cout << "joining cluster " << joinNamedToString(cluster, ' ') << "\n"
1157  << " incoming=" << toString(clusterIncoming) << "\n"
1158  << " inside=" << toString(inside) << "\n";
1159 #endif
1160 
1161  // determine possible connectivity from outside edges
1162  std::map<NBEdge*, EdgeSet> reachable;
1163  for (NBEdge* e : clusterIncoming) {
1164  EdgeVector open;
1165  EdgeSet seen;
1166  open.push_back(e);
1167  while (open.size() > 0) {
1168  NBEdge* cur = open.back();
1169  //std::cout << " e=" << e->getID() << " cur=" << cur->getID() << " open=" << toString(open) << "\n";
1170  seen.insert(cur);
1171  open.pop_back();
1172  if (cluster.count(cur->getToNode()) == 0) {
1173  //std::cout << " continue\n";
1174  continue;
1175  }
1176  const auto& cons = cur->getConnections();
1177  if (cons.size() == 0 || ec.hasPostProcessConnection(cur->getID()) || cur->getStep() == NBEdge::INIT) {
1178  // check permissions to determine reachability
1179  for (NBEdge* out : cur->getToNode()->getOutgoingEdges()) {
1180  if (seen.count(out) == 0
1181  && allEdges.count(out) != 0
1182  && (out->getPermissions() & cur->getPermissions() & ~SVC_PEDESTRIAN) != 0) {
1183  open.push_back(out);
1184  }
1185  }
1186  } else {
1187  // check existing connections
1188  for (const auto& con : cons) {
1189  if (con.toEdge != nullptr
1190  && seen.count(con.toEdge) == 0
1191  && allEdges.count(con.toEdge) != 0) {
1192  open.push_back(con.toEdge);
1193  }
1194  }
1195  }
1196  }
1197  seen.erase(e);
1198  for (NBEdge* reached : seen) {
1199  // filter out inside edges from reached
1200  if (inside.count(reached) == 0) {
1201  reachable[e].insert(reached);
1202  }
1203  }
1204 #ifdef DEBUG_JOINJUNCTIONS
1205  std::cout << " reachable e=" << e->getID() << " seen=" << toString(seen) << " reachable=" << toString(reachable[e]) << "\n";
1206 #endif
1207  }
1208 
1209  // remap and remove edges which are completely within the new intersection
1210  for (NBEdge* e : inside) {
1211  for (NBEdge* e2 : allEdges) {
1212  if (e != e2) {
1213  e2->replaceInConnections(e, e->getConnections());
1214  }
1215  }
1216  ec.extract(dc, e, true);
1217  allEdges.erase(e);
1218  }
1219 
1220  // remap edges which are incoming / outgoing
1221  for (NBEdge* e : allEdges) {
1222  std::vector<NBEdge::Connection> conns = e->getConnections();
1223  const bool outgoing = cluster.count(e->getFromNode()) > 0;
1224  NBNode* from = outgoing ? newNode : e->getFromNode();
1225  NBNode* to = outgoing ? e->getToNode() : newNode;
1226  if (origNames) {
1227  if (outgoing) {
1228  e->setParameter("origFrom", e->getFromNode()->getID());
1229  } else {
1230  e->setParameter("origTo", e->getToNode()->getID());
1231  }
1232  }
1233  e->reinitNodes(from, to);
1234  // re-add connections which previously existed and may still valid.
1235  // connections to removed edges will be ignored
1236  for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1237  e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass);
1238  if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1239  // @note (see NIImporter_DlrNavteq::ConnectedLanesHandler)
1240  e->declareConnectionsAsLoaded(NBEdge::INIT);
1241  }
1242  }
1243  }
1244  // disable connections that were impossible with the old topology
1245  for (NBEdge* in : newNode->getIncomingEdges()) {
1246  for (NBEdge* out : newNode->getOutgoingEdges()) {
1247  if (reachable[in].count(out) == 0 && !ec.hasPostProcessConnection(in->getID(), out->getID())) {
1248  //std::cout << " removeUnreachable in=" << in->getID() << " out=" << out->getID() << "\n";
1249  in->removeFromConnections(out, -1, -1, true, false, true);
1250  }
1251  }
1252  }
1253 
1254  // remove original nodes
1255  registerJoinedCluster(cluster);
1256  for (NBNode* n : cluster) {
1257  erase(n);
1258  }
1259 }
1260 
1261 
1262 void
1264  std::set<std::string> ids;
1265  for (NBNode* n : cluster) {
1266  ids.insert(n->getID());
1267  }
1268  myJoinedClusters.push_back(ids);
1269 }
1270 
1271 
1272 void
1273 NBNodeCont::analyzeCluster(NodeSet cluster, std::string& id, Position& pos,
1274  bool& hasTLS, TrafficLightType& type, SumoXMLNodeType& nodeType) {
1275  id += "_" + joinNamedToString(cluster, '_');
1276  hasTLS = false;
1277  bool ambiguousType = false;
1278  for (NBNode* j : cluster) {
1279  pos.add(j->getPosition());
1280  // add a traffic light if any of the cluster members was controlled
1281  if (j->isTLControlled()) {
1282  if (!hasTLS) {
1283  // init type
1284  type = (*j->getControllingTLS().begin())->getType();
1285  } else if (type != (*j->getControllingTLS().begin())->getType()) {
1286  ambiguousType = true;
1287  }
1288  hasTLS = true;
1289  }
1290  SumoXMLNodeType otherType = j->getType();
1291  if (nodeType == NODETYPE_UNKNOWN) {
1292  nodeType = otherType;
1293  } else if (nodeType != otherType) {
1294  if (hasTLS) {
1295  nodeType = NODETYPE_TRAFFIC_LIGHT;;
1296  } else {
1297  if ((nodeType != NODETYPE_PRIORITY && (nodeType != NODETYPE_NOJUNCTION || otherType != NODETYPE_PRIORITY))
1298  || (otherType != NODETYPE_NOJUNCTION && otherType != NODETYPE_UNKNOWN && otherType != NODETYPE_PRIORITY)) {
1299  WRITE_WARNING("Ambiguous node type for node cluster '" + id + "' (" + toString(nodeType) + "," + toString(otherType) + ") set to '" + toString(NODETYPE_PRIORITY) + "'");
1300  }
1301  nodeType = NODETYPE_PRIORITY;
1302  }
1303  }
1304  }
1305  pos.mul(1.0 / cluster.size());
1306  if (ambiguousType) {
1307  type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
1308  WRITE_WARNING("Ambiguous traffic light type for node cluster '" + id + "' set to '" + toString(type) + "'");
1309  }
1310 }
1311 
1312 
1313 // ----------- (Helper) methods for guessing/computing traffic lights
1314 bool
1315 NBNodeCont::shouldBeTLSControlled(const NodeSet& c, double laneSpeedThreshold) const {
1316  int noIncoming = 0;
1317  int noOutgoing = 0;
1318  bool tooFast = false;
1319  double f = 0;
1320  std::set<NBEdge*> seen;
1321  for (NBNode* j : c) {
1322  const EdgeVector& edges = j->getEdges();
1323  for (EdgeVector::const_iterator k = edges.begin(); k != edges.end(); ++k) {
1324  if (c.find((*k)->getFromNode()) != c.end() && c.find((*k)->getToNode()) != c.end()) {
1325  continue;
1326  }
1327  if (j->hasIncoming(*k)) {
1328  ++noIncoming;
1329  f += (double)(*k)->getNumLanes() * (*k)->getLaneSpeed(0);
1330  } else {
1331  ++noOutgoing;
1332  }
1333  if ((*k)->getLaneSpeed(0) * 3.6 > 79) {
1334  tooFast = true;
1335  }
1336  }
1337  }
1338  //std::cout << " c=" << joinNamedToString(c, ' ') << " f=" << f << " size=" << c.size() << " thresh=" << laneSpeedThreshold << " tooFast=" << tooFast << "\n";
1339  return !tooFast && f >= laneSpeedThreshold && c.size() != 0;
1340 }
1341 
1342 bool
1344  // check whether all component nodes are solely pedestrian crossings
1345  // (these work fine without joining)
1346  for (NBNode* node : c) {
1347  EdgeVector nonPedIncoming;
1348  EdgeVector nonPedOutgoing;
1349  for (NBEdge* e : node->getIncomingEdges()) {
1350  if (e->getPermissions() != SVC_PEDESTRIAN) {
1351  nonPedIncoming.push_back(e);
1352  }
1353  }
1354  for (NBEdge* e : node->getOutgoingEdges()) {
1355  if (e->getPermissions() != SVC_PEDESTRIAN) {
1356  nonPedOutgoing.push_back(e);
1357  }
1358  }
1359  if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
1360  //for (NBNode* node : c) {
1361  // if (node->getID() == "2480337678") {
1362  // std::cout << " node=" << node->getID() << " nonPedIncoming=" << toString(nonPedIncoming) << " nonPedOutgoing=" << toString(nonPedOutgoing) << "\n";
1363  // }
1364  //}
1365  return false;
1366  }
1367  }
1368  return true;
1369 }
1370 
1371 
1372 bool
1374  for (NBNode* node : c) {
1375  if (node->isTLControlled()) {
1376  const std::string tlID = (*node->getControllingTLS().begin())->getID();
1377  if (tlID != node->getID()
1378  && !StringUtils::startsWith(tlID, "joinedS_")
1379  && !StringUtils::startsWith(tlID, "joinedG_")
1380  && !StringUtils::startsWith(tlID, "GS")) {
1381  return true;
1382  }
1383  }
1384  }
1385  return false;
1386 }
1387 
1388 
1389 void
1391  // build list of definitely not tls-controlled junctions
1392  const double laneSpeedThreshold = oc.getFloat("tls.guess.threshold");
1393  std::vector<NBNode*> ncontrolled;
1394  if (oc.isSet("tls.unset")) {
1395  std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset");
1396  for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
1397  NBNode* n = NBNodeCont::retrieve(*i);
1398  if (n == nullptr) {
1399  throw ProcessError(" The junction '" + *i + "' to set as not-controlled is not known.");
1400  }
1401  std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS();
1402  for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
1403  (*j)->removeNode(n);
1404  }
1405  n->removeTrafficLights();
1406  ncontrolled.push_back(n);
1407  }
1408  }
1409 
1411  // loop#1 checking whether the node shall be tls controlled,
1412  // because it is assigned to a district
1413  if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) {
1414  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1415  NBNode* cur = (*i).second;
1416  if (cur->isNearDistrict() && std::find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) {
1417  setAsTLControlled(cur, tlc, type);
1418  }
1419  }
1420  }
1421 
1422  // figure out which nodes mark the locations of TLS signals
1423  // This assumes nodes are already joined
1424  if (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals")) {
1425  // prepare candidate edges
1426  const double signalDist = oc.getFloat("tls.guess-signals.dist");
1427  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1428  NBNode* node = (*i).second;
1429  if (node->isTLControlled() && node->geometryLike()) {
1430  std::set<NBEdge*> seen;
1431  std::set<std::pair<NBEdge*, double> > check;
1432  for (NBEdge* edge : node->getOutgoingEdges()) {
1433  double offset = edge->getLength();
1434  edge->setSignalOffset(offset, node);
1435  seen.insert(edge);
1436  check.insert(std::make_pair(edge, offset));
1437  }
1438  // propagate signalOffset until the next real intersection
1439  while (check.size() > 0) {
1440  NBEdge* edge = check.begin()->first;
1441  const double offset = check.begin()->second;
1442  check.erase(check.begin());
1443  NBNode* nextNode = edge->getToNode();
1444  if (nextNode->geometryLike() && !nextNode->isTLControlled()) {
1445  for (NBEdge* edge : nextNode->getOutgoingEdges()) {
1446  if (seen.count(edge) == 0) {
1447  double offset2 = offset + edge->getLength();
1448  edge->setSignalOffset(offset2, node);
1449  seen.insert(edge);
1450  check.insert(std::make_pair(edge, offset2));
1451  }
1452  }
1453  }
1454  }
1455  }
1456  }
1457  // check which nodes should be controlled
1458  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1459  NBNode* node = i->second;
1460  if (find(ncontrolled.begin(), ncontrolled.end(), node) != ncontrolled.end()) {
1461  continue;
1462  }
1463  const EdgeVector& incoming = node->getIncomingEdges();
1464  const EdgeVector& outgoing = node->getOutgoingEdges();
1465  if (!node->isTLControlled() && incoming.size() > 1 && !node->geometryLike()
1467  && node->getType() != NODETYPE_RAIL_CROSSING) {
1468  std::vector<NBNode*> signals;
1469  bool isTLS = true;
1470  for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
1471  const NBEdge* inEdge = *it_i;
1472  if ((inEdge->getSignalOffset() == NBEdge::UNSPECIFIED_SIGNAL_OFFSET || inEdge->getSignalOffset() > signalDist)
1473  && inEdge->getPermissions() != SVC_TRAM) {
1474  //if (node->getID() == "cluster_2292787672_259083790") std::cout << " noTLS, edge=" << inEdge->getID() << " offset=" << inEdge->getSignalOffset() << "\n";
1475  isTLS = false;
1476  break;
1477  }
1478  NBNode* signal = inEdge->getSignalNode();
1479  if (signal != nullptr) {
1480  //if (true || node->getID() == "cluster_2648427269_3180391961_3180391964_736234762") std::cout << " edge=" << inEdge->getID() << " signalNode=" << signal->getID() << " offset=" << inEdge->getSignalOffset() << "\n";
1481  signals.push_back(signal);
1482  }
1483  }
1484  // outgoing edges may be tagged with pedestrian crossings. These
1485  // should also be merged into the main TLS
1486  for (EdgeVector::const_iterator it_i = outgoing.begin(); it_i != outgoing.end(); ++it_i) {
1487  const NBEdge* outEdge = *it_i;
1488  NBNode* cand = outEdge->getToNode();
1489  if (cand->isTLControlled() && cand->geometryLike() && outEdge->getLength() <= signalDist) {
1490  //if (true || node->getID() == "cluster_2648427269_3180391961_3180391964_736234762") std::cout << " node=" << node->getID() << " outEdge=" << outEdge->getID() << " signalNode=" << cand->getID() << " len=" << outEdge->getLength() << "\n";
1491  signals.push_back(cand);
1492  }
1493  }
1494  if (isTLS) {
1495  for (std::vector<NBNode*>::iterator j = signals.begin(); j != signals.end(); ++j) {
1496  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
1497  (*j)->reinit((*j)->getPosition(), NODETYPE_PRIORITY);
1498  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
1499  tlc.removeFully((*j)->getID());
1500  }
1501  }
1502  //if (true) std::cout << " node=" << node->getID() << " signals=" << toString(signals) << "\n";
1503  NBTrafficLightDefinition* tlDef = new NBOwnTLDef("GS_" + node->getID(), node, 0, type);
1504  // @todo patch endOffset for all incoming lanes according to the signal positions
1505  if (!tlc.insert(tlDef)) {
1506  // actually, nothing should fail here
1507  WRITE_WARNING("Could not build joined tls '" + node->getID() + "'.");
1508  delete tlDef;
1509  return;
1510  }
1511  }
1512  }
1513  }
1514  }
1515 
1516  // guess joined tls first, if wished
1517  if (oc.getBool("tls.guess.joining")) {
1518  // get node clusters
1519  NodeClusters cands;
1520  generateNodeClusters(oc.getFloat("tls.join-dist"), cands);
1521  // check these candidates (clusters) whether they should be controlled by a tls
1522  for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
1523  NodeSet& c = (*i);
1524  // regard only junctions which are not yet controlled and are not
1525  // forbidden to be controlled
1526  for (NodeSet::iterator j = c.begin(); j != c.end();) {
1527  if ((*j)->isTLControlled() || std::find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) {
1528  c.erase(j++);
1529  } else {
1530  ++j;
1531  }
1532  }
1533  // check whether the cluster should be controlled
1534  // to avoid gigantic clusters, assume that at most 4 nodes should be needed for a guessed-joined-tls
1535  if (c.size() == 0 || !shouldBeTLSControlled(c, laneSpeedThreshold * c.size() / MIN2((int)c.size(), 4))) {
1536  i = cands.erase(i);
1537  } else {
1538  ++i;
1539  }
1540  }
1541  // cands now only contain sets of junctions that shall be joined into being tls-controlled
1542  int index = 0;
1543  for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
1544  std::vector<NBNode*> nodes;
1545  for (NodeSet::iterator j = (*i).begin(); j != (*i).end(); j++) {
1546  nodes.push_back(*j);
1547  }
1548  std::string id = "joinedG_" + toString(index++);
1549  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1550  if (!tlc.insert(tlDef)) {
1551  // actually, nothing should fail here
1552  WRITE_WARNING("Could not build guessed, joined tls");
1553  delete tlDef;
1554  return;
1555  }
1556  }
1557  }
1558 
1559  // guess single tls
1560  if (oc.getBool("tls.guess")) {
1561  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1562  NBNode* cur = (*i).second;
1563  // do nothing if already is tl-controlled
1564  if (cur->isTLControlled()) {
1565  continue;
1566  }
1567  // do nothing if in the list of explicit non-controlled junctions
1568  if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) {
1569  continue;
1570  }
1571  NodeSet c;
1572  c.insert(cur);
1573  if (!shouldBeTLSControlled(c, laneSpeedThreshold) || cur->geometryLike()) {
1574  continue;
1575  }
1576  setAsTLControlled((*i).second, tlc, type);
1577  }
1578  }
1579 }
1580 
1581 
1582 void
1584  NodeClusters cands;
1585  generateNodeClusters(maxdist, cands);
1586  IDSupplier idSupplier("joinedS_");
1587  for (NodeSet& c : cands) {
1588  for (NodeSet::iterator j = c.begin(); j != c.end();) {
1589  if (!(*j)->isTLControlled()) {
1590  c.erase(j++);
1591  } else {
1592  ++j;
1593  }
1594  }
1595  if (c.size() < 2 || onlyCrossings(c) || customTLID(c)) {
1596  continue;
1597  }
1598  // figure out type of the joined TLS
1599  Position dummyPos;
1600  bool dummySetTL;
1601  std::string id = "joined"; // prefix (see #3871)
1602  TrafficLightType type;
1603  SumoXMLNodeType nodeType = NODETYPE_UNKNOWN;
1604  analyzeCluster(c, id, dummyPos, dummySetTL, type, nodeType);
1605  for (NBNode* j : c) {
1606  std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
1607  j->removeTrafficLights();
1608  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
1609  tlc.removeFully(j->getID());
1610  }
1611  }
1612  std::vector<NBNode*> nodes;
1613  for (NBNode* j : c) {
1614  nodes.push_back(j);
1615  }
1616  id = idSupplier.getNext();
1617  while (tlc.getPrograms(id).size() > 0) {
1618  id = idSupplier.getNext();
1619  }
1620  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1621  if (!tlc.insert(tlDef)) {
1622  // actually, nothing should fail here
1623  WRITE_WARNING("Could not build a joined tls.");
1624  delete tlDef;
1625  return;
1626  }
1627  }
1628 }
1629 
1630 
1631 void
1633  TrafficLightType type, std::string id) {
1634  if (id == "") {
1635  id = node->getID();
1636  }
1637  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node, 0, type);
1638  if (!tlc.insert(tlDef)) {
1639  // actually, nothing should fail here
1640  WRITE_WARNING("Building a tl-logic for junction '" + id + "' twice is not possible.");
1641  delete tlDef;
1642  return;
1643  }
1644 }
1645 
1646 
1647 // -----------
1648 void
1650  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1651  (*i).second->computeLanes2Lanes();
1652  }
1653 }
1654 
1655 
1656 // computes the "wheel" of incoming and outgoing edges for every node
1657 void
1659  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1660  (*i).second->computeLogic(ec, oc);
1661  }
1662 }
1663 
1664 
1665 void
1667  std::set<NBNode*> roundaboutNodes;
1668  const bool checkLaneFoesAll = oc.getBool("check-lane-foes.all");
1669  const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.getBool("check-lane-foes.roundabout");
1670  if (checkLaneFoesRoundabout) {
1671  const std::set<EdgeSet>& roundabouts = ec.getRoundabouts();
1672  for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
1673  for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
1674  roundaboutNodes.insert((*j)->getToNode());
1675  }
1676  }
1677  }
1678  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1679  const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
1680  (*i).second->computeLogic2(checkLaneFoes);
1681  }
1682 }
1683 
1684 
1685 void
1687  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1688  delete ((*i).second);
1689  }
1690  myNodes.clear();
1691  for (auto& item : myExtractedNodes) {
1692  delete item.second;
1693  }
1694  myExtractedNodes.clear();
1695 }
1696 
1697 
1698 std::string
1700  int counter = 0;
1701  std::string freeID = "SUMOGenerated" + toString<int>(counter);
1702  // While there is a node with id equal to freeID
1703  while (retrieve(freeID) != nullptr) {
1704  // update counter and generate a new freeID
1705  counter++;
1706  freeID = "SUMOGenerated" + toString<int>(counter);
1707  }
1708  return freeID;
1709 }
1710 
1711 
1712 void
1713 NBNodeCont::computeNodeShapes(double mismatchThreshold) {
1714  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1715  (*i).second->computeNodeShape(mismatchThreshold);
1716  }
1717 }
1718 
1719 
1720 void
1722  int numUnregulatedJunctions = 0;
1723  int numDeadEndJunctions = 0;
1724  int numTrafficLightJunctions = 0;
1725  int numPriorityJunctions = 0;
1726  int numRightBeforeLeftJunctions = 0;
1727  int numAllWayStopJunctions = 0;
1728  int numZipperJunctions = 0;
1729  int numDistrictJunctions = 0;
1730  int numRailCrossing = 0;
1731  int numRailSignals = 0;
1732  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1733  switch ((*i).second->getType()) {
1734  case NODETYPE_NOJUNCTION:
1735  ++numUnregulatedJunctions;
1736  break;
1737  case NODETYPE_DEAD_END:
1738  ++numDeadEndJunctions;
1739  break;
1743  ++numTrafficLightJunctions;
1744  break;
1745  case NODETYPE_PRIORITY:
1747  ++numPriorityJunctions;
1748  break;
1750  ++numRightBeforeLeftJunctions;
1751  break;
1752  case NODETYPE_ALLWAY_STOP:
1753  ++numAllWayStopJunctions;
1754  break;
1755  case NODETYPE_ZIPPER:
1756  ++numZipperJunctions;
1757  break;
1758  case NODETYPE_DISTRICT:
1759  ++numDistrictJunctions;
1760  break;
1762  ++numRailCrossing;
1763  break;
1764  case NODETYPE_RAIL_SIGNAL:
1765  ++numRailSignals;
1766  break;
1767  case NODETYPE_UNKNOWN:
1768  // should not happen
1769  break;
1770  default:
1771  break;
1772  }
1773  }
1774  WRITE_MESSAGE(" Node type statistics:");
1775  WRITE_MESSAGE(" Unregulated junctions : " + toString(numUnregulatedJunctions));
1776  if (numDeadEndJunctions > 0) {
1777  WRITE_MESSAGE(" Dead-end junctions : " + toString(numDeadEndJunctions));
1778  }
1779  WRITE_MESSAGE(" Priority junctions : " + toString(numPriorityJunctions));
1780  WRITE_MESSAGE(" Right-before-left junctions : " + toString(numRightBeforeLeftJunctions));
1781  if (numTrafficLightJunctions > 0) {
1782  WRITE_MESSAGE(" Traffic light junctions : " + toString(numTrafficLightJunctions));
1783  }
1784  if (numAllWayStopJunctions > 0) {
1785  WRITE_MESSAGE(" All-way stop junctions : " + toString(numAllWayStopJunctions));
1786  }
1787  if (numZipperJunctions > 0) {
1788  WRITE_MESSAGE(" Zipper-merge junctions : " + toString(numZipperJunctions));
1789  }
1790  if (numRailCrossing > 0) {
1791  WRITE_MESSAGE(" Rail crossing junctions : " + toString(numRailCrossing));
1792  }
1793  if (numRailSignals > 0) {
1794  WRITE_MESSAGE(" Rail signal junctions : " + toString(numRailSignals));
1795  }
1796  if (numDistrictJunctions > 0) {
1797  WRITE_MESSAGE(" District junctions : " + toString(numDistrictJunctions));
1798  }
1799 }
1800 
1801 
1802 std::vector<std::string>
1804  std::vector<std::string> ret;
1805  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1806  ret.push_back((*i).first);
1807  }
1808  return ret;
1809 }
1810 
1811 
1812 void
1813 NBNodeCont::rename(NBNode* node, const std::string& newID) {
1814  if (myNodes.count(newID) != 0) {
1815  throw ProcessError("Attempt to rename node using existing id '" + newID + "'");
1816  }
1817  myNodes.erase(node->getID());
1818  node->setID(newID);
1819  myNodes[newID] = node;
1820 }
1821 
1822 
1823 void
1824 NBNodeCont::discardTrafficLights(NBTrafficLightLogicCont& tlc, bool geometryLike, bool guessSignals) {
1825  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1826  NBNode* node = i->second;
1827  if (node->isTLControlled() && (!geometryLike || node->geometryLike())) {
1828  // make a copy of tldefs
1829  const std::set<NBTrafficLightDefinition*> tldefs = node->getControllingTLS();
1830  if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
1831  // do not remove joined tls when only removing geometry-like tls
1832  continue;
1833  }
1834  if (guessSignals && node->isTLControlled() && node->geometryLike()) {
1835  // record signal location
1836  const EdgeVector& outgoing = node->getOutgoingEdges();
1837  for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) {
1838  (*it_o)->setSignalOffset((*it_o)->getLength(), nullptr);
1839  }
1840  }
1841  for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
1842  NBTrafficLightDefinition* tlDef = *it;
1843  node->removeTrafficLight(tlDef);
1844  tlc.extract(tlDef);
1845  }
1847  node->reinit(node->getPosition(), newType);
1848  }
1849  }
1850 }
1851 
1852 
1853 void
1855  for (auto& item : myNodes) {
1856  NBNode* node = item.second;
1857  if (node->getType() == NODETYPE_RAIL_SIGNAL) {
1858  node->reinit(node->getPosition(), NODETYPE_PRIORITY);
1859  }
1860  }
1861 }
1862 
1863 
1864 int
1865 NBNodeCont::remapIDs(bool numericaIDs, bool reservedIDs, const std::string& prefix) {
1866  std::vector<std::string> avoid = getAllNames();
1867  std::set<std::string> reserve;
1868  if (reservedIDs) {
1869  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "node:", reserve); // backward compatibility
1870  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "junction:", reserve); // selection format
1871  avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1872  }
1873  IDSupplier idSupplier("", avoid);
1874  NodeSet toChange;
1875  for (NodeCont::iterator it = myNodes.begin(); it != myNodes.end(); it++) {
1876  if (numericaIDs) {
1877  try {
1878  StringUtils::toLong(it->first);
1879  } catch (NumberFormatException&) {
1880  toChange.insert(it->second);
1881  }
1882  }
1883  if (reservedIDs && reserve.count(it->first) > 0) {
1884  toChange.insert(it->second);
1885  }
1886  }
1887  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1888  for (NBNode* node : toChange) {
1889  myNodes.erase(node->getID());
1890  if (origNames) {
1891  node->setParameter(SUMO_PARAM_ORIGID, node->getID());
1892  }
1893  node->setID(idSupplier.getNext());
1894  myNodes[node->getID()] = node;
1895  }
1896  if (prefix.empty()) {
1897  return (int)toChange.size();
1898  } else {
1899  int renamed = 0;
1900  // make a copy because we will modify the map
1901  auto oldNodes = myNodes;
1902  for (auto item : oldNodes) {
1903  if (!StringUtils::startsWith(item.first, prefix)) {
1904  rename(item.second, prefix + item.first);
1905  renamed++;
1906  }
1907  }
1908  return renamed;
1909  }
1910 }
1911 
1912 /****************************************************************************/
1913 
NBNodeCont::myJoinedClusters
std::vector< std::set< std::string > > myJoinedClusters
sets of node ids which were joined
Definition: NBNodeCont.h:380
NBNodeCont::removeUnwishedNodes
int removeUnwishedNodes(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc, NBPTLineCont &lc, NBParkingCont &pc, bool removeGeometryNodes)
Removes "unwished" nodes.
Definition: NBNodeCont.cpp:370
NBNodeCont::myJoinExclusions
std::set< std::string > myJoinExclusions
set of node ids which should not be joined
Definition: NBNodeCont.h:374
OptionsCont::isSet
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
Definition: OptionsCont.cpp:136
Boundary.h
NODETYPE_PRIORITY
Definition: SUMOXMLDefinitions.h:1056
SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:157
NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED
Definition: SUMOXMLDefinitions.h:1053
ToString.h
NBNodeCont::getFreeID
std::string getFreeID()
generates a new node ID
Definition: NBNodeCont.cpp:1699
NODETYPE_ZIPPER
Definition: SUMOXMLDefinitions.h:1060
MIN2
T MIN2(T a, T b)
Definition: StdDefs.h:74
NBNodeCont::computeNodeShapes
void computeNodeShapes(double mismatchThreshold=-1)
Compute the junction shape for this node.
Definition: NBNodeCont.cpp:1713
NBPTStopCont
Definition: NBPTStopCont.h:28
NBTrafficLightLogicCont::getPrograms
const std::map< std::string, NBTrafficLightDefinition * > & getPrograms(const std::string &id) const
Returns all programs for the given tl-id.
Definition: NBTrafficLightLogicCont.cpp:244
NBEdgeCont::retrieve
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:245
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:239
NBParkingCont::addEdges2Keep
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
Definition: NBParking.cpp:80
NBEdgeCont
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:61
NBNodeCont::rename
void rename(NBNode *node, const std::string &newID)
Renames the node. Throws exception if newID already exists.
Definition: NBNodeCont.cpp:1813
NBNodeCont::setAsTLControlled
void setAsTLControlled(NBNode *node, NBTrafficLightLogicCont &tlc, TrafficLightType type, std::string id="")
Sets the given node as being controlled by a tls.
Definition: NBNodeCont.cpp:1632
NamedRTree::Remove
void Remove(const float a_min[2], const float a_max[2], Named *const &a_data)
Remove entry.
Definition: NamedRTree.h:93
NBNodeCont::computeLanes2Lanes
void computeLanes2Lanes()
divides the incoming lanes on outgoing lanes
Definition: NBNodeCont.cpp:1649
NBNodeCont::myNodes
NodeCont myNodes
The map of names to nodes.
Definition: NBNodeCont.h:368
NBTrafficLightLogicCont
A container for traffic light definitions and built programs.
Definition: NBTrafficLightLogicCont.h:58
NBEdgeCont::erase
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:379
NBEdge::getStep
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:568
NBPTStopCont::addEdges2Keep
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
Definition: NBPTStopCont.cpp:314
Position::z
double z() const
Returns the z-position.
Definition: Position.h:67
Position::INVALID
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:285
OptionsCont.h
NBEdge::getSignalOffset
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.h:626
NBNodeCont::guessTLs
void guessTLs(OptionsCont &oc, NBTrafficLightLogicCont &tlc)
Guesses which junctions or junction clusters shall be controlled by tls.
Definition: NBNodeCont.cpp:1390
NBEdge::getSignalNode
NBNode * getSignalNode() const
Returns the node that (possibly) represents a traffic signal controlling at the end of this edge.
Definition: NBEdge.h:631
Named::StoringVisitor
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:93
Position::setx
void setx(double x)
set position x
Definition: Position.h:72
NBPTStopCont::begin
std::map< std::string, NBPTStop * >::const_iterator begin() const
Returns the pointer to the begin of the stored pt stops.
Definition: NBPTStopCont.h:51
MsgHandler.h
EdgeVector
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
NBNodeCont::myJoined
std::set< std::string > myJoined
ids found in loaded join clusters used for error checking
Definition: NBNodeCont.h:383
NBNodeCont::onlyCrossings
bool onlyCrossings(const NodeSet &c) const
check wheter the set of nodes only contains pedestrian crossings
Definition: NBNodeCont.cpp:1343
NBNodeCont::insert
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:79
NBNodeCont::getAllNames
std::vector< std::string > getAllNames() const
get all node names
Definition: NBNodeCont.cpp:1803
OptionsCont::getString
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
Definition: OptionsCont.cpp:202
NBNode::getOutgoingEdges
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:264
NBNodeCont::NodeAndDist
std::pair< NBNode *, double > NodeAndDist
Definition: NBNodeCont.h:65
TrafficLightType
TrafficLightType
Definition: SUMOXMLDefinitions.h:1192
OptionsCont::exists
bool exists(const std::string &name) const
Returns the information whether the named option is known.
Definition: OptionsCont.cpp:130
NBEdgeCont.h
GeoConvHelper.h
NBNodeCont::begin
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:116
IDSupplier
Definition: IDSupplier.h:38
OptionsCont::getBool
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Definition: OptionsCont.cpp:223
NBOwnTLDef
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:47
NODETYPE_UNKNOWN
Definition: SUMOXMLDefinitions.h:1050
NBNodeCont::removeComponents
void removeComponents(NBDistrictCont &dc, NBEdgeCont &ec, const int numKeep)
Checks the network for weak connectivity and removes all but the largest components....
Definition: NBNodeCont.cpp:312
NBNodeCont::avoidOverlap
void avoidOverlap()
fix overlap
Definition: NBNodeCont.cpp:444
OptionsCont::getOptions
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
NBNode::getType
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:276
SUMO_const_laneWidth
const double SUMO_const_laneWidth
Definition: StdDefs.h:50
NBEdgeCont::getByID
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
Definition: NBEdgeCont.cpp:1009
NBNodeCont::addCluster2Join
void addCluster2Join(std::set< std::string > cluster, NBNode *node)
add ids of nodes which shall be joined into a single node
Definition: NBNodeCont.cpp:581
NBEdge::getPermissions
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3441
NBNodeCont::pruneClusterFringe
void pruneClusterFringe(NodeSet &cluster) const
remove geometry-like fringe nodes from cluster
Definition: NBNodeCont.cpp:754
NBParking.h
NBNodeCont::remapIDs
int remapIDs(bool numericaIDs, bool reservedIDs, const std::string &prefix)
remap node IDs accoring to options –numerical-ids and –reserved-ids
Definition: NBNodeCont.cpp:1865
NBEdge::L2L_USER
The connection was given by the user.
Definition: NBEdge.h:128
NBDistrictCont
A container for districts.
Definition: NBDistrictCont.h:53
NBDistrict.h
NBNodeCont::erase
bool erase(NBNode *node)
Removes the given node, deleting it.
Definition: NBNodeCont.cpp:138
NBEdge
The representation of a single edge during network building.
Definition: NBEdge.h:86
SVC_TRAM
vehicle is a light rail
Definition: SUMOVehicleClass.h:185
NBEdgeCont::joinSameNodeConnectingEdges
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
Definition: NBEdgeCont.cpp:871
NBNode::getPosition
const Position & getPosition() const
Definition: NBNode.h:251
NBNodeCont::analyzeCluster
void analyzeCluster(NodeSet cluster, std::string &id, Position &pos, bool &hasTLS, TrafficLightType &type, SumoXMLNodeType &nodeType)
Definition: NBNodeCont.cpp:1273
NBNodeCont::computeLogics
void computeLogics(const NBEdgeCont &ec, OptionsCont &oc)
build the list of outgoing edges and lanes
Definition: NBNodeCont.cpp:1658
NBNode::checkIsRemovable
bool checkIsRemovable() const
check if node is removable
Definition: NBNode.cpp:2047
NBNode::getEdgesToJoin
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
Definition: NBNode.cpp:2120
NumberFormatException
Definition: UtilExceptions.h:96
NBHelpers::loadPrefixedIDsFomFile
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:106
NODETYPE_ALLWAY_STOP
Definition: SUMOXMLDefinitions.h:1059
NODETYPE_RAIL_SIGNAL
Definition: SUMOXMLDefinitions.h:1054
NBEdge::isNearEnough2BeJoined2
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
Definition: NBEdge.cpp:3131
NBEdge::getToNode
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:486
NBNode::isTLControlled
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:317
NBTrafficLightLogicCont::extract
void extract(NBTrafficLightDefinition *definition)
Extracts a traffic light definition from myDefinitions but keeps it in myExtracted for eventual * del...
Definition: NBTrafficLightLogicCont.cpp:134
NBPTLineCont
Definition: NBPTLineCont.h:27
NBPTLineCont.h
NBNodeCont::removeIsolatedRoads
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
NamedRTree::Insert
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:82
SVCPermissions
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
Definition: SUMOVehicleClass.h:219
NBNodeCont::removeSelfLoops
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
NBNodeCont::joinSimilarEdges
void joinSimilarEdges(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins edges connecting the same nodes.
Definition: NBNodeCont.cpp:179
NODETYPE_PRIORITY_STOP
Definition: SUMOXMLDefinitions.h:1057
NBEdgeCont::hasPostProcessConnection
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
Definition: NBEdgeCont.cpp:1023
SVC_RAIL_CLASSES
classes which drive on tracks
Definition: SUMOVehicleClass.h:205
NODETYPE_TRAFFIC_LIGHT_NOJUNCTION
Definition: SUMOXMLDefinitions.h:1052
NBNodeCont::feasibleCluster
bool feasibleCluster(const NodeSet &cluster, const NBEdgeCont &ec, const NBPTStopCont &sc, std::string &reason) const
determine wether the cluster is not too complex for joining
Definition: NBNodeCont.cpp:832
SumoXMLNodeType
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
Definition: SUMOXMLDefinitions.h:1049
StringBijection::get
T get(const std::string &str) const
Definition: StringBijection.h:98
StringTokenizer
Definition: StringTokenizer.h:62
EdgeSet
std::set< NBEdge * > EdgeSet
container for unique edges
Definition: NBCont.h:50
joinNamedToString
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition: ToString.h:281
NBPTLineCont::addEdges2Keep
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
Definition: NBPTLineCont.cpp:287
SUMO_PARAM_ORIGID
const std::string SUMO_PARAM_ORIGID
NBNode::removeTrafficLight
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:369
NBNodeCont::joinNodeClusters
void joinNodeClusters(NodeClusters clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
joins the given node clusters
Definition: NBNodeCont.cpp:1083
SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
Definition: SUMOVehicleClass.h:160
DEBUGCOND
#define DEBUGCOND(obj)
Definition: NBNodeCont.cpp:62
OutputDevice.h
ProcessError
Definition: UtilExceptions.h:40
NBNodeCont::NodeSet
std::set< NBNode *, ComparatorIdLess > NodeSet
Definition of a node cluster container.
Definition: NBNodeCont.h:63
NBNodeCont::printBuiltNodesStatistics
void printBuiltNodesStatistics() const
Prints statistics about built nodes.
Definition: NBNodeCont.cpp:1721
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:364
NBNodeCont::myClusters2Join
std::vector< std::pair< std::set< std::string >, NBNode * > > myClusters2Join
loaded sets of node ids to join (cleared after use)
Definition: NBNodeCont.h:377
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
NBNode::removeTrafficLights
void removeTrafficLights()
Removes all references to traffic lights that control this tls.
Definition: NBNode.cpp:376
Position::x
double x() const
Returns the x-position.
Definition: Position.h:57
UtilExceptions.h
NBHelpers.h
NBParkingCont
Definition: NBParking.h:63
NBNodeCont::addJoinExclusion
void addJoinExclusion(const std::vector< std::string > &ids, bool check=false)
Definition: NBNodeCont.cpp:565
OptionsCont
A storage for options typed value containers)
Definition: OptionsCont.h:90
NBNode::getEdges
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:269
NBNodeCont::joinTLS
void joinTLS(NBTrafficLightLogicCont &tlc, double maxdist)
Builds clusters of tls-controlled junctions and joins the control if possible.
Definition: NBNodeCont.cpp:1583
StringUtils::startsWith
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
Definition: StringUtils.cpp:142
NBEdge::UNSPECIFIED_SIGNAL_OFFSET
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:321
IDSupplier.h
NBNodeCont::shortestEdge
NBEdge * shortestEdge(const NodeSet &cluster, const NodeSet &startNodes, const std::vector< NBNode * > &exclude) const
find closest neighbor for building circle
Definition: NBNodeCont.cpp:1062
Position::mul
void mul(double val)
Multiplies both positions with the given value.
Definition: Position.h:107
NBNodeCont::mySplit
std::set< const NBNode * > mySplit
nodes that were created when splitting an edge
Definition: NBNodeCont.h:386
NODETYPE_RAIL_CROSSING
Definition: SUMOXMLDefinitions.h:1055
NODETYPE_RIGHT_BEFORE_LEFT
Definition: SUMOXMLDefinitions.h:1058
NBEdgeCont::end
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:193
NODETYPE_DEAD_END
Definition: SUMOXMLDefinitions.h:1064
NBPTStopCont::end
std::map< std::string, NBPTStop * >::const_iterator end() const
Returns the pointer to the end of the stored pt stops.
Definition: NBPTStopCont.h:58
NBNodeCont::retrieve
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:108
NODETYPE_DISTRICT
Definition: SUMOXMLDefinitions.h:1061
NBEdge::getLoadedLength
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:542
NBNodeCont::NBNodeCont
NBNodeCont()
Constructor.
Definition: NBNodeCont.cpp:67
NBEdgeCont::getAllNames
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
Definition: NBEdgeCont.cpp:688
Position::distanceTo2D
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:244
NBEdge::getIncomingEdges
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1238
OptionsCont::getFloat
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
Definition: OptionsCont.cpp:209
NBEdge::getLength
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:533
NBNodeCont.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
StringUtils.h
NBEdge::INIT
The edge has been loaded, nothing is computed yet.
Definition: NBEdge.h:107
NBNodeCont::customTLID
bool customTLID(const NodeSet &c) const
check wheter the set of nodes contains traffic lights with custom id
Definition: NBNodeCont.cpp:1373
Position::y
double y() const
Returns the y-position.
Definition: Position.h:62
NBEdge::getSpeed
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:559
NBNode::geometryLike
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3046
NBNode::getControllingTLS
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:322
NBNodeCont::clear
void clear()
deletes all nodes
Definition: NBNodeCont.cpp:1686
NBTrafficLightLogicCont::removeFully
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
Definition: NBTrafficLightLogicCont.cpp:98
NBNodeCont::shouldBeTLSControlled
bool shouldBeTLSControlled(const NodeSet &c, double laneSpeedThreshold) const
Returns whethe the given node cluster should be controlled by a tls.
Definition: NBNodeCont.cpp:1315
NBNode::getIncomingEdges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:259
NBNodeCont::myRTree
NamedRTree myRTree
node positions for faster lookup
Definition: NBNodeCont.h:389
NBEdgeCont::extract
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:386
NBNodeCont::registerJoinedCluster
void registerJoinedCluster(const NodeSet &cluster)
gets all joined clusters (see doc for myClusters2Join)
Definition: NBNodeCont.cpp:1263
NBNodeCont::~NBNodeCont
~NBNodeCont()
Destructor.
Definition: NBNodeCont.cpp:72
IDSupplier::getNext
std::string getNext()
Returns the next id.
Definition: IDSupplier.cpp:52
joinToString
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:247
Parameterised::setParameter
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
Definition: Parameterised.cpp:45
SUMOXMLDefinitions::TrafficLightTypes
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
Definition: SUMOXMLDefinitions.h:1387
NBNodeTypeComputer::isRailwayNode
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
Definition: NBAlgorithms.cpp:271
NBNode::hasIncoming
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1534
NBNodeCont::extract
bool extract(NBNode *node, bool remember=false)
Removes the given node but does not delete it.
Definition: NBNodeCont.cpp:149
config.h
NBNodeCont::joinNodeCluster
void joinNodeCluster(NodeSet clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBNode *predefined=nullptr)
Definition: NBNodeCont.cpp:1092
NBNodeCont::joinLoadedClusters
int joinLoadedClusters(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins loaded junction clusters (see NIXMLNodesHandler)
Definition: NBNodeCont.cpp:621
NBNodeCont::discardRailSignals
void discardRailSignals()
Definition: NBNodeCont.cpp:1854
NBNodeCont::generateNodeClusters
void generateNodeClusters(double maxDist, NodeClusters &into) const
Builds node clusters.
Definition: NBNodeCont.cpp:452
Position::add
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:127
GeomHelper.h
NBNodeCont::joinJunctions
int joinJunctions(double maxDist, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc)
Joins junctions that are very close together.
Definition: NBNodeCont.cpp:646
StringTokenizer.h
StdDefs.h
NamedRTree::Search
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:115
NBNodeCont::myExtractedNodes
NodeCont myExtractedNodes
The extracted nodes which are kept for reference.
Definition: NBNodeCont.h:371
StringUtils::toLong
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
Definition: StringUtils.cpp:265
NBNode
Represents a single node (junction) during network building.
Definition: NBNode.h:68
NBOwnTLDef.h
NBTrafficLightLogicCont.h
NBNodeCont::NodeClusters
std::vector< NodeSet > NodeClusters
Definition: NBNodeCont.h:64
NBAlgorithms.h
NBTrafficLightLogicCont::insert
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
Definition: NBTrafficLightLogicCont.cpp:74
NBNodeCont::discardTrafficLights
void discardTrafficLights(NBTrafficLightLogicCont &tlc, bool geometryLike, bool guessSignals)
Definition: NBNodeCont.cpp:1824
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:77
NBEdge::getAngleAtNode
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1863
NBEdgeCont::begin
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:185
POSITION_EPS
#define POSITION_EPS
Definition: config.h:169
WRITE_ERROR
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:245
NBEdge::getConnections
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:924
NBDistrict
A class representing a single district.
Definition: NBDistrict.h:65
NBEdge::getFromNode
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:479
NBEdge::setSignalOffset
void setSignalOffset(double offset, NBNode *signalNode)
sets the offset of a traffic signal from the end of this edge
Definition: NBEdge.h:636
WRITE_MESSAGE
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:240
OptionsCont::getStringVector
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)
Definition: OptionsCont.cpp:921
NBEdgeCont::getRoundabouts
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
Definition: NBEdgeCont.cpp:1232
SUMOXMLDefinitions.h
NBNodeCont::reduceToCircle
bool reduceToCircle(NodeSet &cluster, int circleSize, NodeSet startNodes, std::vector< NBNode * > cands=std::vector< NBNode * >()) const
try to find a joinable subset (recursively)
Definition: NBNodeCont.cpp:1015
NBTrafficLightLogicCont::replaceRemoved
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane)
Replaces occurences of the removed edge/lane in all definitions by the given edge.
Definition: NBTrafficLightLogicCont.cpp:221
NBNode::reinit
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:304
NBTrafficLightDefinition
The base class for traffic light logic definitions.
Definition: NBTrafficLightDefinition.h:68
Named::setID
void setID(const std::string &newID)
resets the id
Definition: Named.h:85
NBNodeCont::computeLogics2
void computeLogics2(const NBEdgeCont &ec, OptionsCont &oc)
compute right-of-way logic for all lane-to-lane connections
Definition: NBNodeCont.cpp:1666
NBNode::replaceIncoming
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:1428
NBHelpers::loadEdgesFromFile
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:88
NODETYPE_NOJUNCTION
Definition: SUMOXMLDefinitions.h:1062
NBPTStopCont.h
NBEdge::getID
const std::string & getID() const
Definition: NBEdge.h:1364
NBNode::isNearDistrict
bool isNearDistrict() const
@chech if node is near district
Definition: NBNode.cpp:2172
NODETYPE_TRAFFIC_LIGHT
Definition: SUMOXMLDefinitions.h:1051