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 (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
650  NBNode* n = *j;
651  for (NBEdge* edge : n->getOutgoingEdges()) {
652  if (cluster.count(edge->getToNode()) != 0 && edge->getLoadedLength() > maxDist /*&& (edge->getPermissions() & SVC_PASSENGER) != 0*/) {
653 #ifdef DEBUG_JOINJUNCTIONS
654  if (DEBUGCOND(n) || DEBUGCOND(edge->getToNode())) {
655  std::cout << "long edge " << edge->getID() << " (" << edge->getLoadedLength() << ", max=" << maxDist << ")\n";
656  }
657 #endif
658  toRemove.insert(n);
659  toRemove.insert(edge->getToNode());
660  }
661  }
662  }
663  for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
664  cluster.erase(*j);
665  }
666  if (cluster.size() < 2) {
667  continue;
668  }
669  std::string reason;
670  bool feasible = feasibleCluster(cluster, ec, sc, reason);
671  //if (!feasible) std::cout << "\ntry to reduce cluster " << joinNamedToString(cluster, ',') << "\n";
672  if (!feasible) {
673  std::string origCluster = joinNamedToString(cluster, ',');
674  if (reduceToCircle(cluster, 4, cluster)) {
675  pruneClusterFringe(cluster);
676  feasible = feasibleCluster(cluster, ec, sc, reason);
677  if (feasible) {
678  WRITE_WARNING("Reducing junction cluster " + origCluster + " (" + reason + ")");
679  }
680  }
681  }
682  if (!feasible) {
683  std::string origCluster = joinNamedToString(cluster, ',');
684  if (reduceToCircle(cluster, 2, cluster)) {
685  pruneClusterFringe(cluster);
686  feasible = feasibleCluster(cluster, ec, sc, reason);
687  if (feasible) {
688  WRITE_WARNING("Reducing junction cluster " + origCluster + " (" + reason + ")");
689  }
690  }
691  }
692  if (!feasible) {
693  WRITE_WARNING("Not joining junctions " + joinNamedToString(cluster, ',') + " (" + reason + ")");
694  continue;
695  }
696  // compute all connected components of this cluster
697  // (may be more than 1 if intermediate nodes were removed)
698  NodeClusters components;
699  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) {
700  // merge all connected components into newComp
701  NodeSet newComp;
702  NBNode* current = *j;
703  //std::cout << "checking connectivity for " << current->getID() << "\n";
704  newComp.insert(current);
705  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
706  NodeClusters::iterator check = it_comp;
707  //std::cout << " connected with " << toString(*check) << "?\n";
708  bool connected = false;
709  for (std::set<NBNode*>::iterator k = (*check).begin(); k != (*check).end(); ++k) {
710  if (current->getConnectionTo(*k) != 0 || (*k)->getConnectionTo(current) != 0) {
711  //std::cout << "joining with connected component " << toString(*check) << "\n";
712  newComp.insert((*check).begin(), (*check).end());
713  it_comp = components.erase(check);
714  connected = true;
715  break;
716  }
717  }
718  if (!connected) {
719  it_comp++;
720  }
721  }
722  //std::cout << "adding new component " << toString(newComp) << "\n";
723  components.push_back(newComp);
724  }
725  for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
726  if ((*it_comp).size() > 1) {
727  //std::cout << "adding cluster " << toString(*it_comp) << "\n";
728  clusters.push_back(*it_comp);
729  }
730  }
731  }
732  joinNodeClusters(clusters, dc, ec, tlc);
733  return (int)clusters.size();
734 }
735 
736 
737 void
739 #ifdef DEBUG_JOINJUNCTIONS
740  if (true) {
741  std::cout << "pruning cluster=" << joinNamedToString(cluster, ' ') << "\n";
742  }
743 #endif
744  // iteratively remove the fringe
745  bool pruneFringe = true;
746  // collect nodes that shall be joined due to distance but are not connected
747  // to the cluster for passenger traffic
748  while (pruneFringe) {
749  pruneFringe = false;
750  for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) {
751  std::set<NBNode*>::iterator check = j;
752  NBNode* n = *check;
753  ++j;
754 
755  // compute clusterDist for node (length of shortest edge which connects this node to the cluster)
756  double clusterDist = std::numeric_limits<double>::max();
757  bool touchingCluster = false;
758  for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
759  NBNode* neighbor = (*it_edge)->getToNode();
760  if (cluster.count(neighbor) != 0) {
761  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
762  touchingCluster |= n->getPosition().distanceTo2D(neighbor->getPosition()) <= SUMO_const_laneWidth;
763  }
764  }
765  for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
766  NBNode* neighbor = (*it_edge)->getFromNode();
767  if (cluster.count(neighbor) != 0) {
768  clusterDist = MIN2(clusterDist, (*it_edge)->getLoadedLength());
769  touchingCluster |= n->getPosition().distanceTo2D(neighbor->getPosition()) <= SUMO_const_laneWidth;
770  }
771  }
772  // remove geometry-like nodes at fringe of the cluster
773  // (they have 1 neighbor in the cluster and at most 1 neighbor outside the cluster)
774  std::set<NBNode*> outsideNeighbors;
775  std::set<NBNode*> clusterNeighbors;
776  const double pedestrianFringeThreshold = 0.3;
777  for (NBEdge* e : n->getEdges()) {
778  NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
779  if (cluster.count(neighbor) == 0) {
780  if ((e->getPermissions() & SVC_PASSENGER) != 0 || clusterDist <= pedestrianFringeThreshold || touchingCluster) {
781  outsideNeighbors.insert(neighbor);
782  }
783  } else {
784  clusterNeighbors.insert(neighbor);
785  }
786  }
787 #ifdef DEBUG_JOINJUNCTIONS
788  if (DEBUGCOND(n)) std::cout << " check n=" << n->getID()
789  << " clusterDist=" << clusterDist
790  << " cd<th=" << (clusterDist <= pedestrianFringeThreshold)
791  << " touching=" << touchingCluster
792  << " out=" << joinNamedToString(outsideNeighbors, ',')
793  << " in=" << joinNamedToString(clusterNeighbors, ',')
794  << "\n";
795 #endif
796  if (outsideNeighbors.size() <= 1
797  && clusterNeighbors.size() == 1
798  && !n->isTLControlled()) {
799  cluster.erase(check);
800  pruneFringe = true; // other nodes could belong to the fringe now
801 #ifdef DEBUG_JOINJUNCTIONS
802  if (DEBUGCOND(n)) {
803  std::cout << " pruned n=" << n->getID() << "\n";
804  }
805 #endif
806  }
807  }
808  }
809 }
810 
811 
812 bool
813 NBNodeCont::feasibleCluster(const NodeSet& cluster, const NBEdgeCont& ec, const NBPTStopCont& sc, std::string& reason) const {
814  // check for clusters which are to complex and probably won't work very well
815  // we count the incoming edges of the final junction
816  std::map<std::string, double> finalIncomingAngles;
817  std::map<std::string, double> finalOutgoingAngles;
818  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
819  for (EdgeVector::const_iterator it_edge = (*j)->getIncomingEdges().begin(); it_edge != (*j)->getIncomingEdges().end(); ++it_edge) {
820  NBEdge* edge = *it_edge;
821  if (cluster.count(edge->getFromNode()) == 0 && (edge->getPermissions() & SVC_PASSENGER) != 0) {
822  // incoming edge, does not originate in the cluster
823  finalIncomingAngles[edge->getID()] = edge->getAngleAtNode(edge->getToNode());
824  }
825  }
826  for (EdgeVector::const_iterator it_edge = (*j)->getOutgoingEdges().begin(); it_edge != (*j)->getOutgoingEdges().end(); ++it_edge) {
827  NBEdge* edge = *it_edge;
828  if (cluster.count(edge->getToNode()) == 0 && (edge->getPermissions() & SVC_PASSENGER) != 0) {
829  // outgoing edge, does not end in the cluster
830  finalOutgoingAngles[edge->getID()] = edge->getAngleAtNode(edge->getFromNode());
831  }
832  }
833 
834  }
835 #ifdef DEBUG_JOINJUNCTIONS
836  for (NBNode* n : cluster) {
837  if (DEBUGCOND(n)) {
838  std::cout << "feasibleCluster c=" << joinNamedToString(cluster, ',')
839  << "\n inAngles=" << joinToString(finalIncomingAngles, ' ', ':')
840  << "\n outAngles=" << joinToString(finalOutgoingAngles, ' ', ':')
841  << "\n";
842  }
843  }
844 #endif
845  if (finalIncomingAngles.size() > 4) {
846  reason = toString(finalIncomingAngles.size()) + " incoming edges";
847  return false;
848  }
849  // check for incoming parallel edges
850  const double PARALLEL_INCOMING_THRESHOLD = 10.0;
851  bool foundParallel = false;
852  for (std::map<std::string, double>::const_iterator j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
853  std::map<std::string, double>::const_iterator k = j;
854  for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
855  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
856  reason = "parallel incoming " + j->first + "," + k->first;
857  return false;
858  }
859  }
860  }
861  // check for outgoing parallel edges
862  for (std::map<std::string, double>::const_iterator j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
863  std::map<std::string, double>::const_iterator k = j;
864  for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
865  if (fabs(j->second - k->second) < PARALLEL_INCOMING_THRESHOLD) {
866  reason = "parallel outgoing " + j->first + "," + k->first;
867  return false;
868  }
869  }
870  }
871  // check for stop edges within the cluster
872  if (OptionsCont::getOptions().isSet("ptstop-output")) {
873  for (auto it = sc.begin(); it != sc.end(); it++) {
874  NBEdge* edge = ec.retrieve(it->second->getEdgeId());
875  if (edge != 0 && cluster.count(edge->getFromNode()) != 0 && cluster.count(edge->getToNode()) != 0) {
876  reason = "it contains stop '" + it->first + "'";
877  return false;
878  }
879  }
880  }
881  // prevent removal of long edges unless there is weak circle or a traffic light
882  if (cluster.size() > 2) {
883  // find the nodes with the biggests physical distance between them
884  double maxDist = -1;
885  bool hasTLS = false;
886  NBEdge* maxEdge = 0;
887  for (NBNode* n1 : cluster) {
888  hasTLS |= n1->isTLControlled();
889  for (NBNode* n2 : cluster) {
890  NBEdge* e1 = n1->getConnectionTo(n2);
891  NBEdge* e2 = n2->getConnectionTo(n1);
892  if (e1 != 0 && e1->getLoadedLength() > maxDist) {
893  maxDist = e1->getLoadedLength();
894  maxEdge = e1;
895  }
896  if (e2 != 0 && e2->getLoadedLength() > maxDist) {
897  maxDist = e2->getLoadedLength();
898  maxEdge = e2;
899  }
900  }
901  }
902 #ifdef DEBUG_JOINJUNCTIONS
903  for (NBNode* n : cluster) {
904  if (DEBUGCOND(n)) {
905  std::cout << "feasible hasTLS=" << hasTLS << " maxDist=" << maxDist << " maxEdge=" << maxEdge->getID() << "\n";
906  }
907  }
908 #endif
909  if (!hasTLS && maxDist > 5) {
910  // find a weak circle within cluster that does not use maxEdge
911  std::vector<NBNode*> toCheck;
912  std::set<NBNode*> visited;
913  toCheck.push_back(maxEdge->getToNode());
914  bool foundCircle = false;
915  while (!toCheck.empty()) {
916  NBNode* n = toCheck.back();
917  if (n == maxEdge->getFromNode()) {
918  foundCircle = true;
919  break;
920  }
921  toCheck.pop_back();
922  visited.insert(n);
923  for (NBEdge* e : n->getEdges()) {
924  if (e != maxEdge) {
925  NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
926  if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
927  toCheck.push_back(cand);
928  }
929  }
930  }
931  }
932  if (!foundCircle) {
933  reason = "not compact (maxEdge=" + maxEdge->getID() + " length=" + toString(maxDist) + ")";
934  return false;
935  }
936  }
937  }
938  return true;
939 }
940 
941 
942 bool
943 NBNodeCont::reduceToCircle(NodeSet& cluster, int circleSize, NodeSet startNodes, std::vector<NBNode*> cands) const {
944  //std::cout << " cs=" << circleSize << " cands=" << toString(cands) << " startNodes=" << toString(startNodes) << "\n";
945  assert(circleSize >= 2);
946  if ((int)cands.size() == circleSize) {
947  if (cands.back()->getConnectionTo(cands.front()) != 0) {
948  // cluster found
949  cluster.clear();
950  cluster.insert(cands.begin(), cands.end());
951  return true;
952  } else {
953  return false;
954  }
955  }
956  if ((int)cluster.size() <= circleSize || startNodes.size() == 0) {
957  // no reduction possible
958  return false;
959  }
960  if (cands.size() == 0) {
961  // try to find a circle starting from another start node
962  NBEdge* e = shortestEdge(cluster, startNodes, cands);
963  if (e != 0) {
964  cands.push_back(e->getFromNode());
965  startNodes.erase(e->getFromNode());
966  if (reduceToCircle(cluster, circleSize, startNodes, cands)) {
967  return true;
968  } else {
969  // try another start node
970  return reduceToCircle(cluster, circleSize, startNodes);
971  }
972  }
973  } else {
974  NodeSet singleStart;
975  singleStart.insert(cands.back());
976  NBEdge* e = shortestEdge(cluster, singleStart, cands);
977  if (e != 0) {
978  std::vector<NBNode*> cands2(cands);
979  cands2.push_back(e->getToNode());
980  if (reduceToCircle(cluster, circleSize, startNodes, cands2)) {
981  return true;
982  }
983  }
984  }
985  return false;
986 }
987 
988 
989 NBEdge*
990 NBNodeCont::shortestEdge(const NodeSet& cluster, const NodeSet& startNodes, const std::vector<NBNode*>& exclude) const {
991  double minDist = std::numeric_limits<double>::max();
992  NBEdge* result = 0;
993  for (NBNode* n : startNodes) {
994  for (NBEdge* e : n->getOutgoingEdges()) {
995  NBNode* neigh = e->getToNode();
996  if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
997  const double dist = n->getPosition().distanceTo2D(neigh->getPosition());
998  //std::cout << " e=" << e->getID() << " dist=" << dist << " minD=" << minDist << "\n";
999  if (dist < minDist) {
1000  minDist = dist;
1001  result = e;
1002  }
1003  }
1004  }
1005  }
1006  //std::cout << "closestNeighbor startNodes=" << toString(startNodes) << " result=" << Named::getIDSecure(result) << "\n";
1007  return result;
1008 }
1009 
1010 void
1013  for (NodeClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) {
1014  NodeSet cluster = *i;
1015  assert(cluster.size() > 1);
1016  Position pos;
1017  bool setTL;
1018  std::string id = "cluster";
1019  TrafficLightType type;
1020  SumoXMLNodeType nodeType = NODETYPE_UNKNOWN;
1021  analyzeCluster(cluster, id, pos, setTL, type, nodeType);
1022  if (!insert(id, pos)) {
1023  // should not fail
1024  WRITE_WARNING("Could not join junctions " + id);
1025  continue;
1026  }
1027  NBNode* newNode = retrieve(id);
1028  newNode->reinit(pos, nodeType);
1029  if (setTL) {
1030  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode, 0, type);
1031  if (!tlc.insert(tlDef)) {
1032  // actually, nothing should fail here
1033  delete tlDef;
1034  throw ProcessError("Could not allocate tls '" + id + "'.");
1035  }
1036  }
1037  // collect edges
1038  std::set<NBEdge*> allEdges;
1039  for (NBNode* n : cluster) {
1040  const EdgeVector& edges = n->getEdges();
1041  allEdges.insert(edges.begin(), edges.end());
1042  }
1043 
1044  // remap and remove edges which are completely within the new intersection
1045  for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end();) {
1046  NBEdge* e = (*j);
1047  NBNode* from = e->getFromNode();
1048  NBNode* to = e->getToNode();
1049  if (cluster.count(from) > 0 && cluster.count(to) > 0) {
1050  for (std::set<NBEdge*>::iterator l = allEdges.begin(); l != allEdges.end(); ++l) {
1051  if (e != *l) {
1052  (*l)->replaceInConnections(e, e->getConnections());
1053  }
1054  }
1055  ec.extract(dc, e, true);
1056  allEdges.erase(j++); // erase does not invalidate the other iterators
1057  } else {
1058  ++j;
1059  }
1060  }
1061 
1062  // remap edges which are incoming / outgoing
1063  for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end(); ++j) {
1064  NBEdge* e = (*j);
1065  std::vector<NBEdge::Connection> conns = e->getConnections();
1066  const bool outgoing = cluster.count(e->getFromNode()) > 0;
1067  NBNode* from = outgoing ? newNode : e->getFromNode();
1068  NBNode* to = outgoing ? e->getToNode() : newNode;
1069  e->reinitNodes(from, to);
1070  // re-add connections which previously existed and may still valid.
1071  // connections to removed edges will be ignored
1072  for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1073  e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass);
1074  if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1075  // @note (see NIImporter_DlrNavteq::ConnectedLanesHandler)
1077  }
1078  }
1079  }
1080  // remove original nodes
1081  registerJoinedCluster(cluster);
1082  for (NodeSet::const_iterator j = cluster.begin(); j != cluster.end(); ++j) {
1083  erase(*j);
1084  }
1085  }
1086 }
1087 
1088 
1089 void
1091  std::set<std::string> ids;
1092  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
1093  ids.insert((*j)->getID());
1094  }
1095  myJoinedClusters.push_back(ids);
1096 }
1097 
1098 
1099 void
1100 NBNodeCont::analyzeCluster(NodeSet cluster, std::string& id, Position& pos,
1101  bool& hasTLS, TrafficLightType& type, SumoXMLNodeType& nodeType) {
1102  id += "_" + joinNamedToString(cluster, '_');
1103  hasTLS = false;
1104  bool ambiguousType = false;
1105  for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) {
1106  pos.add((*j)->getPosition());
1107  // add a traffic light if any of the cluster members was controlled
1108  if ((*j)->isTLControlled()) {
1109  if (!hasTLS) {
1110  // init type
1111  type = (*(*j)->getControllingTLS().begin())->getType();
1112  } else if (type != (*(*j)->getControllingTLS().begin())->getType()) {
1113  ambiguousType = true;
1114  }
1115  hasTLS = true;
1116  }
1117  SumoXMLNodeType otherType = (*j)->getType();
1118  if (nodeType == NODETYPE_UNKNOWN) {
1119  nodeType = otherType;
1120  } else if (nodeType != otherType) {
1121  if (hasTLS) {
1122  nodeType = NODETYPE_TRAFFIC_LIGHT;;
1123  } else {
1124  if ((nodeType != NODETYPE_PRIORITY && (nodeType != NODETYPE_NOJUNCTION || otherType != NODETYPE_PRIORITY))
1125  || (otherType != NODETYPE_NOJUNCTION && otherType != NODETYPE_UNKNOWN && otherType != NODETYPE_PRIORITY)) {
1126  WRITE_WARNING("Ambiguous node type for node cluster '" + id + "' (" + toString(nodeType) + "," + toString(otherType) + ") set to '" + toString(NODETYPE_PRIORITY) + "'");
1127  }
1128  nodeType = NODETYPE_PRIORITY;
1129  }
1130  }
1131  }
1132  pos.mul(1.0 / cluster.size());
1133  if (ambiguousType) {
1134  type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
1135  WRITE_WARNING("Ambiguous traffic light type for node cluster '" + id + "' set to '" + toString(type) + "'");
1136  }
1137 }
1138 
1139 
1140 // ----------- (Helper) methods for guessing/computing traffic lights
1141 bool
1143  int noIncoming = 0;
1144  int noOutgoing = 0;
1145  bool tooFast = false;
1146  double f = 0;
1147  std::set<NBEdge*> seen;
1148  for (std::set<NBNode*>::const_iterator j = c.begin(); j != c.end(); ++j) {
1149  const EdgeVector& edges = (*j)->getEdges();
1150  for (EdgeVector::const_iterator k = edges.begin(); k != edges.end(); ++k) {
1151  if (c.find((*k)->getFromNode()) != c.end() && c.find((*k)->getToNode()) != c.end()) {
1152  continue;
1153  }
1154  if ((*j)->hasIncoming(*k)) {
1155  ++noIncoming;
1156  f += (double)(*k)->getNumLanes() * (*k)->getLaneSpeed(0);
1157  } else {
1158  ++noOutgoing;
1159  }
1160  if ((*k)->getLaneSpeed(0) * 3.6 > 79) {
1161  tooFast = true;
1162  }
1163  }
1164  }
1165  return !tooFast && f >= 150. / 3.6 && c.size() != 0;
1166 }
1167 
1168 
1169 void
1171  // build list of definitely not tls-controlled junctions
1172  std::vector<NBNode*> ncontrolled;
1173  if (oc.isSet("tls.unset")) {
1174  std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset");
1175  for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
1176  NBNode* n = NBNodeCont::retrieve(*i);
1177  if (n == 0) {
1178  throw ProcessError(" The junction '" + *i + "' to set as not-controlled is not known.");
1179  }
1180  std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS();
1181  for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
1182  (*j)->removeNode(n);
1183  }
1184  n->removeTrafficLights();
1185  ncontrolled.push_back(n);
1186  }
1187  }
1188 
1190  // loop#1 checking whether the node shall be tls controlled,
1191  // because it is assigned to a district
1192  if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) {
1193  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1194  NBNode* cur = (*i).second;
1195  if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) {
1196  setAsTLControlled(cur, tlc, type);
1197  }
1198  }
1199  }
1200 
1201  // figure out which nodes mark the locations of TLS signals
1202  // This assumes nodes are already joined
1203  if (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals")) {
1204  // prepare candidate edges
1205  const double signalDist = oc.getFloat("tls.guess-signals.dist");
1206  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1207  NBNode* node = (*i).second;
1208  if (node->isTLControlled() && node->geometryLike()) {
1209  const EdgeVector& outgoing = node->getOutgoingEdges();
1210  for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) {
1211  (*it_o)->setSignalOffset((*it_o)->getLength());
1212  }
1213  }
1214  }
1215  // check which nodes should be controlled
1216  for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1217  NBNode* node = i->second;
1218  if (find(ncontrolled.begin(), ncontrolled.end(), node) != ncontrolled.end()) {
1219  continue;
1220  }
1221  const EdgeVector& incoming = node->getIncomingEdges();
1222  const EdgeVector& outgoing = node->getOutgoingEdges();
1223  if (!node->isTLControlled() && incoming.size() > 1 && !node->geometryLike() && !NBNodeTypeComputer::isRailwayNode(node)) {
1224  std::vector<NBNode*> signals;
1225  bool isTLS = true;
1226  for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
1227  const NBEdge* inEdge = *it_i;
1228  if (inEdge->getSignalOffset() == NBEdge::UNSPECIFIED_SIGNAL_OFFSET || inEdge->getSignalOffset() > signalDist) {
1229  isTLS = false;
1230  break;
1231  }
1232  if (inEdge->getSignalOffset() == inEdge->getLength()) {
1233  signals.push_back(inEdge->getFromNode());
1234  }
1235  }
1236  // outgoing edges may be tagged with pedestrian crossings. These
1237  // should also be merged into the main TLS
1238  for (EdgeVector::const_iterator it_i = outgoing.begin(); it_i != outgoing.end(); ++it_i) {
1239  const NBEdge* outEdge = *it_i;
1240  NBNode* cand = outEdge->getToNode();
1241  if (cand->isTLControlled() && cand->geometryLike() && outEdge->getLength() <= signalDist) {
1242  signals.push_back(cand);
1243  }
1244  }
1245  if (isTLS) {
1246  for (std::vector<NBNode*>::iterator j = signals.begin(); j != signals.end(); ++j) {
1247  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
1248  (*j)->reinit((*j)->getPosition(), NODETYPE_PRIORITY);
1249  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
1250  tlc.removeFully((*j)->getID());
1251  }
1252  }
1253  NBTrafficLightDefinition* tlDef = new NBOwnTLDef("GS_" + node->getID(), node, 0, type);
1254  // @todo patch endOffset for all incoming lanes according to the signal positions
1255  if (!tlc.insert(tlDef)) {
1256  // actually, nothing should fail here
1257  WRITE_WARNING("Could not build joined tls '" + node->getID() + "'.");
1258  delete tlDef;
1259  return;
1260  }
1261  }
1262  }
1263  }
1264  }
1265 
1266  // maybe no tls shall be guessed
1267  if (!oc.getBool("tls.guess")) {
1268  return;
1269  }
1270 
1271  // guess joined tls first, if wished
1272  if (oc.getBool("tls.join")) {
1273  // get node clusters
1274  NodeClusters cands;
1275  generateNodeClusters(oc.getFloat("tls.join-dist"), cands);
1276  // check these candidates (clusters) whether they should be controlled by a tls
1277  for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
1278  NodeSet& c = (*i);
1279  // regard only junctions which are not yet controlled and are not
1280  // forbidden to be controlled
1281  for (NodeSet::iterator j = c.begin(); j != c.end();) {
1282  if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) {
1283  c.erase(j++);
1284  } else {
1285  ++j;
1286  }
1287  }
1288  // check whether the cluster should be controlled
1289  if (!shouldBeTLSControlled(c)) {
1290  i = cands.erase(i);
1291  } else {
1292  ++i;
1293  }
1294  }
1295  // cands now only contain sets of junctions that shall be joined into being tls-controlled
1296  int index = 0;
1297  for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) {
1298  std::vector<NBNode*> nodes;
1299  for (NodeSet::iterator j = (*i).begin(); j != (*i).end(); j++) {
1300  nodes.push_back(*j);
1301  }
1302  std::string id = "joinedG_" + toString(index++);
1303  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1304  if (!tlc.insert(tlDef)) {
1305  // actually, nothing should fail here
1306  WRITE_WARNING("Could not build guessed, joined tls");
1307  delete tlDef;
1308  return;
1309  }
1310  }
1311  }
1312 
1313  // guess tls
1314  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1315  NBNode* cur = (*i).second;
1316  // do nothing if already is tl-controlled
1317  if (cur->isTLControlled()) {
1318  continue;
1319  }
1320  // do nothing if in the list of explicit non-controlled junctions
1321  if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) {
1322  continue;
1323  }
1324  NodeSet c;
1325  c.insert(cur);
1326  if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) {
1327  continue;
1328  }
1329  setAsTLControlled((*i).second, tlc, type);
1330  }
1331 }
1332 
1333 
1334 void
1336  NodeClusters cands;
1337  generateNodeClusters(maxdist, cands);
1338  int index = 0;
1339  for (NodeSet& c : cands) {
1340  for (NodeSet::iterator j = c.begin(); j != c.end();) {
1341  if (!(*j)->isTLControlled()) {
1342  c.erase(j++);
1343  } else {
1344  ++j;
1345  }
1346  }
1347  if (c.size() < 2) {
1348  continue;
1349  }
1350  // figure out type of the joined TLS
1351  Position dummyPos;
1352  bool dummySetTL;
1353  std::string id = "joined"; // prefix (see #3871)
1354  TrafficLightType type;
1355  SumoXMLNodeType nodeType = NODETYPE_UNKNOWN;
1356  analyzeCluster(c, id, dummyPos, dummySetTL, type, nodeType);
1357  for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); ++j) {
1358  std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
1359  (*j)->removeTrafficLights();
1360  for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
1361  tlc.removeFully((*j)->getID());
1362  }
1363  }
1364  id = "joinedS_" + toString(index++);
1365  std::vector<NBNode*> nodes;
1366  for (NodeSet::iterator j = c.begin(); j != c.end(); j++) {
1367  nodes.push_back(*j);
1368  }
1369  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type);
1370  if (!tlc.insert(tlDef)) {
1371  // actually, nothing should fail here
1372  WRITE_WARNING("Could not build a joined tls.");
1373  delete tlDef;
1374  return;
1375  }
1376  }
1377 }
1378 
1379 
1380 void
1382  TrafficLightType type, std::string id) {
1383  if (id == "") {
1384  id = node->getID();
1385  }
1386  NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node, 0, type);
1387  if (!tlc.insert(tlDef)) {
1388  // actually, nothing should fail here
1389  WRITE_WARNING("Building a tl-logic for junction '" + id + "' twice is not possible.");
1390  delete tlDef;
1391  return;
1392  }
1393 }
1394 
1395 
1396 // -----------
1397 void
1399  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1400  (*i).second->computeLanes2Lanes();
1401  }
1402 }
1403 
1404 
1405 // computes the "wheel" of incoming and outgoing edges for every node
1406 void
1408  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1409  (*i).second->computeLogic(ec, oc);
1410  }
1411 }
1412 
1413 
1414 void
1416  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1417  delete((*i).second);
1418  }
1419  myNodes.clear();
1420  for (std::set<NBNode*>::iterator i = myExtractedNodes.begin(); i != myExtractedNodes.end(); i++) {
1421  delete(*i);
1422  }
1423  myExtractedNodes.clear();
1424 }
1425 
1426 
1427 std::string
1429  int counter = 0;
1430  std::string freeID = "SUMOGenerated" + toString<int>(counter);
1431  // While there is a node with id equal to freeID
1432  while (retrieve(freeID) != 0) {
1433  // update counter and generate a new freeID
1434  counter++;
1435  freeID = "SUMOGenerated" + toString<int>(counter);
1436  }
1437  return freeID;
1438 }
1439 
1440 
1441 void
1442 NBNodeCont::computeNodeShapes(double mismatchThreshold) {
1443  for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1444  (*i).second->computeNodeShape(mismatchThreshold);
1445  }
1446 }
1447 
1448 
1449 void
1451  int numUnregulatedJunctions = 0;
1452  int numDeadEndJunctions = 0;
1453  int numPriorityJunctions = 0;
1454  int numRightBeforeLeftJunctions = 0;
1455  int numAllWayStopJunctions = 0;
1456  int numZipperJunctions = 0;
1457  int numRailSignals = 0;
1458  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) {
1459  switch ((*i).second->getType()) {
1460  case NODETYPE_NOJUNCTION:
1462  ++numUnregulatedJunctions;
1463  break;
1464  case NODETYPE_DEAD_END:
1465  ++numDeadEndJunctions;
1466  break;
1467  case NODETYPE_PRIORITY:
1472  ++numPriorityJunctions;
1473  break;
1475  ++numRightBeforeLeftJunctions;
1476  break;
1477  case NODETYPE_ALLWAY_STOP:
1478  ++numAllWayStopJunctions;
1479  break;
1480  case NODETYPE_ZIPPER:
1481  ++numZipperJunctions;
1482  break;
1483  case NODETYPE_DISTRICT:
1484  ++numRightBeforeLeftJunctions;
1485  break;
1486  case NODETYPE_UNKNOWN:
1487  break;
1488  case NODETYPE_RAIL_SIGNAL:
1489  ++numRailSignals;
1490  break;
1491  default:
1492  break;
1493  }
1494  }
1495  WRITE_MESSAGE(" Node type statistics:");
1496  WRITE_MESSAGE(" Unregulated junctions : " + toString(numUnregulatedJunctions));
1497  if (numDeadEndJunctions > 0) {
1498  WRITE_MESSAGE(" Dead-end junctions : " + toString(numDeadEndJunctions));
1499  }
1500  WRITE_MESSAGE(" Priority junctions : " + toString(numPriorityJunctions));
1501  WRITE_MESSAGE(" Right-before-left junctions : " + toString(numRightBeforeLeftJunctions));
1502  if (numAllWayStopJunctions > 0) {
1503  WRITE_MESSAGE(" All-way stop junctions : " + toString(numAllWayStopJunctions));
1504  }
1505  if (numZipperJunctions > 0) {
1506  WRITE_MESSAGE(" Zipper-merge junctions : " + toString(numZipperJunctions));
1507  }
1508  if (numRailSignals > 0) {
1509  WRITE_MESSAGE(" Rail signal junctions : " + toString(numRailSignals));
1510  }
1511 }
1512 
1513 
1514 std::vector<std::string>
1516  std::vector<std::string> ret;
1517  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1518  ret.push_back((*i).first);
1519  }
1520  return ret;
1521 }
1522 
1523 
1524 void
1525 NBNodeCont::rename(NBNode* node, const std::string& newID) {
1526  if (myNodes.count(newID) != 0) {
1527  throw ProcessError("Attempt to rename node using existing id '" + newID + "'");
1528  }
1529  myNodes.erase(node->getID());
1530  node->setID(newID);
1531  myNodes[newID] = node;
1532 }
1533 
1534 
1535 void
1536 NBNodeCont::discardTrafficLights(NBTrafficLightLogicCont& tlc, bool geometryLike, bool guessSignals) {
1537  for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) {
1538  NBNode* node = i->second;
1539  if (node->isTLControlled() && (!geometryLike || node->geometryLike())) {
1540  // make a copy of tldefs
1541  const std::set<NBTrafficLightDefinition*> tldefs = node->getControllingTLS();
1542  if (guessSignals && node->isTLControlled() && node->geometryLike()) {
1543  // record signal location
1544  const EdgeVector& outgoing = node->getOutgoingEdges();
1545  for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) {
1546  (*it_o)->setSignalOffset((*it_o)->getLength());
1547  }
1548  }
1549  for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
1550  NBTrafficLightDefinition* tlDef = *it;
1551  node->removeTrafficLight(tlDef);
1552  tlc.extract(tlDef);
1553  }
1555  node->reinit(node->getPosition(), newType);
1556  }
1557  }
1558 }
1559 
1560 
1561 void
1563  for (auto& item : myNodes) {
1564  NBNode* node = item.second;
1565  if (node->getType() == NODETYPE_RAIL_SIGNAL) {
1566  node->reinit(node->getPosition(), NODETYPE_PRIORITY);
1567  }
1568  }
1569 }
1570 
1571 
1572 int
1573 NBNodeCont::remapIDs(bool numericaIDs, bool reservedIDs, const std::string& prefix) {
1574  std::vector<std::string> avoid = getAllNames();
1575  std::set<std::string> reserve;
1576  if (reservedIDs) {
1577  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "node:", reserve);
1578  avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1579  }
1580  IDSupplier idSupplier("", avoid);
1581  NodeSet toChange;
1582  for (NodeCont::iterator it = myNodes.begin(); it != myNodes.end(); it++) {
1583  if (numericaIDs) {
1584  try {
1585  TplConvert::_str2long(it->first);
1586  } catch (NumberFormatException&) {
1587  toChange.insert(it->second);
1588  }
1589  }
1590  if (reservedIDs && reserve.count(it->first) > 0) {
1591  toChange.insert(it->second);
1592  }
1593  }
1594  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1595  for (NBNode* node : toChange) {
1596  myNodes.erase(node->getID());
1597  if (origNames) {
1598  node->setParameter(SUMO_PARAM_ORIGID, node->getID());
1599  }
1600  node->setID(idSupplier.getNext());
1601  myNodes[node->getID()] = node;
1602  }
1603  if (prefix.empty()) {
1604  return (int)toChange.size();
1605  } else {
1606  int renamed = 0;
1607  // make a copy because we will modify the map
1608  auto oldNodes = myNodes;
1609  for (auto item : oldNodes) {
1610  if (!StringUtils::startsWith(item.first, prefix)) {
1611  rename(item.second, prefix + item.first);
1612  renamed++;
1613  }
1614  }
1615  return renamed;
1616  }
1617 }
1618 
1619 /****************************************************************************/
1620 
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:483
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:813
#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:943
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:572
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:43
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:271
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:1201
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
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:1929
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:990
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:415
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:2790
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:62
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:1749
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:3279
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:509
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:862
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:2915
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:1215
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:429
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:492
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:2982
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:436
void pruneClusterFringe(NodeSet &cluster) const
remove geometry-like fringe nodes from cluster
Definition: NBNodeCont.cpp:738
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