Eclipse SUMO - Simulation of Urban MObility
NBEdgeCont.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-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // Storage for edges, including some functionality operating on multiple edges
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <vector>
26 #include <string>
27 #include <cassert>
28 #include <algorithm>
29 #include <cmath>
30 #include <utils/geom/Boundary.h>
31 #include <utils/geom/GeomHelper.h>
35 #include <utils/common/ToString.h>
43 #include "NBNetBuilder.h"
44 #include "NBEdgeCont.h"
45 #include "NBNodeCont.h"
46 #include "NBPTLineCont.h"
47 #include "NBHelpers.h"
48 #include "NBCont.h"
50 #include "NBDistrictCont.h"
51 #include "NBTypeCont.h"
52 
53 #define JOIN_TRAM_MAX_ANGLE 10
54 #define JOIN_TRAM_MIN_LENGTH 3
55 
56 //#define DEBUG_GUESS_ROUNDABOUT
57 //#define DEBUG_JOIN_TRAM
58 #define DEBUG_EDGE_ID "301241681#2"
59 
60 // ===========================================================================
61 // method definitions
62 // ===========================================================================
64  myTypeCont(tc),
65  myEdgesSplit(0),
66  myVehicleClasses2Keep(0),
67  myVehicleClasses2Remove(0),
68  myNeedGeoTransformedPruningBoundary(false) {
69 }
70 
71 
73  clear();
74 }
75 
76 
77 void
79  // set edges dismiss/accept options
80  myEdgesMinSpeed = oc.getFloat("keep-edges.min-speed");
81  myRemoveEdgesAfterJoining = oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload");
82  // we possibly have to load the edges to keep/remove
83  if (oc.isSet("keep-edges.input-file")) {
84  NBHelpers::loadEdgesFromFile(oc.getString("keep-edges.input-file"), myEdges2Keep);
85  }
86  if (oc.isSet("remove-edges.input-file")) {
87  NBHelpers::loadEdgesFromFile(oc.getString("remove-edges.input-file"), myEdges2Remove);
88  }
89  if (oc.isSet("keep-edges.explicit")) {
90  const std::vector<std::string> edges = oc.getStringVector("keep-edges.explicit");
91  myEdges2Keep.insert(edges.begin(), edges.end());
92  }
93  if (oc.isSet("remove-edges.explicit")) {
94  const std::vector<std::string> edges = oc.getStringVector("remove-edges.explicit");
95  myEdges2Remove.insert(edges.begin(), edges.end());
96  }
97  if (oc.exists("keep-edges.by-vclass") && oc.isSet("keep-edges.by-vclass")) {
98  myVehicleClasses2Keep = parseVehicleClasses(oc.getStringVector("keep-edges.by-vclass"));
99  }
100  if (oc.exists("remove-edges.by-vclass") && oc.isSet("remove-edges.by-vclass")) {
101  myVehicleClasses2Remove = parseVehicleClasses(oc.getStringVector("remove-edges.by-vclass"));
102  }
103  if (oc.exists("keep-edges.by-type") && oc.isSet("keep-edges.by-type")) {
104  const std::vector<std::string> types = oc.getStringVector("keep-edges.by-type");
105  myTypes2Keep.insert(types.begin(), types.end());
106  }
107  if (oc.exists("remove-edges.by-type") && oc.isSet("remove-edges.by-type")) {
108  const std::vector<std::string> types = oc.getStringVector("remove-edges.by-type");
109  myTypes2Remove.insert(types.begin(), types.end());
110  }
111 
112  if (oc.isSet("keep-edges.in-boundary") || oc.isSet("keep-edges.in-geo-boundary")) {
113 
114  std::string polyPlainString = oc.getValueString(oc.isSet("keep-edges.in-boundary") ?
115  "keep-edges.in-boundary" : "keep-edges.in-geo-boundary");
116  // try interpreting the boundary like shape attribute with spaces
117  bool ok = true;
118  PositionVector boundaryShape = GeomConvHelper::parseShapeReporting(polyPlainString, "pruning-boundary", 0, ok, false, false);
119  if (ok) {
120  if (boundaryShape.size() < 2) {
121  throw ProcessError("Invalid boundary: need at least 2 coordinates");
122  } else if (boundaryShape.size() == 2) {
123  // prunning boundary (box)
124  myPruningBoundary.push_back(boundaryShape[0]);
125  myPruningBoundary.push_back(Position(boundaryShape[1].x(), boundaryShape[0].y()));
126  myPruningBoundary.push_back(boundaryShape[1]);
127  myPruningBoundary.push_back(Position(boundaryShape[0].x(), boundaryShape[1].y()));
128  } else {
129  myPruningBoundary = boundaryShape;
130  }
131  } else {
132  // maybe positions are separated by ',' instead of ' '
133  std::vector<std::string> polyS = oc.getStringVector(oc.isSet("keep-edges.in-boundary") ?
134  "keep-edges.in-boundary" : "keep-edges.in-geo-boundary");
135  std::vector<double> poly;
136  for (std::vector<std::string>::iterator i = polyS.begin(); i != polyS.end(); ++i) {
137  poly.push_back(StringUtils::toDouble((*i))); // !!! may throw something anyhow...
138  }
139  if (poly.size() < 4) {
140  throw ProcessError("Invalid boundary: need at least 2 coordinates");
141  } else if (poly.size() % 2 != 0) {
142  throw ProcessError("Invalid boundary: malformed coordinate");
143  } else if (poly.size() == 4) {
144  // prunning boundary (box)
145  myPruningBoundary.push_back(Position(poly[0], poly[1]));
146  myPruningBoundary.push_back(Position(poly[2], poly[1]));
147  myPruningBoundary.push_back(Position(poly[2], poly[3]));
148  myPruningBoundary.push_back(Position(poly[0], poly[3]));
149  } else {
150  for (std::vector<double>::iterator j = poly.begin(); j != poly.end();) {
151  double x = *j++;
152  double y = *j++;
153  myPruningBoundary.push_back(Position(x, y));
154  }
155  }
156  }
157  myNeedGeoTransformedPruningBoundary = oc.isSet("keep-edges.in-geo-boundary");
158  }
159 }
160 
161 
162 void
164  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
165  delete ((*i).second);
166  }
167  myEdges.clear();
168  for (EdgeCont::iterator i = myExtractedEdges.begin(); i != myExtractedEdges.end(); i++) {
169  delete ((*i).second);
170  }
171  myExtractedEdges.clear();
172 }
173 
174 
175 
176 // ----- edge access methods
177 bool
178 NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
179  if (myEdges.count(edge->getID()) != 0) {
180  return false;
181  }
182  if (!ignorePrunning && ignoreFilterMatch(edge)) {
183  edge->getFromNode()->removeEdge(edge);
184  edge->getToNode()->removeEdge(edge);
185  myIgnoredEdges.insert(edge->getID());
186  delete edge;
187  } else {
189  if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
191  }
192  myEdges[edge->getID()] = edge;
193  }
194  return true;
195 }
196 
197 
198 bool
200  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
201  if (edge->getSpeed() < myEdgesMinSpeed) {
202  return true;
203  }
204  // check whether the edge is a named edge to keep
205  if (!myRemoveEdgesAfterJoining && myEdges2Keep.size() != 0) {
206  if (myEdges2Keep.count(edge->getID()) == 0) {
207  // explicit whitelisting may be combined additively with other filters
209  && myTypes2Keep.size() == 0 && myTypes2Remove.size() == 0
210  && myPruningBoundary.size() == 0) {
211  return true;
212  }
213  } else {
214  // explicit whitelisting overrides other filters
215  return false;
216  }
217  }
218  // check whether the edge is a named edge to remove
219  if (myEdges2Remove.size() != 0) {
220  if (myEdges2Remove.count(edge->getID()) != 0) {
221  return true;
222  }
223  }
224  // check whether the edge shall be removed because it does not allow any of the wished classes
225  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
226  return true;
227  }
228  // check whether the edge shall be removed due to allowing unwished classes only
230  return true;
231  }
232  // check whether the edge shall be removed because it does not have one of the requested types
233  if (myTypes2Keep.size() != 0) {
234  if (myTypes2Keep.count(edge->getTypeID()) == 0) {
235  return true;
236  }
237  }
238  // check whether the edge shall be removed because it has one of the forbidden types
239  if (myTypes2Remove.size() != 0) {
240  if (myTypes2Remove.count(edge->getTypeID()) > 0) {
241  return true;
242  }
243  }
244  // check whether the edge is within the pruning boundary
245  if (myPruningBoundary.size() != 0) {
247  if (GeoConvHelper::getProcessing().usingGeoProjection()) {
249  } else if (GeoConvHelper::getLoaded().usingGeoProjection()) {
250  // XXX what if input file with different projections are loaded?
251  for (int i = 0; i < (int) myPruningBoundary.size(); i++) {
253  }
254  } else {
255  WRITE_ERROR("Cannot prune edges using a geo-boundary because no projection has been loaded");
256  }
258  }
259  if (!(edge->getGeometry().getBoxBoundary().grow(POSITION_EPS).overlapsWith(myPruningBoundary))) {
260  return true;
261  } else if (!(edge->getGeometry().partialWithin(myPruningBoundary, 2 * POSITION_EPS) || edge->getGeometry().intersects(myPruningBoundary))) {
262  // a more detailed check is necessary because the bounding box may be much bigger than the edge
263  // @note: overlapsWith implicitly closes the edge shape but this is not wanted here
264  return true;
265  }
266  }
268  return true;
269  }
270  return false;
271 }
272 
273 
274 NBEdge*
275 NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
276  EdgeCont::const_iterator i = myEdges.find(id);
277  if (i == myEdges.end()) {
278  if (retrieveExtracted) {
279  i = myExtractedEdges.find(id);
280  if (i == myExtractedEdges.end()) {
281  return nullptr;
282  }
283  } else {
284  return nullptr;
285  }
286  }
287  return (*i).second;
288 }
289 
290 // FIXME: This can't work
291 /*
292 NBEdge*
293 NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
294  NBEdge* edge = retrieve(id);
295  if (edge == 0) {
296  return 0;
297  }
298  const EdgeVector* candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
299  while (candidates->size() == 1) {
300  const std::string& nextID = candidates->front()->getID();
301  if (nextID.find(id) != 0 || nextID.size() <= id.size() + 1 || (nextID[id.size()] != '.' && nextID[id.size()] != '-')) {
302  break;
303  }
304  edge = candidates->front();
305  candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
306  }
307  return edge;
308 }*/
309 
310 NBEdge*
311 NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
312  NBEdge* edge = retrieve(id);
313  if (edge != nullptr) {
314  return edge;
315  }
316  // NOTE: (TODO) for multiply split edges (e.g. 15[0][0]) one could try recursion
317  if ((retrieve(id + "[0]") != nullptr) && (retrieve(id + "[1]") != nullptr)) {
318  // Edge was split during the netbuilding process
319  if (downstream == true) {
320  return retrieve(id + "[1]");
321  } else {
322  return retrieve(id + "[0]");
323  }
324  }
325  return edge;
326 }
327 
328 
329 NBEdge*
330 NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
331  // try to retrieve using the given name (iterative)
332  NBEdge* edge = retrieve(id);
333  if (edge != nullptr) {
334  return edge;
335  }
336  // now, we did not find it; we have to look over all possibilities
337  EdgeVector hints;
338  // check whether at least the hint was not splitted
339  NBEdge* hintedge = retrieve(hint);
340  if (hintedge == nullptr) {
341  hints = getGeneratedFrom(hint);
342  } else {
343  hints.push_back(hintedge);
344  }
345  EdgeVector candidates = getGeneratedFrom(id);
346  for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) {
347  NBEdge* hintedge = (*i);
348  for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) {
349  NBEdge* poss_searched = (*j);
350  NBNode* node = incoming
351  ? poss_searched->myTo : poss_searched->myFrom;
352  const EdgeVector& cont = incoming
353  ? node->getOutgoingEdges() : node->getIncomingEdges();
354  if (find(cont.begin(), cont.end(), hintedge) != cont.end()) {
355  return poss_searched;
356  }
357  }
358  }
359  return nullptr;
360 }
361 
362 
363 NBEdge*
364 NBEdgeCont::retrievePossiblySplit(const std::string& id, double pos) const {
365  // check whether the edge was not split, yet
366  NBEdge* edge = retrieve(id);
367  if (edge != nullptr) {
368  return edge;
369  }
370  int maxLength = 0;
371  std::string tid = id + "[";
372  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
373  if ((*i).first.find(tid) == 0) {
374  maxLength = MAX2(maxLength, (int)(*i).first.length());
375  }
376  }
377  // find the part of the edge which matches the position
378  double seen = 0;
379  std::vector<std::string> names;
380  names.push_back(id + "[1]");
381  names.push_back(id + "[0]");
382  while (names.size() > 0) {
383  // retrieve the first subelement (to follow)
384  std::string cid = names.back();
385  names.pop_back();
386  edge = retrieve(cid);
387  // The edge was splitted; check its subparts within the
388  // next step
389  if (edge == nullptr) {
390  if ((int)cid.length() + 3 < maxLength) {
391  names.push_back(cid + "[1]");
392  names.push_back(cid + "[0]");
393  }
394  }
395  // an edge with the name was found,
396  // check whether the position lies within it
397  else {
398  seen += edge->getLength();
399  if (seen >= pos) {
400  return edge;
401  }
402  }
403  }
404  return nullptr;
405 }
406 
407 
408 void
410  extract(dc, edge);
411  delete edge;
412 }
413 
414 
415 void
416 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
417  if (remember) {
418  myExtractedEdges[edge->getID()] = edge;
419  }
420  myEdges.erase(edge->getID());
421  edge->myFrom->removeEdge(edge);
422  edge->myTo->removeEdge(edge);
423  dc.removeFromSinksAndSources(edge);
424 }
425 
426 
427 void
428 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
429  if (myEdges.count(newID) != 0) {
430  throw ProcessError("Attempt to rename edge using existing id '" + newID + "'");
431  }
432  myEdges.erase(edge->getID());
433  edge->setID(newID);
434  myEdges[newID] = edge;
435 }
436 
437 
438 // ----- explicit edge manipulation methods
439 
440 void
441 NBEdgeCont::processSplits(NBEdge* e, std::vector<Split> splits,
443  if (splits.size() == 0) {
444  return;
445  }
446  const std::string origID = e->getID();
447  std::vector<Split>::iterator i;
448  sort(splits.begin(), splits.end(), split_sorter());
449  int noLanesMax = e->getNumLanes();
450  // compute the node positions and sort the lanes
451  for (i = splits.begin(); i != splits.end(); ++i) {
452  sort((*i).lanes.begin(), (*i).lanes.end());
453  noLanesMax = MAX2(noLanesMax, (int)(*i).lanes.size());
454  }
455  // split the edge
456  std::vector<int> currLanes;
457  for (int l = 0; l < e->getNumLanes(); ++l) {
458  currLanes.push_back(l);
459  }
460  if (e->getNumLanes() != (int)splits.back().lanes.size()) {
461  // invalidate traffic light definitions loaded from a SUMO network
462  e->getToNode()->invalidateTLS(tlc, true, true);
463  // if the number of lanes changes the connections should be
464  // recomputed
465  e->invalidateConnections(true);
466  }
467 
468  std::string firstID = "";
469  double seen = 0;
470  for (i = splits.begin(); i != splits.end(); ++i) {
471  const Split& exp = *i;
472  assert(exp.lanes.size() != 0);
473  if (exp.pos > 0 && e->getGeometry().length() + seen > exp.pos && exp.pos > seen) {
474  nc.insert(exp.node);
475  nc.markAsSplit(exp.node);
476  // split the edge
477  std::string idBefore = exp.idBefore == "" ? e->getID() : exp.idBefore;
478  std::string idAfter = exp.idAfter == "" ? exp.nameID : exp.idAfter;
479  if (firstID == "") {
480  firstID = idBefore;
481  }
482  const bool ok = splitAt(dc, e, exp.pos - seen, exp.node,
483  idBefore, idAfter, e->getNumLanes(), (int) exp.lanes.size(), exp.speed);
484  if (!ok) {
485  WRITE_WARNING("Error on parsing a split (edge '" + origID + "').");
486  }
487  seen = exp.pos;
488  std::vector<int> newLanes = exp.lanes;
489  NBEdge* pe = retrieve(idBefore);
490  NBEdge* ne = retrieve(idAfter);
491  // reconnect lanes
492  pe->invalidateConnections(true);
493  // new on right
494  int rightMostP = currLanes[0];
495  int rightMostN = newLanes[0];
496  for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
498  }
499  // new on left
500  int leftMostP = currLanes.back();
501  int leftMostN = newLanes.back();
502  for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
503  pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
504  }
505  // all other connected
506  for (int l = 0; l < noLanesMax; ++l) {
507  if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
508  continue;
509  }
510  if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
511  continue;
512  }
513  pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
514  }
515  // if there are edges at this node which are not connected
516  // we can assume that this split was attached to an
517  // existing node. Reset all connections to let the default
518  // algorithm recompute them
519  if (exp.node->getIncomingEdges().size() > 1 || exp.node->getOutgoingEdges().size() > 1) {
520  for (NBEdge* in : exp.node->getIncomingEdges()) {
521  in->invalidateConnections(true);
522  }
523  }
524  // move to next
525  e = ne;
526  currLanes = newLanes;
527  } else if (exp.pos == 0) {
528  const int laneCountDiff = e->getNumLanes() - (int)exp.lanes.size();
529  if (laneCountDiff < 0) {
530  e->incLaneNo(-laneCountDiff);
531  } else {
532  e->decLaneNo(laneCountDiff);
533  }
534  currLanes = exp.lanes;
535  // invalidate traffic light definition loaded from a SUMO network
536  // XXX it would be preferable to reconstruct the phase definitions heuristically
537  e->getFromNode()->invalidateTLS(tlc, true, true);
538  } else {
539  WRITE_WARNING("Split at '" + toString(exp.pos) + "' lies beyond the edge's length (edge '" + origID + "').");
540  }
541  }
542  // patch lane offsets
543  e = retrieve(firstID);
544  if (splits.front().pos != 0) {
545  // add a dummy split at the beginning to ensure correct offset
546  Split start;
547  start.pos = 0;
548  for (int lane = 0; lane < (int)e->getNumLanes(); ++lane) {
549  start.lanes.push_back(lane);
550  }
551  start.offset = splits.front().offset;
552  start.offsetFactor = splits.front().offsetFactor;
553  splits.insert(splits.begin(), start);
554  }
555  i = splits.begin();
556  if (e != nullptr) {
557  for (; i != splits.end(); ++i) {
558  int maxLeft = (*i).lanes.back();
559  double offset = (*i).offset;
560  if (maxLeft < noLanesMax) {
562  offset += (*i).offsetFactor * SUMO_const_laneWidthAndOffset * (noLanesMax - 1 - maxLeft);
563  } else {
564  offset += (*i).offsetFactor * SUMO_const_halfLaneAndOffset * (noLanesMax - 1 - maxLeft);
565  }
566  }
567  int maxRight = (*i).lanes.front();
568  if (maxRight > 0 && e->getLaneSpreadFunction() == LaneSpreadFunction::CENTER) {
569  offset -= (*i).offsetFactor * SUMO_const_halfLaneAndOffset * maxRight;
570  }
571  //std::cout << " processSplits " << origID << " splitOffset=" << (*i).offset << " offset=" << offset << "\n";
572  if (offset != 0) {
573  PositionVector g = e->getGeometry();
574  g.move2side(offset);
575  e->setGeometry(g);
576  }
577  if (e->getToNode()->getOutgoingEdges().size() != 0) {
578  e = e->getToNode()->getOutgoingEdges()[0];
579  }
580  }
581  }
582 }
583 
584 
585 bool
587  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
588  (int) edge->myLanes.size(), (int) edge->myLanes.size());
589 }
590 
591 
592 bool
594  const std::string& firstEdgeName,
595  const std::string& secondEdgeName,
596  int noLanesFirstEdge, int noLanesSecondEdge,
597  const double speed,
598  const int changedLeft) {
599  double pos;
600  pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
601  if (pos <= 0) {
603  edge->myFrom->getPosition(), edge->myTo->getPosition(),
604  node->getPosition());
605  }
606  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
607  return false;
608  }
609  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
610  noLanesFirstEdge, noLanesSecondEdge, speed, changedLeft);
611 }
612 
613 
614 bool
616  NBEdge* edge, double pos, NBNode* node,
617  const std::string& firstEdgeName,
618  const std::string& secondEdgeName,
619  int noLanesFirstEdge, int noLanesSecondEdge,
620  const double speed,
621  const int changedLeft
622  ) {
623  // there must be at least some overlap between first and second edge
624  assert(changedLeft > -((int)noLanesFirstEdge));
625  assert(changedLeft < (int)noLanesSecondEdge);
626 
627  // build the new edges' geometries
628  std::pair<PositionVector, PositionVector> geoms =
629  edge->getGeometry().splitAt(pos);
630  // build and insert the edges
631  NBEdge* one = new NBEdge(firstEdgeName, edge->myFrom, node, edge, geoms.first, noLanesFirstEdge);
632  NBEdge* two = new NBEdge(secondEdgeName, node, edge->myTo, edge, geoms.second, noLanesSecondEdge);
633  if (OptionsCont::getOptions().getBool("output.original-names")) {
634  const std::string origID = edge->getLaneStruct(0).getParameter(SUMO_PARAM_ORIGID, edge->getID());
635  if (firstEdgeName != origID) {
636  one->setOrigID(origID);
637  }
638  if (secondEdgeName != origID) {
639  two->setOrigID(origID);
640  }
641  }
642  two->copyConnectionsFrom(edge);
643  if (speed != -1.) {
644  two->setSpeed(-1, speed);
645  }
646  // replace information about this edge within the nodes
647  edge->myFrom->replaceOutgoing(edge, one, 0);
648  edge->myTo->replaceIncoming(edge, two, 0);
649  // patch tls
650  std::set<NBTrafficLightDefinition*> fromTLS = edge->myFrom->getControllingTLS();
651  for (std::set<NBTrafficLightDefinition*>::iterator i = fromTLS.begin(); i != fromTLS.end(); ++i) {
652  (*i)->replaceRemoved(edge, -1, one, -1, false);
653  }
654  std::set<NBTrafficLightDefinition*> toTLS = edge->myTo->getControllingTLS();
655  for (std::set<NBTrafficLightDefinition*>::iterator i = toTLS.begin(); i != toTLS.end(); ++i) {
656  (*i)->replaceRemoved(edge, -1, two, -1, true);
657  }
658  // the edge is now occuring twice in both nodes...
659  // clean up
660  edge->myFrom->removeDoubleEdges();
661  edge->myTo->removeDoubleEdges();
662  // add connections from the first to the second edge
663  // there will be as many connections as there are lanes on the second edge
664  // by default lanes will be added / discontinued on the right side
665  // (appropriate for highway on-/off-ramps)
666  const int offset = (int)one->getNumLanes() - (int)two->getNumLanes() + changedLeft;
667  for (int i2 = 0; i2 < (int)two->getNumLanes(); i2++) {
668  const int i1 = MIN2(MAX2((int)0, i2 + offset), (int)one->getNumLanes());
670  throw ProcessError("Could not set connection!");
671  }
672  }
674  if (myEdges2Keep.count(edge->getID()) != 0) {
675  myEdges2Keep.insert(one->getID());
676  myEdges2Keep.insert(two->getID());
677  }
678  if (myEdges2Remove.count(edge->getID()) != 0) {
679  myEdges2Remove.insert(one->getID());
680  myEdges2Remove.insert(two->getID());
681  }
682  }
683  // erase the splitted edge
684  patchRoundabouts(edge, one, two, myRoundabouts);
685  patchRoundabouts(edge, one, two, myGuessedRoundabouts);
686  const std::string oldID = edge->getID();
687  extract(dc, edge);
688  if (!insert(one, true)) {
689  WRITE_ERROR("Could not insert edge '" + one->getID() + "' before split of edge '" + oldID + "'");
690  };
691  if (!insert(two, true)) {
692  WRITE_ERROR("Could not insert edge '" + two->getID() + "' after split of edge '" + oldID + "'");
693  }
694  myEdgesSplit++;
695  return true;
696 }
697 
698 
699 void
700 NBEdgeCont::patchRoundabouts(NBEdge* orig, NBEdge* part1, NBEdge* part2, std::set<EdgeSet>& roundabouts) {
701  std::set<EdgeSet> addLater;
702  for (std::set<EdgeSet>::iterator it = roundabouts.begin(); it != roundabouts.end(); ++it) {
703  EdgeSet roundaboutSet = *it;
704  if (roundaboutSet.count(orig) > 0) {
705  roundaboutSet.erase(orig);
706  roundaboutSet.insert(part1);
707  roundaboutSet.insert(part2);
708  }
709  addLater.insert(roundaboutSet);
710  }
711  roundabouts.clear();
712  roundabouts.insert(addLater.begin(), addLater.end());
713 }
714 
715 
716 // ----- container access methods
717 std::vector<std::string>
719  std::vector<std::string> ret;
720  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
721  ret.push_back((*i).first);
722  }
723  return ret;
724 }
725 
726 
727 // ----- Adapting the input
728 void
730  EdgeVector toRemove;
731  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
732  NBEdge* edge = (*i).second;
733  if (!myEdges2Keep.count(edge->getID())) {
734  edge->getFromNode()->removeEdge(edge);
735  edge->getToNode()->removeEdge(edge);
736  toRemove.push_back(edge);
737  }
738  }
739  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
740  erase(dc, *j);
741  }
742 }
743 
744 
745 void
747  // make a copy of myEdges because splitting will modify it
748  EdgeCont edges = myEdges;
749  for (auto& item : edges) {
750  NBEdge* edge = item.second;
751  if (edge->getGeometry().size() < 3) {
752  continue;
753  }
754  PositionVector geom = edge->getGeometry();
755  const std::string id = edge->getID();
756  double offset = 0;
757  for (int i = 1; i < (int)geom.size() - 1; i++) {
758  offset += geom[i - 1].distanceTo(geom[i]);
759  std::string nodeID = id + "." + toString((int)offset);
760  if (!nc.insert(nodeID, geom[i])) {
761  WRITE_WARNING("Could not split geometry of edge '" + id + "' at index " + toString(i));
762  continue;
763  }
764  NBNode* node = nc.retrieve(nodeID);
765  splitAt(dc, edge, node, edge->getID(), nodeID, edge->getNumLanes(), edge->getNumLanes());
766  edge = retrieve(nodeID);
767  }
768  }
769 }
770 
771 
772 void
773 NBEdgeCont::reduceGeometries(const double minDist) {
774  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
775  (*i).second->reduceGeometry(minDist);
776  }
777 }
778 
779 
780 void
781 NBEdgeCont::checkGeometries(const double maxAngle, const double minRadius, bool fix, bool fixRailways, bool silent) {
782  if (maxAngle > 0 || minRadius > 0) {
783  for (auto& item : myEdges) {
784  if (isSidewalk(item.second->getPermissions()) || isForbidden(item.second->getPermissions())) {
785  continue;
786  }
787  item.second->checkGeometry(maxAngle, minRadius, fix || (fixRailways && isRailway(item.second->getPermissions())), silent);
788  }
789  }
790 }
791 
792 
793 // ----- processing methods
794 void
796  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
797  (*i).second->clearControllingTLInformation();
798  }
799 }
800 
801 
802 void
804  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
805  (*i).second->sortOutgoingConnectionsByAngle();
806  }
807 }
808 
809 
810 void
811 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
812  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
813  (*i).second->computeEdge2Edges(noLeftMovers);
814  }
815 }
816 
817 
818 void
820  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
821  (*i).second->computeLanes2Edges();
822  }
823 }
824 
825 
826 void
828  const bool fixOppositeLengths = OptionsCont::getOptions().getBool("opposites.guess.fix-lengths");
829  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
830  NBEdge* edge = i->second;
831  edge->recheckLanes();
832  // check opposites
833  if (edge->getNumLanes() > 0) {
834  int leftmostLane = edge->getNumLanes() - 1;
835  // check oppositeID stored in other lanes
836  for (int i = 0; i < leftmostLane; i++) {
837  const std::string& oppositeID = edge->getLanes()[i].oppositeID;
838  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
839  if (oppositeID != "" && oppositeID != "-") {
840  if (edge->getLanes().back().oppositeID == "" && oppEdge != nullptr) {
841  edge->getLaneStruct(leftmostLane).oppositeID = oppositeID;
842  WRITE_WARNING("Moving opposite lane '" + oppositeID + "' from invalid lane '" + edge->getLaneID(i) + "' to lane " + toString(leftmostLane) + ".");
843  } else {
844  WRITE_WARNING("Removing opposite lane '" + oppositeID + "' for invalid lane '" + edge->getLaneID(i) + "'.");
845  }
846  edge->getLaneStruct(i).oppositeID = "";
847  }
848  }
849  const std::string& oppositeID = edge->getLanes().back().oppositeID;
850  if (oppositeID != "" && oppositeID != "-") {
851  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
852  if (oppEdge == nullptr) {
853  WRITE_WARNING("Removing unknown opposite lane '" + oppositeID + "' for edge '" + edge->getID() + "'.");
854  edge->getLaneStruct(leftmostLane).oppositeID = "";
855  continue;
856  } else if (oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != oppositeID) {
857  const std::string oppEdgeLeftmost = oppEdge->getLaneID(oppEdge->getNumLanes() - 1);
858  WRITE_WARNING("Adapting invalid opposite lane '" + oppositeID + "' for edge '" + edge->getID() + "' to '" + oppEdgeLeftmost + "'");
859  edge->getLaneStruct(leftmostLane).oppositeID = oppEdgeLeftmost;
860  }
861  if (fabs(oppEdge->getLoadedLength() - edge->getLoadedLength()) > NUMERICAL_EPS) {
862  if (fixOppositeLengths) {
863  const double avgLength = 0.5 * (edge->getFinalLength() + oppEdge->getFinalLength());
864  WRITE_WARNING("Averaging edge lengths for lane '" + oppositeID + "' (length " + toString(oppEdge->getLoadedLength()) + ") and edge '" + edge->getID() + "' (length "
865  + toString(edge->getLoadedLength()) + ").");
866  edge->setLoadedLength(avgLength);
867  oppEdge->setLoadedLength(avgLength);
868  } else {
869  WRITE_ERROR("Opposite lane '" + oppositeID + "' (length " + toString(oppEdge->getLoadedLength()) + ") differs in length from edge '" + edge->getID() + "' (length "
870  + toString(edge->getLoadedLength()) + "). Set --opposites.guess.fix-lengths to fix this.");
871  edge->getLaneStruct(edge->getNumLanes() - 1).oppositeID = "";
872  continue;
873  }
874  }
875  if (oppEdge->getFromNode() != edge->getToNode() || oppEdge->getToNode() != edge->getFromNode()) {
876  WRITE_ERROR("Opposite lane '" + oppositeID + "' does not connect the same nodes as edge '" + edge->getID() + "'!");
877  edge->getLaneStruct(edge->getNumLanes() - 1).oppositeID = "";
878  }
879  }
880  }
881  }
882 }
883 
884 
885 void
886 NBEdgeCont::appendTurnarounds(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike) {
887  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
888  (*i).second->appendTurnaround(noTLSControlled, noFringe, onlyDeadends, onlyTurnlane, noGeometryLike, true);
889  }
890 }
891 
892 
893 void
894 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
895  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
896  myEdges[*it]->appendTurnaround(noTLSControlled, false, false, false, false, false);
897  }
898 }
899 
900 
901 void
903  std::set<std::string> stopEdgeIDs;
904  for (auto& stopItem : sc.getStops()) {
905  stopEdgeIDs.insert(stopItem.second->getEdgeId());
906  }
907  for (auto& item : myEdges) {
908  NBEdge* edge = item.second;
909  if (edge->isBidiRail()
910  && (stopEdgeIDs.count(item.first) > 0 ||
911  stopEdgeIDs.count(edge->getTurnDestination(true)->getID()) > 0)) {
912  NBEdge* to = edge->getTurnDestination(true);
913  assert(to != 0);
914  edge->setConnection(edge->getNumLanes() - 1,
915  to, to->getNumLanes() - 1, NBEdge::Lane2LaneInfoType::VALIDATED, false, false,
919  }
920  }
921 }
922 
923 void
924 NBEdgeCont::computeEdgeShapes(double smoothElevationThreshold) {
925  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
926  (*i).second->computeEdgeShape(smoothElevationThreshold);
927  }
928  // equalize length of opposite edges
929  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
930  NBEdge* edge = i->second;
931  const std::string& oppositeID = edge->getLanes().back().oppositeID;
932  if (oppositeID != "" && oppositeID != "-") {
933  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
934  if (oppEdge == nullptr || oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != oppositeID) {
935  continue;
936  }
937  if (fabs(oppEdge->getLength() - edge->getLength()) > NUMERICAL_EPS) {
938  double avgLength = (oppEdge->getLength() + edge->getLength()) / 2;
939  edge->setAverageLengthWithOpposite(avgLength);
940  oppEdge->setAverageLengthWithOpposite(avgLength);
941  }
942  }
943  }
944 }
945 
946 
947 void
949  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
950  (*i).second->computeLaneShapes();
951  }
952 }
953 
954 
955 void
958  EdgeVector edges) {
959  // !!! Attention!
960  // No merging of the geometry to come is being done
961  // The connections are moved from one edge to another within
962  // the replacement where the edge is a node's incoming edge.
963 
964  // count the number of lanes, the speed and the id
965  int nolanes = 0;
966  double speed = 0;
967  int priority = -1;
968  bool joinEdges = true;
969  std::string id;
970  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
971  // retrieve the connected nodes
972  NBEdge* tpledge = *(edges.begin());
973  NBNode* from = tpledge->getFromNode();
974  NBNode* to = tpledge->getToNode();
975  EdgeVector::const_iterator i;
976  int myPriority = (*edges.begin())->getPriority();
977  for (i = edges.begin(); i != edges.end(); i++) {
978  // some assertions
979  assert((*i)->getFromNode() == from);
980  assert((*i)->getToNode() == to);
981  // ad the number of lanes the current edge has
982  nolanes += (*i)->getNumLanes();
983  // build the id
984  if (i != edges.begin()) {
985  id += "+";
986  }
987  id += (*i)->getID();
988  // compute the speed
989  speed += (*i)->getSpeed();
990  // build the priority
991  // merged edges should have the same inherited priority
992  if (myPriority == (*i)->getPriority()) {
993  priority = myPriority;
994  } else {
995  priority = -1;
996  joinEdges = false;
997  }
998  }
999  if (joinEdges) {
1000  speed /= edges.size();
1001  // build the new edge
1002  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, nolanes, priority,
1004  tpledge->getStreetName(), tpledge->myLaneSpreadFunction);
1005  // copy lane attributes
1006  int laneIndex = 0;
1007  for (i = edges.begin(); i != edges.end(); ++i) {
1008  const std::vector<NBEdge::Lane>& lanes = (*i)->getLanes();
1009  for (int j = 0; j < (int)lanes.size(); ++j) {
1010  newEdge->setPermissions(lanes[j].permissions, laneIndex);
1011  newEdge->setLaneWidth(laneIndex, lanes[j].width);
1012  newEdge->setEndOffset(laneIndex, lanes[j].endOffset);
1013  laneIndex++;
1014  }
1015  }
1016  insert(newEdge, true);
1017  // replace old edge by current within the nodes
1018  // and delete the old
1019  from->replaceOutgoing(edges, newEdge);
1020  to->replaceIncoming(edges, newEdge);
1021  // patch connections
1022  // add edge2edge-information
1023  for (i = edges.begin(); i != edges.end(); i++) {
1024  EdgeVector ev = (*i)->getConnectedEdges();
1025  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
1026  newEdge->addEdge2EdgeConnection(*j);
1027  }
1028  }
1029  // copy outgoing connections to the new edge
1030  int currLane = 0;
1031  for (i = edges.begin(); i != edges.end(); i++) {
1032  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
1033  currLane += (*i)->getNumLanes();
1034  }
1035  // patch tl-information
1036  currLane = 0;
1037  for (i = edges.begin(); i != edges.end(); i++) {
1038  int noLanes = (*i)->getNumLanes();
1039  for (int j = 0; j < noLanes; j++, currLane++) {
1040  // replace in traffic lights
1041  tlc.replaceRemoved(*i, j, newEdge, currLane, true);
1042  tlc.replaceRemoved(*i, j, newEdge, currLane, false);
1043  }
1044  }
1045  // delete joined edges
1046  for (i = edges.begin(); i != edges.end(); i++) {
1047  extract(dc, *i, true);
1048  }
1049  }
1050 }
1051 
1052 
1053 void
1055  //@todo magic values
1056  const double distanceThreshold = 7;
1057  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1058  NBEdge* edge = i->second;
1059  const int numLanes = edge->getNumLanes();
1060  if (numLanes > 0) {
1061  NBEdge::Lane& lastLane = edge->getLaneStruct(numLanes - 1);
1062  if (lastLane.oppositeID == "") {
1063  NBEdge* opposite = nullptr;
1064  //double minOppositeDist = std::numeric_limits<double>::max();
1065  for (EdgeVector::const_iterator j = edge->getToNode()->getOutgoingEdges().begin(); j != edge->getToNode()->getOutgoingEdges().end(); ++j) {
1066  if ((*j)->getToNode() == edge->getFromNode() && !(*j)->getLanes().empty()) {
1067  const double distance = VectorHelper<double>::maxValue(lastLane.shape.distances((*j)->getLanes().back().shape));
1068  if (distance < distanceThreshold) {
1069  //minOppositeDist = distance;
1070  opposite = *j;
1071  }
1072  }
1073  }
1074  if (opposite != nullptr) {
1075  lastLane.oppositeID = opposite->getLaneID(opposite->getNumLanes() - 1);
1076  }
1077  }
1078  }
1079  }
1080 }
1081 
1082 
1083 void
1085  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1086  NBEdge* opposite = getOppositeByID(i->first);
1087  if (opposite != nullptr) {
1088  i->second->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
1090  } else {
1091  i->second->setLaneSpreadFunction(LaneSpreadFunction::CENTER);
1092  }
1093  }
1094 }
1095 
1096 
1097 NBEdge*
1098 NBEdgeCont::getOppositeByID(const std::string& edgeID) const {
1099  const std::string oppositeID = edgeID[0] == '-' ? edgeID.substr(1) : "-" + edgeID;
1100  EdgeCont::const_iterator it = myEdges.find(oppositeID);
1101  return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1102 }
1103 
1104 NBEdge*
1105 NBEdgeCont::getByID(const std::string& edgeID) const {
1106  EdgeCont::const_iterator it = myEdges.find(edgeID);
1107  return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1108 }
1109 
1110 // ----- other
1111 void
1112 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass,
1113  KeepClear keepClear, double contPos, double visibility, double speed, double length,
1114  const PositionVector& customShape, bool uncontrolled, bool warnOnly, SVCPermissions permissions) {
1115  myConnections[from].push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass, keepClear, contPos, visibility,
1116  speed, length, customShape, uncontrolled, warnOnly, permissions));
1117 }
1118 
1119 bool
1120 NBEdgeCont::hasPostProcessConnection(const std::string& from, const std::string& to) {
1121  if (myConnections.count(from) == 0) {
1122  return false;
1123  } else {
1124  if (to == "") {
1125  // wildcard
1126  return true;
1127  }
1128  for (const auto& ppc : myConnections[from]) {
1129  if (ppc.to == to) {
1130  return true;
1131  }
1132  }
1133  return false;
1134  }
1135 }
1136 
1137 void
1139  const bool warnOnly = OptionsCont::getOptions().exists("ignore-errors.connections") && OptionsCont::getOptions().getBool("ignore-errors.connections");
1140  for (const auto& item : myConnections) {
1141  for (std::vector<PostProcessConnection>::const_iterator i = item.second.begin(); i != item.second.end(); ++i) {
1142  NBEdge* from = retrievePossiblySplit((*i).from, true);
1143  NBEdge* to = retrievePossiblySplit((*i).to, false);
1144  if (from == nullptr || to == nullptr ||
1145  !from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::Lane2LaneInfoType::USER, true, (*i).mayDefinitelyPass,
1146  (*i).keepClear, (*i).contPos, (*i).visibility, (*i).speed, (*i).customLength, (*i).customShape,
1147  (*i).uncontrolled, SVC_UNSPECIFIED,
1148  true)) {
1149  const std::string msg = "Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.";
1150  if (warnOnly || (*i).warnOnly) {
1151  WRITE_WARNING(msg);
1152  } else {
1153  WRITE_ERROR(msg);
1154  }
1155  }
1156  }
1157  }
1158  // during loading we also kept some ambiguous connections in hope they might be valid after processing
1159  // we need to make sure that all invalid connections are removed now
1160  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
1161  NBEdge* edge = it->second;
1162  NBNode* to = edge->getToNode();
1163  // make a copy because we may delete connections
1164  std::vector<NBEdge::Connection> connections = edge->getConnections();
1165  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1166  NBEdge::Connection& c = *it_con;
1167  if (c.toEdge != nullptr && c.toEdge->getFromNode() != to) {
1168  WRITE_WARNING("Found and removed invalid connection from edge '" + edge->getID() +
1169  "' to edge '" + c.toEdge->getID() + "' via junction '" + to->getID() + "'.");
1170  edge->removeFromConnections(c.toEdge);
1171  }
1172  }
1173  }
1174 }
1175 
1176 
1177 EdgeVector
1178 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
1179  int len = (int)id.length();
1180  EdgeVector ret;
1181  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1182  std::string curr = (*i).first;
1183  // the next check makes it possibly faster - we don not have
1184  // to compare the names
1185  if ((int)curr.length() <= len) {
1186  continue;
1187  }
1188  // the name must be the same as the given id but something
1189  // beginning with a '[' must be appended to it
1190  if (curr.substr(0, len) == id && curr[len] == '[') {
1191  ret.push_back((*i).second);
1192  continue;
1193  }
1194  // ok, maybe the edge is a compound made during joining of edges
1195  std::string::size_type pos = curr.find(id);
1196  // surely not
1197  if (pos == std::string::npos) {
1198  continue;
1199  }
1200  // check leading char
1201  if (pos > 0) {
1202  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
1203  // actually, this is another id
1204  continue;
1205  }
1206  }
1207  if (pos + id.length() < curr.length()) {
1208  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
1209  // actually, this is another id
1210  continue;
1211  }
1212  }
1213  ret.push_back((*i).second);
1214  }
1215  return ret;
1216 }
1217 
1218 
1219 int
1221  myGuessedRoundabouts.clear();
1222  std::set<NBEdge*> loadedRoundaboutEdges;
1223  for (std::set<EdgeSet>::const_iterator it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1224  loadedRoundaboutEdges.insert(it->begin(), it->end());
1225  }
1226  // step 1: keep only those edges which have no turnarounds and which are not
1227  // part of a loaded roundabout
1228  std::set<NBEdge*> candidates;
1230  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1231  NBEdge* e = (*i).second;
1232  NBNode* const to = e->getToNode();
1233  if (e->getTurnDestination() == nullptr
1234  && to->getConnectionTo(e->getFromNode()) == nullptr
1235  && loadedRoundaboutEdges.count(e) == 0
1236  && (e->getPermissions() & valid) != 0) {
1237  candidates.insert(e);
1238  }
1239  }
1240 
1241  // step 2:
1242  std::set<NBEdge*> visited;
1243  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
1244  EdgeVector loopEdges;
1245  // start with a random edge (this doesn't have to be a roundabout edge)
1246  // loop over connected edges (using always the leftmost one)
1247  // and keep the list in loopEdges
1248  // continue until we loop back onto a loopEdges and extract the loop
1249  NBEdge* e = (*i);
1250  if (visited.count(e) > 0) {
1251  // already seen
1252  continue;
1253  }
1254  loopEdges.push_back(e);
1255  bool doLoop = true;
1256 #ifdef DEBUG_GUESS_ROUNDABOUT
1257  gDebugFlag1 = false;
1258 #endif
1259  do {
1260 #ifdef DEBUG_GUESS_ROUNDABOUT
1261  if (e->getID() == DEBUG_EDGE_ID || gDebugFlag1) {
1262  std::cout << " e=" << e->getID() << " loopEdges=" << toString(loopEdges) << "\n";
1263  gDebugFlag1 = true;
1264  }
1265 #endif
1266  visited.insert(e);
1267  const EdgeVector& edges = e->getToNode()->getEdges();
1269  doLoop = false;
1270 #ifdef DEBUG_GUESS_ROUNDABOUT
1271  if (gDebugFlag1) {
1272  std::cout << " rbl\n";
1273  }
1274  gDebugFlag1 = false;
1275 #endif
1276  break;
1277  }
1278  if (edges.size() < 2) {
1279  doLoop = false;
1280 #ifdef DEBUG_GUESS_ROUNDABOUT
1281  if (gDebugFlag1) {
1282  std::cout << " deadend\n";
1283  }
1284  gDebugFlag1 = false;
1285 #endif
1286  break;
1287  }
1288  if (e->getTurnDestination() != nullptr || e->getToNode()->getConnectionTo(e->getFromNode()) != nullptr) {
1289  // do not follow turn-arounds while in a (tentative) loop
1290  doLoop = false;
1291 #ifdef DEBUG_GUESS_ROUNDABOUT
1292  if (gDebugFlag1) {
1293  std::cout << " turn\n";
1294  }
1295  gDebugFlag1 = false;
1296 #endif
1297  break;
1298  }
1299  EdgeVector::const_iterator me = std::find(edges.begin(), edges.end(), e);
1300  NBContHelper::nextCW(edges, me);
1301  NBEdge* left = *me;
1302  while ((left->getPermissions() & valid) == 0 && left != e) {
1303  NBContHelper::nextCW(edges, me);
1304  left = *me;
1305  }
1306  if (left == e) {
1307  // no usable continuation edge found
1308  doLoop = false;
1309 #ifdef DEBUG_GUESS_ROUNDABOUT
1310  if (gDebugFlag1) {
1311  std::cout << " noContinuation\n";
1312  }
1313  gDebugFlag1 = false;
1314 #endif
1315  break;
1316  }
1317  NBContHelper::nextCW(edges, me);
1318  NBEdge* nextLeft = *me;
1319  double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
1320  double nextAngle = nextLeft == e ? 180 : fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), nextLeft->getAngleAtNode(e->getToNode())));
1321 #ifdef DEBUG_GUESS_ROUNDABOUT
1322  if (gDebugFlag1) {
1323  std::cout << " angle=" << angle << " nextAngle=" << nextAngle << "\n";
1324  }
1325 #endif
1326  if (angle >= 120
1327  || (angle >= 90 &&
1328  // if the edges are long or the junction shape is small we should expect roundness (low angles)
1329  (MAX2(e->getLength(), left->getLength()) > 5
1330  || e->getLaneShape(0).back().distanceTo2D(left->getLaneShape(0).front()) < 10
1331  // there should be no straigher edge further left
1332  || (nextAngle < 45)
1333  ))) {
1334  // roundabouts do not have sharp turns (or they wouldn't be called 'round')
1335  // however, if the roundabout is very small then most of the roundness may be in the junction so the angle may be as high as 120
1336  doLoop = false;
1337 #ifdef DEBUG_GUESS_ROUNDABOUT
1338  if (gDebugFlag1) {
1339  std::cout << " angle=" << angle << "\n";
1340  }
1341  gDebugFlag1 = false;
1342 #endif
1343  break;
1344  }
1345  EdgeVector::const_iterator loopClosed = std::find(loopEdges.begin(), loopEdges.end(), left);
1346  const int loopSize = (int)(loopEdges.end() - loopClosed);
1347  if (loopSize > 0) {
1348  // loop found
1349  if (loopSize < 3) {
1350  doLoop = false; // need at least 3 edges for a roundabout
1351  } else if (loopSize < (int)loopEdges.size()) {
1352  // remove initial edges not belonging to the loop
1353  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
1354  }
1355  // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
1356  int attachments = 0;
1357  for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
1358  if ((*j)->getToNode()->getEdges().size() > 2) {
1359  attachments++;
1360  }
1361  }
1362  if (attachments < 3) {
1363  doLoop = false;
1364 #ifdef DEBUG_GUESS_ROUNDABOUT
1365  if (gDebugFlag1) {
1366  std::cout << " attachments=" << attachments << "\n";
1367  }
1368  gDebugFlag1 = false;
1369 #endif
1370  }
1371  break;
1372  }
1373  if (visited.count(left) > 0) {
1374  doLoop = false;
1375  } else {
1376  // keep going
1377  loopEdges.push_back(left);
1378  e = left;
1379  }
1380  } while (doLoop);
1381 #ifdef DEBUG_GUESS_ROUNDABOUT
1382  gDebugFlag1 = false;
1383 #endif
1384  if (doLoop) {
1385  // check form factor to avoid elongated shapes (circle: 1, square: ~0.79)
1386  if (formFactor(loopEdges) > 0.6) {
1387  // collected edges are marked in markRoundabouts
1388  myGuessedRoundabouts.insert(EdgeSet(loopEdges.begin(), loopEdges.end()));
1389  }
1390  }
1391  }
1392  return (int)myGuessedRoundabouts.size();
1393 }
1394 
1395 
1396 double
1398  PositionVector points;
1399  for (EdgeVector::const_iterator it = loopEdges.begin(); it != loopEdges.end(); ++it) {
1400  points.append((*it)->getGeometry());
1401  }
1402  double circumference = points.length2D();
1403  return 4 * M_PI * points.area() / (circumference * circumference);
1404 }
1405 
1406 
1407 const std::set<EdgeSet>
1409  std::set<EdgeSet> result = myRoundabouts;
1410  result.insert(myGuessedRoundabouts.begin(), myGuessedRoundabouts.end());
1411  return result;
1412 }
1413 
1414 
1415 void
1417  if (roundabout.size() > 0) {
1418  if (find(myRoundabouts.begin(), myRoundabouts.end(), roundabout) != myRoundabouts.end()) {
1419  WRITE_WARNING("Ignoring duplicate roundabout: " + toString(roundabout));
1420  } else {
1421  myRoundabouts.insert(roundabout);
1422  }
1423  }
1424 }
1425 
1426 void
1428  for (auto it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1429  for (NBEdge* e : *it) {
1430  if (e->getToNode() == node) {
1431  myRoundabouts.erase(it);
1432  return;
1433  }
1434  }
1435  }
1436 }
1437 
1438 
1439 void
1441  for (const EdgeSet& roundaboutSet : getRoundabouts()) {
1442  for (NBEdge* const edge : roundaboutSet) {
1443  // disable turnarounds on incoming edges
1444  NBNode* const node = edge->getToNode();
1445  for (NBEdge* const inEdge : node->getIncomingEdges()) {
1446  if (roundaboutSet.count(inEdge) > 0) {
1447  continue;
1448  }
1449  if (inEdge->getStep() >= NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
1450  continue;
1451  }
1452  if (inEdge->getTurnDestination() != nullptr) {
1453  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
1454  }
1455  }
1456  // let the connections to succeeding roundabout edge have a higher priority
1457  edge->setJunctionPriority(node, NBEdge::JunctionPriority::ROUNDABOUT);
1458  edge->setJunctionPriority(edge->getFromNode(), NBEdge::JunctionPriority::ROUNDABOUT);
1459  node->setRoundabout();
1460  }
1461  }
1462 }
1463 
1464 
1465 void
1467  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1468  NBEdge* e = i->second;
1469  const double offset = MAX2(0., e->getLength() - 3);
1470  if (e->getToNode()->isSimpleContinuation(false)) {
1471  // not a "real" junction?
1472  continue;
1473  }
1474  const SumoXMLNodeType nodeType = e->getToNode()->getType();
1475  switch (nodeType) {
1477  // yield or major?
1478  if (e->getJunctionPriority(e->getToNode()) > 0) {
1480  } else {
1481  e->addSign(NBSign(NBSign::SIGN_TYPE_YIELD, offset));
1482  }
1483  break;
1485  // yield or major?
1486  if (e->getJunctionPriority(e->getToNode()) > 0) {
1488  } else {
1489  e->addSign(NBSign(NBSign::SIGN_TYPE_STOP, offset));
1490  }
1491  break;
1494  break;
1497  break;
1498  default:
1499  break;
1500  }
1501  }
1502 }
1503 
1504 
1505 int
1506 NBEdgeCont::guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string& excludeOpt) {
1507  int lanesCreated = 0;
1508  std::vector<std::string> edges;
1509  if (excludeOpt != "") {
1510  edges = OptionsCont::getOptions().getStringVector(excludeOpt);
1511  }
1512  std::set<std::string> exclude(edges.begin(), edges.end());
1513  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1514  NBEdge* edge = it->second;
1515  if (// not excluded
1516  exclude.count(edge->getID()) == 0
1517  // does not yet have a sidewalk
1518  && !edge->hasRestrictedLane(svc)
1519  && (
1520  // guess.from-permissions
1521  (fromPermissions && (edge->getPermissions() & svc) != 0)
1522  // guess from speed
1523  || (!fromPermissions && edge->getSpeed() > minSpeed && edge->getSpeed() <= maxSpeed)
1524  )) {
1525  edge->addRestrictedLane(width, svc);
1526  lanesCreated += 1;
1527  }
1528  }
1529  return lanesCreated;
1530 }
1531 
1532 
1533 int
1534 NBEdgeCont::remapIDs(bool numericaIDs, bool reservedIDs, const std::string& prefix, NBPTStopCont& sc) {
1535  bool startGiven = !OptionsCont::getOptions().isDefault("numerical-ids.edge-start");
1536  std::vector<std::string> avoid;
1537  if (startGiven) {
1538  avoid.push_back(toString(OptionsCont::getOptions().getInt("numerical-ids.edge-start") - 1));
1539  } else {
1540  avoid = getAllNames();
1541  }
1542  std::set<std::string> reserve;
1543  if (reservedIDs) {
1544  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "edge:", reserve);
1545  avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1546  }
1547  IDSupplier idSupplier("", avoid);
1548  std::set<NBEdge*, ComparatorIdLess> toChange;
1549  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1550  if (startGiven) {
1551  toChange.insert(it->second);
1552  continue;
1553  }
1554  if (numericaIDs) {
1555  try {
1556  StringUtils::toLong(it->first);
1557  } catch (NumberFormatException&) {
1558  toChange.insert(it->second);
1559  }
1560  }
1561  if (reservedIDs && reserve.count(it->first) > 0) {
1562  toChange.insert(it->second);
1563  }
1564  }
1565 
1566  std::map<std::string, std::vector<NBPTStop*> > stopsOnEdge;
1567  for (const auto& item : sc.getStops()) {
1568  stopsOnEdge[item.second->getEdgeId()].push_back(item.second);
1569  }
1570 
1571  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1572  for (NBEdge* edge : toChange) {
1573  myEdges.erase(edge->getID());
1574  }
1575  for (NBEdge* edge : toChange) {
1576  const std::string origID = edge->getID();
1577  if (origNames) {
1578  edge->setOrigID(origID);
1579  }
1580  edge->setID(idSupplier.getNext());
1581  myEdges[edge->getID()] = edge;
1582  for (NBPTStop* stop : stopsOnEdge[origID]) {
1583  stop->setEdgeId(prefix + edge->getID(), *this);
1584  }
1585  }
1586  if (prefix.empty()) {
1587  return (int)toChange.size();
1588  } else {
1589  int renamed = 0;
1590  // make a copy because we will modify the map
1591  auto oldEdges = myEdges;
1592  for (auto item : oldEdges) {
1593  if (!StringUtils::startsWith(item.first, prefix)) {
1594  rename(item.second, prefix + item.first);
1595  renamed++;
1596  }
1597  }
1598  return renamed;
1599  }
1600 }
1601 
1602 
1603 void
1604 NBEdgeCont::checkOverlap(double threshold, double zThreshold) const {
1605  for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1606  const NBEdge* e1 = it->second;
1607  Boundary b1 = e1->getGeometry().getBoxBoundary();
1608  b1.grow(e1->getTotalWidth());
1609  PositionVector outline1 = e1->getCCWBoundaryLine(*e1->getFromNode());
1610  outline1.append(e1->getCCWBoundaryLine(*e1->getToNode()));
1611  // check is symmetric. only check once per pair
1612  for (EdgeCont::const_iterator it2 = it; it2 != myEdges.end(); it2++) {
1613  const NBEdge* e2 = it2->second;
1614  if (e1 == e2) {
1615  continue;
1616  }
1617  Boundary b2 = e2->getGeometry().getBoxBoundary();
1618  b2.grow(e2->getTotalWidth());
1619  if (b1.overlapsWith(b2)) {
1620  PositionVector outline2 = e2->getCCWBoundaryLine(*e2->getFromNode());
1621  outline2.append(e2->getCCWBoundaryLine(*e2->getToNode()));
1622  const double overlap = outline1.getOverlapWith(outline2, zThreshold);
1623  if (overlap > threshold) {
1624  WRITE_WARNINGF("Edge '%' overlaps with edge '%' by %.", e1->getID(), e2->getID(), toString(overlap));
1625  }
1626  }
1627  }
1628  }
1629 }
1630 
1631 
1632 void
1633 NBEdgeCont::checkGrade(double threshold) const {
1634  for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1635  const NBEdge* edge = it->second;
1636  for (int i = 0; i < (int)edge->getNumLanes(); i++) {
1637  double maxJump = 0;
1638  const double grade = edge->getLaneShape(i).getMaxGrade(maxJump);
1639  if (maxJump > 0.01) {
1640  WRITE_WARNINGF("Edge '%s' has a vertical jump of %sm.", edge->getID(), toString(maxJump));
1641  } else if (grade > threshold) {
1642  WRITE_WARNINGF("Edge '%' has a grade of %%.", edge->getID(), toString(grade * 100), "%");
1643  break;
1644  }
1645  }
1646  const std::vector<NBEdge::Connection>& connections = edge->getConnections();
1647  for (std::vector<NBEdge::Connection>::const_iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1648  const NBEdge::Connection& c = *it_con;
1649  double maxJump = 0;
1650  const double grade = MAX2(c.shape.getMaxGrade(maxJump), c.viaShape.getMaxGrade(maxJump));
1651  if (maxJump > 0.01) {
1652  WRITE_WARNINGF("Connection '%' has a vertical jump of %m.", c.getDescription(edge), toString(maxJump));
1653  } else if (grade > threshold) {
1654  WRITE_WARNINGF("Connection '%' has a grade of %%.", c.getDescription(edge), toString(grade * 100), "%");
1655  break;
1656  }
1657  }
1658  }
1659 }
1660 
1661 int
1663  int affectedEdges = 0;
1664  for (auto item : myEdges) {
1665  if (item.second->joinLanes(perms)) {
1666  affectedEdges++;
1667  }
1668  }
1669  return affectedEdges;
1670 }
1671 
1672 
1673 int
1675  // this is different from joinSimilarEdges because there don't need to be
1676  // shared nodes and tram edges may be split
1677  std::set<NBEdge*> tramEdges;
1678  std::set<NBEdge*> targetEdges;
1679  for (auto item : myEdges) {
1680  SVCPermissions permissions = item.second->getPermissions();
1681  if (permissions == SVC_TRAM) {
1682  if (item.second->getNumLanes() == 1) {
1683  tramEdges.insert(item.second);
1684  } else {
1685  WRITE_WARNINGF("Not joining tram edge '%s' with % lanes", item.second->getID(), item.second->getNumLanes());
1686  }
1687  } else if ((permissions & SVC_PASSENGER) != 0) {
1688  targetEdges.insert(item.second);
1689  }
1690  }
1691  if (tramEdges.size() == 0 || targetEdges.size() == 0) {
1692  return 0;
1693  }
1694  int numJoined = 0;
1695  NamedRTree tramTree;
1696  for (NBEdge* edge : tramEdges) {
1697  const Boundary& bound = edge->getGeometry().getBoxBoundary();
1698  float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1699  float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1700  tramTree.Insert(min, max, edge);
1701  }
1702  // {targetEdge, laneIndex : tramEdge}
1703  std::map<std::pair<NBEdge*, int>, NBEdge*> matches;
1704 
1705  for (NBEdge* edge : targetEdges) {
1706  Boundary bound = edge->getGeometry().getBoxBoundary();
1707  bound.grow(maxDist + edge->getTotalWidth());
1708  float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1709  float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1710  std::set<const Named*> nearby;
1711  Named::StoringVisitor visitor(nearby);
1712  tramTree.Search(min, max, visitor);
1713  for (const Named* namedEdge : nearby) {
1714  // find a continous stretch of tramEdge that runs along one of the
1715  // lanes of the road edge
1716  NBEdge* tramEdge = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
1717  const PositionVector& tramShape = tramEdge->getGeometry();
1718  double minEdgeDist = maxDist + 1;
1719  int minLane = -1;
1720  // find the lane where the maximum distance from the tram geometry
1721  // is minimal and within maxDist
1722  for (int i = 0; i < edge->getNumLanes(); i++) {
1723  double maxLaneDist = -1;
1724  if ((edge->getPermissions(i) & SVC_PASSENGER) != 0) {
1725  const PositionVector& laneShape = edge->getLaneShape(i);
1726  for (Position pos : laneShape) {
1727  const double dist = tramShape.distance2D(pos, false);
1728 #ifdef DEBUG_JOIN_TRAM
1729  //if (edge->getID() == "106838214#1") {
1730  // std::cout << " edge=" << edge->getID() << " tramEdge=" << tramEdge->getID() << " lane=" << i << " pos=" << pos << " dist=" << dist << "\n";
1731  //}
1732 #endif
1733  if (dist == GeomHelper::INVALID_OFFSET || dist > maxDist) {
1734  maxLaneDist = -1;
1735  break;
1736  }
1737  maxLaneDist = MAX2(maxLaneDist, dist);
1738  }
1739  if (maxLaneDist >= 0 && maxLaneDist < minEdgeDist) {
1740  minEdgeDist = maxLaneDist;
1741  minLane = i;
1742  }
1743  }
1744  }
1745  if (minLane >= 0) {
1746  // edge could run in the wrong direction and still fit the threshold we check the angle as well
1747  const PositionVector& laneShape = edge->getLaneShape(minLane);
1748  const double offset1 = tramShape.nearest_offset_to_point2D(laneShape.front(), false);
1749  const double offset2 = tramShape.nearest_offset_to_point2D(laneShape.back(), false);
1750  Position p1 = tramShape.positionAtOffset2D(offset1);
1751  Position p2 = tramShape.positionAtOffset2D(offset2);
1752  double tramAngle = GeomHelper::legacyDegree(p1.angleTo2D(p2), true);
1753  bool angleOK = GeomHelper::getMinAngleDiff(tramAngle, edge->getTotalAngle()) < JOIN_TRAM_MAX_ANGLE;
1754  if (angleOK && offset2 > offset1) {
1755  std::pair<NBEdge*, int> key = std::make_pair(edge, minLane);
1756  if (matches.count(key) == 0) {
1757  matches[key] = tramEdge;
1758  } else {
1759  WRITE_WARNINGF("Ambiguous tram edges '%' and '%' for lane '%'", matches[key]->getID(), tramEdge->getID(), edge->getLaneID(minLane));
1760  }
1761 #ifdef DEBUG_JOIN_TRAM
1762  std::cout << edge->getLaneID(minLane) << " is close to tramEdge " << tramEdge->getID() << " maxLaneDist=" << minEdgeDist << " tramLength=" << tramEdge->getLength() << " edgeLength=" << edge->getLength() << " tramAngle=" << tramAngle << " edgeAngle=" << edge->getTotalAngle() << "\n";
1763 #endif
1764  }
1765  }
1766  }
1767  }
1768  if (matches.size() == 0) {
1769  return 0;
1770  }
1771  // find continous runs of matched edges for each tramEdge
1772  for (NBEdge* tramEdge : tramEdges) {
1773  std::vector<std::pair<double, std::pair<NBEdge*, int> > > roads;
1774  for (auto item : matches) {
1775  if (item.second == tramEdge) {
1776  NBEdge* road = item.first.first;
1777  int laneIndex = item.first.second;
1778  const PositionVector& laneShape = road->getLaneShape(laneIndex);
1779  double tramPos = tramEdge->getGeometry().nearest_offset_to_point2D(laneShape.front(), false);
1780  roads.push_back(std::make_pair(tramPos, item.first));
1781  }
1782  }
1783  if (roads.size() != 0) {
1784 
1785  sort(roads.begin(), roads.end());
1786 #ifdef DEBUG_JOIN_TRAM
1787  std::cout << " tramEdge=" << tramEdge->getID() << " roads=";
1788  for (auto item : roads) {
1789  std::cout << item.second.first->getLaneID(item.second.second) << ",";
1790  }
1791  std::cout << " offsets=";
1792  for (auto item : roads) {
1793  std::cout << item.first << ",";
1794  }
1795  std::cout << "\n";
1796 #endif
1797  // merge tramEdge into road lanes
1798  EdgeVector replacement;
1799  double pos = 0;
1800  int tramPart = 0;
1801  std::string tramEdgeID = tramEdge->getID();
1802  NBNode* tramFrom = tramEdge->getFromNode();
1803  PositionVector tramShape = tramEdge->getGeometry();
1804  const double tramLength = tramShape.length();
1805  EdgeVector incoming = tramFrom->getIncomingEdges();
1806  bool erasedLast = false;
1807  for (auto item : roads) {
1808  const double gap = item.first - pos;
1809  NBEdge* road = item.second.first;
1810  int laneIndex = item.second.second;
1811  if (gap >= JOIN_TRAM_MIN_LENGTH) {
1812 #ifdef DEBUG_JOIN_TRAM
1813  std::cout << " splitting tramEdge=" << tramEdge->getID() << " at " << item.first << " (gap=" << gap << ")\n";
1814 #endif
1815  const std::string firstPartID = tramEdgeID + "#" + toString(tramPart++);
1816  splitAt(dc, tramEdge, gap, road->getFromNode(), firstPartID, tramEdgeID, 1, 1);
1817  tramEdge = retrieve(tramEdgeID); // second part;
1818  NBEdge* firstPart = retrieve(firstPartID);
1819  firstPart->invalidateConnections(true);
1820  incoming.clear();
1821  incoming.push_back(firstPart);
1822  replacement.push_back(firstPart);
1823  }
1824  pos = item.first + road->getGeometry().length();
1825  numJoined++;
1826  replacement.push_back(road);
1827  // merge section of tramEdge into road lane
1828  if (road->getToNode() != tramEdge->getToNode() && (tramLength - pos) >= JOIN_TRAM_MIN_LENGTH) {
1829  tramEdge->reinitNodes(road->getToNode(), tramEdge->getToNode());
1830  tramEdge->setGeometry(tramShape.getSubpart(pos, tramShape.length()));
1831  erasedLast = false;
1832 #ifdef DEBUG_JOIN_TRAM
1833  std::cout << " shorted tramEdge=" << tramEdge->getID() << " (joined with roadEdge=" << road->getID() << "\n";
1834 #endif
1835  } else {
1836 #ifdef DEBUG_JOIN_TRAM
1837  std::cout << " erased tramEdge=" << tramEdge->getID() << "\n";
1838 #endif
1839  extract(dc, tramEdge);
1840  erasedLast = true;
1841  }
1842  road->setPermissions(road->getPermissions(laneIndex) | SVC_TRAM, laneIndex);
1843  for (NBEdge* in : incoming) {
1844  if (in->getPermissions() == SVC_TRAM && !in->isConnectedTo(road)) {
1845  if (in->getFromNode() != road->getFromNode()) {
1846  in->reinitNodes(in->getFromNode(), road->getFromNode());
1847  } else {
1848  extract(dc, in);
1849 #ifdef DEBUG_JOIN_TRAM
1850  std::cout << " erased incoming tramEdge=" << in->getID() << "\n";
1851 #endif
1852  }
1853  }
1854  }
1855  incoming.clear();
1856  }
1857  NBEdge* lastRoad = roads.back().second.first;
1858  if (erasedLast) {
1859  for (NBEdge* out : tramEdge->getToNode()->getOutgoingEdges()) {
1860  if (out->getPermissions() == SVC_TRAM && !lastRoad->isConnectedTo(out)) {
1861  if (lastRoad->getToNode() != out->getToNode()) {
1862  out->reinitNodes(lastRoad->getToNode(), out->getToNode());
1863  } else {
1864  extract(dc, out);
1865 #ifdef DEBUG_JOIN_TRAM
1866  std::cout << " erased outgoing tramEdge=" << out->getID() << "\n";
1867 #endif
1868 
1869  }
1870  }
1871  }
1872  } else {
1873  replacement.push_back(tramEdge);
1874  }
1875  // update ptlines
1876  lc.replaceEdge(tramEdgeID, replacement);
1877  }
1878  }
1879 
1880  return numJoined;
1881 }
1882 
1883 
1884 EdgeVector
1886  EdgeVector result;
1887  for (auto item : myEdges) {
1888  item.second->setNumericalID((int)result.size());
1889  result.push_back(item.second);
1890  }
1891  return result;
1892 }
1893 
1896  EdgeVector all = getAllEdges();
1897  return RouterEdgeVector(all.begin(), all.end());
1898 }
1899 
1900 bool
1902  bool ok = true;
1903  for (const auto& item : myEdges) {
1904  NBEdge* e = item.second;
1905  if (nc.retrieve(e->getFromNode()->getID()) == nullptr) {
1906  WRITE_ERROR("Edge's '" + e->getID() + "' from-node '" + e->getFromNode()->getID() + "' is not known.");
1907  ok = false;
1908  }
1909  if (nc.retrieve(e->getToNode()->getID()) == nullptr) {
1910  WRITE_ERROR("Edge's '" + e->getID() + "' to-node '" + e->getToNode()->getID() + "' is not known.");
1911  ok = false;
1912  }
1913 
1914  }
1915  return ok;
1916 }
1917 
1918 
1919 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:277
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
std::set< NBEdge * > EdgeSet
container for unique edges
Definition: NBCont.h:49
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
KeepClear
keepClear status of connections
Definition: NBCont.h:57
@ KEEPCLEAR_UNSPECIFIED
Definition: NBCont.h:60
std::vector< NBRouterEdge * > RouterEdgeVector
Definition: NBCont.h:42
#define JOIN_TRAM_MIN_LENGTH
Definition: NBEdgeCont.cpp:54
#define JOIN_TRAM_MAX_ANGLE
Definition: NBEdgeCont.cpp:53
#define DEBUG_EDGE_ID
Definition: NBEdgeCont.cpp:58
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
SVCPermissions parseVehicleClasses(const std::string &allowedS)
Parses the given definition of allowed vehicle classes into the given containers Deprecated classes g...
bool isSidewalk(SVCPermissions permissions)
Returns whether an edge with the given permission is a sidewalk.
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const std::string SUMO_PARAM_ORIGID
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:31
T MIN2(T a, T b)
Definition: StdDefs.h:73
const double SUMO_const_laneWidthAndOffset
Definition: StdDefs.h:51
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:60
T MAX2(T a, T b)
Definition: StdDefs.h:79
const double SUMO_const_halfLaneAndOffset
Definition: StdDefs.h:52
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:129
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:117
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:299
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns whether the boundary overlaps with the given polygon.
Definition: Boundary.cpp:180
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:135
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:123
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:84
static GeoConvHelper & getLoaded()
the coordinate transformation that was loaded fron an input file
Definition: GeoConvHelper.h:89
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation.
static PositionVector parseShapeReporting(const std::string &shpdef, const std::string &objecttype, const char *objectid, bool &ok, bool allowEmpty, bool report=true)
Builds a PositionVector from a string representation, reporting occurred errors.
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:50
static double nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
Definition: GeomHelper.cpp:88
static double legacyDegree(const double angle, const bool positive=false)
Definition: GeomHelper.cpp:215
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:173
std::string getNext()
Returns the next id.
Definition: IDSupplier.cpp:51
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
A container for districts.
void removeFromSinksAndSources(NBEdge *const e)
Removes the given edge from the lists of sources and sinks in all stored districts.
Sorts splits by their position (increasing)
Definition: NBEdgeCont.h:739
void patchRoundabouts(NBEdge *orig, NBEdge *part1, NBEdge *part2, std::set< EdgeSet > &roundabouts)
fix roundabout information after splitting an edge
Definition: NBEdgeCont.cpp:700
void computeEdgeShapes(double smoothElevationThreshold=-1)
Computes the shapes of all edges stored in the container.
Definition: NBEdgeCont.cpp:924
void removeUnwishedEdges(NBDistrictCont &dc)
Removes unwished edges (not in keep-edges)
Definition: NBEdgeCont.cpp:729
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
void computeEdge2Edges(bool noLeftMovers)
Computes for each edge the approached edges.
Definition: NBEdgeCont.cpp:811
int guessRoundabouts()
Determines which edges belong to roundabouts and increases their priority.
bool myNeedGeoTransformedPruningBoundary
whether a geo transform has been applied to the pruning boundary
Definition: NBEdgeCont.h:728
~NBEdgeCont()
Destructor.
Definition: NBEdgeCont.cpp:72
void sortOutgoingLanesConnections()
Sorts all lanes of all edges within the container by their direction.
Definition: NBEdgeCont.cpp:803
void addRoundabout(const EdgeSet &roundabout)
add user specified roundabout
std::set< EdgeSet > myRoundabouts
Edges marked as belonging to a roundabout by the user (each EdgeVector is a roundabout)
Definition: NBEdgeCont.h:732
void appendRailwayTurnarounds(const NBPTStopCont &sc)
Appends turnarounds to all bidiRail edges with stops.
Definition: NBEdgeCont.cpp:902
std::set< std::string > myEdges2Remove
Set of ids of edges which shall explicitly be removed.
Definition: NBEdgeCont.h:710
std::set< std::string > myIgnoredEdges
The ids of ignored edges.
Definition: NBEdgeCont.h:692
double myEdgesMinSpeed
The minimum speed an edge may have in order to be kept (default: -1)
Definition: NBEdgeCont.h:701
int myEdgesSplit
the number of splits of edges during the building
Definition: NBEdgeCont.h:695
void recheckPostProcessConnections()
Try to set any stored connections.
void checkGeometries(const double maxAngle, const double minRadius, bool fix, bool fixRailways, bool silent=false)
Definition: NBEdgeCont.cpp:781
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:416
void processSplits(NBEdge *e, std::vector< Split > splits, NBNodeCont &nc, NBDistrictCont &dc, NBTrafficLightLogicCont &tlc)
Definition: NBEdgeCont.cpp:441
EdgeVector getAllEdges() const
return all edges
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:409
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:275
std::set< std::string > myTypes2Keep
Set of edges types which shall be kept.
Definition: NBEdgeCont.h:719
void recheckLanes()
Rechecks whether all lanes have a successor for each of the stored edges.
Definition: NBEdgeCont.cpp:827
NBEdge * getOppositeByID(const std::string &edgeID) const
Returns the edge with negated id if it exists.
EdgeCont myExtractedEdges
The extracted nodes which are kept for reference.
Definition: NBEdgeCont.h:689
void reduceGeometries(const double minDist)
Definition: NBEdgeCont.cpp:773
void recheckLaneSpread()
Rechecks whether the lane spread is proper.
bool ignoreFilterMatch(NBEdge *edge)
Returns true if this edge matches one of the removal criteria.
Definition: NBEdgeCont.cpp:199
void removeRoundabout(const NBNode *node)
remove roundabout that contains the given node
void splitGeometry(NBDistrictCont &dc, NBNodeCont &nc)
Splits edges into multiple if they have a complex geometry.
Definition: NBEdgeCont.cpp:746
void computeLanes2Edges()
Computes for each edge which lanes approach the next edges.
Definition: NBEdgeCont.cpp:819
NBEdge * retrievePossiblySplit(const std::string &id, bool downstream) const
Tries to retrieve an edge, even if it is splitted.
Definition: NBEdgeCont.cpp:311
RouterEdgeVector getAllRouterEdges() const
void rename(NBEdge *edge, const std::string &newID)
Renames the edge. Throws exception if newID already exists.
Definition: NBEdgeCont.cpp:428
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
EdgeCont myEdges
The instance of the dictionary (id->edge)
Definition: NBEdgeCont.h:686
std::set< std::string > myEdges2Keep
Set of ids of edges which shall explicitly be kept.
Definition: NBEdgeCont.h:707
NBTypeCont & myTypeCont
The network builder; used to obtain type information.
Definition: NBEdgeCont.h:619
void generateStreetSigns()
assigns street signs to edges based on toNode types
void clearControllingTLInformation() const
Clears information about controlling traffic lights for all connenections of all edges.
Definition: NBEdgeCont.cpp:795
std::set< EdgeSet > myGuessedRoundabouts
Edges marked as belonging to a roundabout after guessing.
Definition: NBEdgeCont.h:734
void clear()
Deletes all edges.
Definition: NBEdgeCont.cpp:163
void guessOpposites()
Sets opposite lane information for geometrically close edges.
void markRoundabouts()
mark edge priorities and prohibit turn-arounds for all roundabout edges
std::set< std::string > myTypes2Remove
Set of edges types which shall be removed.
Definition: NBEdgeCont.h:722
void applyOptions(OptionsCont &oc)
Initialises the storage by applying given options.
Definition: NBEdgeCont.cpp:78
PositionVector myPruningBoundary
Boundary within which an edge must be located in order to be kept.
Definition: NBEdgeCont.h:725
int joinLanes(SVCPermissions perms)
join adjacent lanes with the given permissions
void checkOverlap(double threshold, double zThreshold) const
check whether edges overlap
SVCPermissions myVehicleClasses2Remove
Set of vehicle types which need not be supported (edges which allow ONLY these are removed)
Definition: NBEdgeCont.h:716
EdgeVector getGeneratedFrom(const std::string &id) const
Returns the edges which have been built by splitting the edge of the given id.
void appendTurnarounds(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike)
Appends turnarounds to all edges stored in the container.
Definition: NBEdgeCont.cpp:886
SVCPermissions myVehicleClasses2Keep
Set of vehicle types which must be allowed on edges in order to keep them.
Definition: NBEdgeCont.h:713
void computeLaneShapes()
Computes the shapes of all lanes of all edges stored in the container.
Definition: NBEdgeCont.cpp:948
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
Definition: NBEdgeCont.cpp:956
bool myRemoveEdgesAfterJoining
Whether edges shall be joined first, then removed.
Definition: NBEdgeCont.h:704
std::map< std::string, NBEdge * > EdgeCont
The type of the dictionary where an edge may be found by its id.
Definition: NBEdgeCont.h:683
void addPostProcessConnection(const std::string &from, int fromLane, const std::string &to, int toLane, bool mayDefinitelyPass, KeepClear keepClear, double contPos, double visibility, double speed, double length, const PositionVector &customShape, bool uncontrolled, bool warnOnly, SVCPermissions permissions=SVC_UNSPECIFIED)
Adds a connection which could not be set during loading.
std::map< std::string, std::vector< PostProcessConnection > > myConnections
The list of connections to recheck.
Definition: NBEdgeCont.h:679
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:178
NBEdgeCont(NBTypeCont &tc)
Constructor.
Definition: NBEdgeCont.cpp:63
int joinTramEdges(NBDistrictCont &dc, NBPTLineCont &lc, double maxDist)
join tram edges into adjacent lanes
int guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string &excludeOpt)
add sidwalks to edges within the given limits or permissions and return the number of edges affected
int remapIDs(bool numericaIDs, bool reservedIDs, const std::string &prefix, NBPTStopCont &sc)
remap node IDs accoring to options –numerical-ids and –reserved-ids
bool checkConsistency(const NBNodeCont &nc)
ensure that all edges have valid nodes
static double formFactor(const EdgeVector &loopEdges)
compute the form factor for a loop of edges
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
Definition: NBEdgeCont.cpp:586
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
Definition: NBEdgeCont.cpp:718
void checkGrade(double threshold) const
check whether edges are to steep
The representation of a single edge during network building.
Definition: NBEdge.h:91
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false)
Adds a connection to another edge.
Definition: NBEdge.cpp:985
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:563
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3655
void setPermissions(SVCPermissions permissions, int lane=-1)
set allowed/disallowed classes for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:3627
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:572
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3597
void reinitNodes(NBNode *from, NBNode *to)
Resets nodes but keeps all other values the same (used when joining)
Definition: NBEdge.cpp:428
PositionVector getCCWBoundaryLine(const NBNode &n) const
get the outer boundary of this edge when going counter-clock-wise around the given node
Definition: NBEdge.cpp:3161
void setOrigID(const std::string origID)
set origID for all lanes
Definition: NBEdge.cpp:3975
void incLaneNo(int by)
increment lane
Definition: NBEdge.cpp:3402
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:618
void setAverageLengthWithOpposite(double val)
patch average lane length in regard to the opposite edge
Definition: NBEdge.cpp:3675
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition: NBEdge.h:803
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:713
void dismissVehicleClassInformation()
dimiss vehicle class information
Definition: NBEdge.cpp:3681
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1654
const std::string & getID() const
Definition: NBEdge.h:1423
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:677
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:516
@ LANES2LANES_USER
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:589
NBNode * myTo
Definition: NBEdge.h:1609
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3491
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:907
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1671
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:490
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:716
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition: NBEdge.h:333
void addRestrictedLane(double width, SUMOVehicleClass vclass)
add a lane of the given width, restricted to the given class and shift existing connections
Definition: NBEdge.cpp:3851
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false, const bool keepPossibleTurns=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1318
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1399
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:3528
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
Definition: NBEdge.h:336
bool isConnectedTo(const NBEdge *e, const bool ignoreTurnaround=false) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition: NBEdge.cpp:1201
void addSign(NBSign sign)
add Sign
Definition: NBEdge.h:1358
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition: NBEdge.cpp:3033
std::string getLaneID(int lane) const
get lane ID
Definition: NBEdge.cpp:3345
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1066
@ USER
The connection was given by the user.
@ VALIDATED
The connection was computed and validated.
@ COMPUTED
The connection was computed.
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1920
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3336
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1946
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:324
bool hasRestrictedLane(SUMOVehicleClass vclass) const
returns whether any lane already allows the given vclass exclusively
Definition: NBEdge.cpp:3840
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:964
void copyConnectionsFrom(NBEdge *src)
copy connections from antoher edge
Definition: NBEdge.cpp:1514
const std::string & getTypeID() const
get ID of type
Definition: NBEdge.h:1104
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3552
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:327
bool recheckLanes()
recheck whether all lanes within the edge are all right and optimises the connections once again
Definition: NBEdge.cpp:2373
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition: NBEdge.cpp:1019
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:901
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1326
void setLoadedLength(double val)
set loaded length
Definition: NBEdge.cpp:3670
void decLaneNo(int by)
decrement lane
Definition: NBEdge.cpp:3433
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1609
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:3954
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:604
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:509
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:104
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition: NBHelpers.cpp:45
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:86
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:58
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:90
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:119
void markAsSplit(const NBNode *node)
mark a node as being created form a split
Definition: NBNodeCont.h:337
Represents a single node (junction) during network building.
Definition: NBNode.h:66
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1724
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition: NBNode.cpp:478
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:271
void replaceOutgoing(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurences of the first edge within the list of outgoing by the second Connections are remap...
Definition: NBNode.cpp:1509
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:259
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:264
void setRoundabout()
update the type of this node as a roundabout
Definition: NBNode.cpp:3227
void invalidateTLS(NBTrafficLightLogicCont &tlCont, bool removedConnections, bool addedConnections)
causes the traffic light to be computed anew
Definition: NBNode.cpp:394
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:254
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:1545
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
Definition: NBNode.h:322
bool typeWasGuessed() const
return whether a priority road turns at this node
Definition: NBNode.h:797
const Position & getPosition() const
Definition: NBNode.h:246
void removeDoubleEdges()
remove duble edges
Definition: NBNode.cpp:1613
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:2303
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the given edge list in all lines
const std::map< std::string, NBPTStop * > & getStops() const
Definition: NBPTStopCont.h:64
The representation of a single pt stop.
Definition: NBPTStop.h:44
A class representing a single street sign.
Definition: NBSign.h:41
@ SIGN_TYPE_ALLWAY_STOP
Definition: NBSign.h:48
@ SIGN_TYPE_YIELD
Definition: NBSign.h:46
@ SIGN_TYPE_STOP
Definition: NBSign.h:47
@ SIGN_TYPE_PRIORITY
Definition: NBSign.h:50
@ SIGN_TYPE_RIGHT_BEFORE_LEFT
Definition: NBSign.h:51
A container for traffic light definitions and built programs.
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces occurences of the removed edge/lane in all definitions by the given edge.
A storage for available edgeTypes of edges.
Definition: NBTypeCont.h:52
bool getEdgeTypeShallBeDiscarded(const std::string &edgeType) const
Returns the information whether edges of this edgeType shall be discarded.
Definition: NBTypeCont.cpp:469
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Definition: NBTypeCont.cpp:270
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:89
Base class for objects which have an id.
Definition: Named.h:53
virtual void setID(const std::string &newID)
resets the id
Definition: Named.h:81
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A RT-tree for efficient storing of SUMO's Named objects.
Definition: NamedRTree.h:60
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:78
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:111
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
std::string getValueString(const std::string &name) const
Returns the string-value of the named option (all options)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position
Definition: Position.h:251
A list of positions.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double length() const
Returns the length.
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
std::pair< PositionVector, PositionVector > splitAt(double where, bool use2D=false) const
Returns the two lists made when this list vector is splitted at the given point.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
double getOverlapWith(const PositionVector &poly, double zThreshold) const
Returns the maximum overlaps between this and the given polygon (when not separated by at least zThre...
bool partialWithin(const AbstractPoly &poly, double offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
double getMaxGrade(double &maxJump) const
double area() const
Returns the area (0 for non-closed)
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
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,...
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static T maxValue(const std::vector< T > &v)
Definition: VectorHelper.h:86
#define M_PI
Definition: odrSpiral.cpp:40
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:188
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:212
PositionVector viaShape
shape of via
Definition: NBEdge.h:266
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:92
PositionVector shape
shape of Connection
Definition: NBEdge.h:254
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:142
std::string oppositeID
An opposite lane ID, if given.
Definition: NBEdge.h:169
PositionVector shape
The lane's shape.
Definition: NBEdge.h:147
A structure representing a connection between two lanes.
Definition: NBEdgeCont.h:624
A structure which describes changes of lane number or speed along the road.
Definition: NBEdgeCont.h:204
int offsetFactor
direction in which to apply the offset (used by netgenerate for lefthand networks)
Definition: NBEdgeCont.h:222
double speed
The speed after this change.
Definition: NBEdgeCont.h:210
double offset
lateral offset to edge geometry
Definition: NBEdgeCont.h:220
std::string nameID
the default node id
Definition: NBEdgeCont.h:218
std::string idBefore
The id for the edge before the split.
Definition: NBEdgeCont.h:214
double pos
The position of this change.
Definition: NBEdgeCont.h:208
std::vector< int > lanes
The lanes after this change.
Definition: NBEdgeCont.h:206
std::string idAfter
The id for the edge after the split.
Definition: NBEdgeCont.h:216
NBNode * node
The new node that is created for this split.
Definition: NBEdgeCont.h:212