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