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