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