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.dev/sumo
3 // Copyright (C) 2001-2024 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 "NBPTStop.h"
48 #include "NBHelpers.h"
49 #include "NBCont.h"
51 #include "NBDistrictCont.h"
52 #include "NBTypeCont.h"
53 
54 #define JOIN_TRAM_MAX_ANGLE 10
55 #define JOIN_TRAM_MIN_LENGTH 3
56 
57 //#define DEBUG_GUESS_ROUNDABOUT
58 //#define DEBUG_JOIN_TRAM
59 #define DEBUG_EDGE_ID ""
60 
61 // ===========================================================================
62 // method definitions
63 // ===========================================================================
65  myTypeCont(tc),
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  myRemoveEdgesAfterLoading = 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(TL("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(TL("Invalid boundary: need at least 2 coordinates"));
141  } else if (poly.size() % 2 != 0) {
142  throw ProcessError(TL("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 (const auto& i : myEdges) {
165  delete i.second;
166  }
167  myEdges.clear();
168  for (const auto& i : myExtractedEdges) {
169  delete i.second;
170  }
171  myExtractedEdges.clear();
172  for (NBEdge* const e : myEdgeCemetery) {
173  delete e;
174  }
175  myEdgeCemetery.clear();
176 }
177 
178 
179 
180 // ----- edge access methods
181 bool
182 NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
183  if (myEdges.count(edge->getID()) != 0) {
184  return false;
185  }
186  if (!ignorePrunning && ignoreFilterMatch(edge)) {
187  edge->getFromNode()->removeEdge(edge);
188  edge->getToNode()->removeEdge(edge);
189  myIgnoredEdges.insert(edge->getID());
190  delete edge;
191  } else {
193  if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
195  }
196  myEdges[edge->getID()] = edge;
197  }
198  return true;
199 }
200 
201 
202 bool
205  // check whether the edge is a named edge to keep
206  if (myEdges2Keep.size() != 0) {
207  if (myEdges2Keep.count(edge->getID()) == 0) {
208  // explicit whitelisting may be combined additively with other filters
210  && myTypes2Keep.size() == 0 && myTypes2Remove.size() == 0
211  && myPruningBoundary.size() == 0) {
212  return true;
213  }
214  } else {
215  // explicit whitelisting overrides other filters
216  return false;
217  }
218  }
219  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
220  if (edge->getSpeed() < myEdgesMinSpeed) {
221  return true;
222  }
223  // check whether the edge shall be removed because it does not allow any of the wished classes
224  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
225  return true;
226  }
227  // check whether the edge shall be removed due to allowing unwished classes only
229  return true;
230  }
231  }
232  // check whether the edge is a named edge to remove
233  if (myEdges2Remove.size() != 0) {
234  if (myEdges2Remove.count(edge->getID()) != 0) {
235  return true;
236  }
237  }
238  // check whether the edge shall be removed because it does not have one of the requested types
239  if (myTypes2Keep.size() != 0) {
240  if (myTypes2Keep.count(edge->getTypeID()) == 0) {
241  return true;
242  }
243  }
244  // check whether the edge shall be removed because it has one of the forbidden types
245  if (myTypes2Remove.size() != 0) {
246  if (myTypes2Remove.count(edge->getTypeID()) > 0) {
247  return true;
248  }
249  }
250  // check whether the edge is within the pruning boundary
251  if (myPruningBoundary.size() != 0) {
253  if (GeoConvHelper::getProcessing().usingGeoProjection()) {
255  } else if (GeoConvHelper::getLoaded().usingGeoProjection()) {
256  // XXX what if input file with different projections are loaded?
257  for (int i = 0; i < (int) myPruningBoundary.size(); i++) {
259  }
260  } else {
261  WRITE_ERROR(TL("Cannot prune edges using a geo-boundary because no projection has been loaded"));
262  }
264  }
265  if (!(edge->getGeometry().getBoxBoundary().grow(POSITION_EPS).overlapsWith(myPruningBoundary))) {
266  return true;
267  } else if (!(edge->getGeometry().partialWithin(myPruningBoundary, 2 * POSITION_EPS) || edge->getGeometry().intersects(myPruningBoundary))) {
268  // a more detailed check is necessary because the bounding box may be much bigger than the edge
269  // @note: overlapsWith implicitly closes the edge shape but this is not wanted here
270  return true;
271  }
272  }
274  return true;
275  }
276  return false;
277 }
278 
279 
280 NBEdge*
281 NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
282  EdgeCont::const_iterator i = myEdges.find(id);
283  if (i == myEdges.end()) {
284  if (retrieveExtracted) {
285  i = myExtractedEdges.find(id);
286  if (i == myExtractedEdges.end()) {
287  return nullptr;
288  }
289  } else {
290  return nullptr;
291  }
292  }
293  return (*i).second;
294 }
295 
296 // FIXME: This can't work
297 /*
298 NBEdge*
299 NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
300  NBEdge* edge = retrieve(id);
301  if (edge == 0) {
302  return 0;
303  }
304  const EdgeVector* candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
305  while (candidates->size() == 1) {
306  const std::string& nextID = candidates->front()->getID();
307  if (nextID.find(id) != 0 || nextID.size() <= id.size() + 1 || (nextID[id.size()] != '.' && nextID[id.size()] != '-')) {
308  break;
309  }
310  edge = candidates->front();
311  candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
312  }
313  return edge;
314 }*/
315 
316 NBEdge*
317 NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
318  NBEdge* edge = retrieve(id);
319  if (edge != nullptr) {
320  return edge;
321  }
322  // NOTE: (TODO) for multiply split edges (e.g. 15[0][0]) one could try recursion
323  if ((retrieve(id + "[0]") != nullptr) && (retrieve(id + "[1]") != nullptr)) {
324  // Edge was split during the netbuilding process
325  if (downstream) {
326  return retrieve(id + "[1]");
327  } else {
328  return retrieve(id + "[0]");
329  }
330  }
331  return edge;
332 }
333 
334 
335 NBEdge*
336 NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
337  // try to retrieve using the given name (iterative)
338  NBEdge* edge = retrieve(id);
339  if (edge != nullptr) {
340  return edge;
341  }
342  // now, we did not find it; we have to look over all possibilities
343  EdgeVector hints;
344  // check whether at least the hint was not splitted
345  NBEdge* hintedge = retrieve(hint);
346  if (hintedge == nullptr) {
347  hints = getGeneratedFrom(hint);
348  } else {
349  hints.push_back(hintedge);
350  }
351  EdgeVector candidates = getGeneratedFrom(id);
352  for (const NBEdge* const currHint : hints) {
353  for (NBEdge* const poss_searched : candidates) {
354  const NBNode* const node = incoming ? poss_searched->myTo : poss_searched->myFrom;
355  const EdgeVector& cont = incoming ? node->getOutgoingEdges() : node->getIncomingEdges();
356  if (find(cont.begin(), cont.end(), currHint) != cont.end()) {
357  return poss_searched;
358  }
359  }
360  }
361  return nullptr;
362 }
363 
364 
365 NBEdge*
366 NBEdgeCont::retrievePossiblySplit(const std::string& id, double pos) const {
367  // check whether the edge was not split, yet
368  NBEdge* edge = retrieve(id);
369  if (edge != nullptr) {
370  return edge;
371  }
372  int maxLength = 0;
373  std::string tid = id + "[";
374  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
375  if ((*i).first.find(tid) == 0) {
376  maxLength = MAX2(maxLength, (int)(*i).first.length());
377  }
378  }
379  // find the part of the edge which matches the position
380  double seen = 0;
381  std::vector<std::string> names;
382  names.push_back(id + "[1]");
383  names.push_back(id + "[0]");
384  while (names.size() > 0) {
385  // retrieve the first subelement (to follow)
386  std::string cid = names.back();
387  names.pop_back();
388  edge = retrieve(cid);
389  // The edge was splitted; check its subparts within the
390  // next step
391  if (edge == nullptr) {
392  if ((int)cid.length() + 3 < maxLength) {
393  names.push_back(cid + "[1]");
394  names.push_back(cid + "[0]");
395  }
396  }
397  // an edge with the name was found,
398  // check whether the position lies within it
399  else {
400  seen += edge->getLength();
401  if (seen >= pos) {
402  return edge;
403  }
404  }
405  }
406  return nullptr;
407 }
408 
409 
410 void
412  extract(dc, edge);
413  delete edge;
414 }
415 
416 
417 void
418 NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
419  if (remember) {
420  const auto& prevExtracted = myExtractedEdges.find(edge->getID());
421  if (prevExtracted != myExtractedEdges.end()) {
422  if (edge != prevExtracted->second) {
423  myEdgeCemetery.insert(prevExtracted->second);
424  prevExtracted->second = edge;
425  }
426  } else {
427  myExtractedEdges[edge->getID()] = edge;
428  }
429  }
430  myEdges.erase(edge->getID());
431  edge->myFrom->removeEdge(edge);
432  edge->myTo->removeEdge(edge);
433  dc.removeFromSinksAndSources(edge);
434 }
435 
436 
437 void
438 NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
439  if (myEdges.count(newID) != 0) {
440  throw ProcessError(TLF("Attempt to rename edge using existing id '%'", newID));
441  }
442  myEdges.erase(edge->getID());
443  edge->setID(newID);
444  myEdges[newID] = edge;
445  // update oppositeID
446  if (edge->getLanes().back().oppositeID != "") {
447  NBEdge* oppo = retrieve(SUMOXMLDefinitions::getEdgeIDFromLane(edge->getLanes().back().oppositeID));
448  if (oppo != nullptr) {
449  oppo->getLaneStruct(oppo->getNumLanes() - 1).oppositeID = edge->getLaneID(edge->getNumLanes() - 1);
450  }
451  }
452 }
453 
454 
455 // ----- explicit edge manipulation methods
456 
457 void
458 NBEdgeCont::processSplits(NBEdge* e, std::vector<Split> splits,
460  if (splits.empty()) {
461  return;
462  }
463  const std::string origID = e->getID();
464  sort(splits.begin(), splits.end(), split_sorter());
465  int maxNumLanes = e->getNumLanes();
466  // compute the node positions and sort the lanes
467  for (Split& split : splits) {
468  sort(split.lanes.begin(), split.lanes.end());
469  maxNumLanes = MAX2(maxNumLanes, (int)split.lanes.size());
470  }
471  // split the edge
472  std::vector<int> currLanes;
473  for (int l = 0; l < e->getNumLanes(); ++l) {
474  currLanes.push_back(l);
475  }
476  if (e->getNumLanes() != (int)splits.back().lanes.size()) {
477  // invalidate traffic light definitions loaded from a SUMO network
478  e->getToNode()->invalidateTLS(tlc, true, true);
479  // if the number of lanes changes the connections should be
480  // recomputed
481  e->invalidateConnections(true);
482  }
483 
484  std::string firstID = "";
485  double seen = 0;
486  for (const Split& exp : splits) {
487  assert(exp.lanes.size() != 0);
488  if (exp.pos > 0 && e->getLoadedLength() + seen > exp.pos && exp.pos > seen) {
489  nc.insert(exp.node);
490  nc.markAsSplit(exp.node);
491  // split the edge
492  const std::string idBefore = exp.idBefore == "" ? e->getID() : exp.idBefore;
493  const std::string idAfter = exp.idAfter == "" ? exp.nameID : exp.idAfter;
494  if (firstID == "") {
495  firstID = idBefore;
496  }
497  const bool ok = splitAt(dc, e, exp.pos - seen, exp.node,
498  idBefore, idAfter, e->getNumLanes(), (int) exp.lanes.size(), exp.speed);
499  if (!ok) {
500  WRITE_WARNINGF(TL("Error on parsing a split (edge '%')."), origID);
501  return;
502  }
503  seen = exp.pos;
504  std::vector<int> newLanes = exp.lanes;
505  NBEdge* pe = retrieve(idBefore);
506  NBEdge* ne = retrieve(idAfter);
507  // reconnect lanes
508  pe->invalidateConnections(true);
509  // new on right
510  int rightMostP = currLanes[0];
511  int rightMostN = newLanes[0];
512  for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
514  }
515  // new on left
516  int leftMostP = currLanes.back();
517  int leftMostN = newLanes.back();
518  for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
519  pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
520  }
521  // all other connected
522  for (int l = 0; l < maxNumLanes; ++l) {
523  if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
524  continue;
525  }
526  if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
527  continue;
528  }
529  pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
530  }
531  // if there are edges at this node which are not connected
532  // we can assume that this split was attached to an
533  // existing node. Reset all connections to let the default
534  // algorithm recompute them
535  if (exp.node->getIncomingEdges().size() > 1 || exp.node->getOutgoingEdges().size() > 1) {
536  for (NBEdge* in : exp.node->getIncomingEdges()) {
537  in->invalidateConnections(true);
538  }
539  }
540  // move to next
541  e = ne;
542  currLanes = newLanes;
543  } else if (exp.pos == 0) {
544  const int laneCountDiff = e->getNumLanes() - (int)exp.lanes.size();
545  if (laneCountDiff < 0) {
546  e->incLaneNo(-laneCountDiff);
547  } else {
548  e->decLaneNo(laneCountDiff);
549  }
550  currLanes = exp.lanes;
551  // invalidate traffic light definition loaded from a SUMO network
552  // XXX it would be preferable to reconstruct the phase definitions heuristically
553  e->getFromNode()->invalidateTLS(tlc, true, true);
554  if (exp.speed != -1.) {
555  e->setSpeed(-1, exp.speed);
556  }
557  } else {
558  WRITE_WARNINGF(TL("Split at '%' lies beyond the edge's length (edge '%')."), toString(exp.pos), origID);
559  }
560  }
561  // patch lane offsets
562  e = retrieve(firstID);
563  if (e != nullptr) {
564  if (splits.front().pos != 0) {
565  // add a dummy split at the beginning to ensure correct offset
566  Split start;
567  start.pos = 0;
568  for (int lane = 0; lane < (int)e->getNumLanes(); ++lane) {
569  start.lanes.push_back(lane);
570  }
571  start.offset = splits.front().offset;
572  start.offsetFactor = splits.front().offsetFactor;
573  splits.insert(splits.begin(), start);
574  }
575  for (const Split& split : splits) {
576  int maxLeft = split.lanes.back();
577  double offset = split.offset;
578  if (maxLeft < maxNumLanes) {
580  offset += split.offsetFactor * SUMO_const_laneWidth * (maxNumLanes - 1 - maxLeft);
581  } else {
582  offset += split.offsetFactor * SUMO_const_halfLaneWidth * (maxNumLanes - 1 - maxLeft);
583  }
584  }
585  int maxRight = split.lanes.front();
586  if (maxRight > 0 && e->getLaneSpreadFunction() == LaneSpreadFunction::CENTER) {
587  offset -= split.offsetFactor * SUMO_const_halfLaneWidth * maxRight;
588  }
589  //std::cout << " processSplits " << origID << " splitOffset=" << (*i).offset << " offset=" << offset << "\n";
590  if (offset != 0) {
591  PositionVector g = e->getGeometry();
592  g.move2side(offset);
593  e->setGeometry(g);
594  }
595  if (e->getToNode()->getOutgoingEdges().size() != 0) {
596  e = e->getToNode()->getOutgoingEdges()[0];
597  }
598  }
599  }
600 }
601 
602 
603 bool
605  return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
606  (int) edge->myLanes.size(), (int) edge->myLanes.size());
607 }
608 
609 
610 bool
612  const std::string& firstEdgeName,
613  const std::string& secondEdgeName,
614  int noLanesFirstEdge, int noLanesSecondEdge,
615  const double speed, const double friction,
616  const int changedLeft) {
617  double pos;
618  pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
619  if (pos <= 0) {
621  edge->myFrom->getPosition(), edge->myTo->getPosition(),
622  node->getPosition());
623  }
624  if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
625  return false;
626  }
627  return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
628  noLanesFirstEdge, noLanesSecondEdge, speed, friction, changedLeft);
629 }
630 
631 
632 bool
634  NBEdge* edge, double pos, NBNode* node,
635  const std::string& firstEdgeName,
636  const std::string& secondEdgeName,
637  int noLanesFirstEdge, int noLanesSecondEdge,
638  const double speed, const double friction,
639  const int changedLeft) {
640  if (firstEdgeName != edge->getID() && myEdges.count(firstEdgeName) != 0) {
641  WRITE_ERRORF(TL("Could not insert edge '%' before split of edge '%'."), firstEdgeName, edge->getID());
642  return false;
643  }
644  if (secondEdgeName == firstEdgeName || (secondEdgeName != edge->getID() && myEdges.count(secondEdgeName) != 0)) {
645  WRITE_ERRORF(TL("Could not insert edge '%' after split of edge '%'."), secondEdgeName, edge->getID());
646  return false;
647  }
648  // there must be at least some overlap between first and second edge
649  assert(changedLeft > -((int)noLanesFirstEdge));
650  assert(changedLeft < (int)noLanesSecondEdge);
651 
652  // build the new edges' geometries
653  double geomPos = pos;
654  if (edge->hasLoadedLength()) {
655  geomPos *= edge->getGeometry().length() / edge->getLoadedLength();
656  }
657  std::pair<PositionVector, PositionVector> geoms = edge->getGeometry().splitAt(geomPos);
658  // reduce inaccuracies and preserve bidi
659  if (geoms.first[-1].almostSame(node->getPosition()) || edge->isBidi()) {
660  geoms.first[-1] = node->getPosition();
661  geoms.second[0] = node->getPosition();
662  }
663  // build and insert the edges
664  NBEdge* one = new NBEdge(firstEdgeName, edge->myFrom, node, edge, geoms.first, noLanesFirstEdge);
665  NBEdge* two = new NBEdge(secondEdgeName, node, edge->myTo, edge, geoms.second, noLanesSecondEdge);
666  if (OptionsCont::getOptions().getBool("output.original-names")) {
667  const std::string origID = edge->getLaneStruct(0).getParameter(SUMO_PARAM_ORIGID, edge->getID());
668  if (firstEdgeName != origID) {
669  one->setOrigID(origID, false);
670  }
671  if (secondEdgeName != origID) {
672  two->setOrigID(origID, false);
673  }
674  }
675  two->copyConnectionsFrom(edge);
676  if (speed != -1.) {
677  two->setSpeed(-1, speed);
678  }
679  if (friction != -1.) {
680  two->setFriction(-1, friction);
681  }
682  if (edge->getDistance() != 0) {
683  one->setDistance(edge->getDistance());
684  two->setDistance(one->getDistance() + pos);
685  }
686  if (edge->hasLoadedLength()) {
687  one->setLoadedLength(pos);
688  two->setLoadedLength(edge->getLoadedLength() - pos);
689  }
690  // replace information about this edge within the nodes
691  edge->myFrom->replaceOutgoing(edge, one, 0);
692  edge->myTo->replaceIncoming(edge, two, 0);
693  // patch tls
694  for (NBTrafficLightDefinition* const tld : edge->myFrom->getControllingTLS()) {
695  tld->replaceRemoved(edge, -1, one, -1, false);
696  }
697  for (NBTrafficLightDefinition* const tld : edge->myTo->getControllingTLS()) {
698  tld->replaceRemoved(edge, -1, two, -1, true);
699  }
700  // the edge is now occuring twice in both nodes...
701  // clean up
702  edge->myFrom->removeDoubleEdges();
703  edge->myTo->removeDoubleEdges();
704  // add connections from the first to the second edge
705  // there will be as many connections as there are lanes on the second edge
706  // by default lanes will be added / discontinued on the right side
707  // (appropriate for highway on-/off-ramps)
708  const int offset = (int)one->getNumLanes() - (int)two->getNumLanes() + changedLeft;
709  for (int i2 = 0; i2 < (int)two->getNumLanes(); i2++) {
710  const int i1 = MIN2(MAX2((int)0, i2 + offset), (int)one->getNumLanes());
712  throw ProcessError(TL("Could not set connection!"));
713  }
714  }
716  if (myEdges2Keep.count(edge->getID()) != 0) {
717  myEdges2Keep.insert(one->getID());
718  myEdges2Keep.insert(two->getID());
719  }
720  if (myEdges2Remove.count(edge->getID()) != 0) {
721  myEdges2Remove.insert(one->getID());
722  myEdges2Remove.insert(two->getID());
723  }
724  }
725  // erase the splitted edge
726  patchRoundabouts(edge, one, two, myRoundabouts);
727  patchRoundabouts(edge, one, two, myGuessedRoundabouts);
728  const std::string oldID = edge->getID();
729  extract(dc, edge, true);
730  insert(one, true); // duplicate id check happened earlier
731  insert(two, true); // duplicate id check happened earlier
732  myEdgesSplit[edge] = {one, two};
733  myWasSplit.insert(one);
734  myWasSplit.insert(two);
735  return true;
736 }
737 
738 
739 void
740 NBEdgeCont::patchRoundabouts(NBEdge* orig, NBEdge* part1, NBEdge* part2, std::set<EdgeSet>& roundabouts) {
741  std::set<EdgeSet> addLater;
742  for (std::set<EdgeSet>::iterator it = roundabouts.begin(); it != roundabouts.end(); ++it) {
743  EdgeSet roundaboutSet = *it;
744  if (roundaboutSet.count(orig) > 0) {
745  roundaboutSet.erase(orig);
746  roundaboutSet.insert(part1);
747  roundaboutSet.insert(part2);
748  }
749  addLater.insert(roundaboutSet);
750  }
751  roundabouts.clear();
752  roundabouts.insert(addLater.begin(), addLater.end());
753 }
754 
755 
756 // ----- container access methods
757 std::vector<std::string>
759  std::vector<std::string> ret;
760  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
761  ret.push_back((*i).first);
762  }
763  return ret;
764 }
765 
766 
767 // ----- Adapting the input
768 int
770  EdgeVector toRemove;
771  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
772  NBEdge* edge = (*i).second;
773  if (!myEdges2Keep.count(edge->getID())) {
774  edge->getFromNode()->removeEdge(edge);
775  edge->getToNode()->removeEdge(edge);
776  toRemove.push_back(edge);
777  }
778  }
779  for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
780  erase(dc, *j);
781  }
782  return (int)toRemove.size();
783 }
784 
785 
786 void
788  // make a copy of myEdges because splitting will modify it
789  EdgeCont edges = myEdges;
790  for (auto& item : edges) {
791  NBEdge* edge = item.second;
792  if (edge->getGeometry().size() < 3) {
793  continue;
794  }
795  PositionVector geom = edge->getGeometry();
796  const std::string id = edge->getID();
797  double offset = 0;
798  for (int i = 1; i < (int)geom.size() - 1; i++) {
799  offset += geom[i - 1].distanceTo(geom[i]);
800  std::string nodeID = id + "." + toString((int)offset);
801  if (!nc.insert(nodeID, geom[i])) {
802  WRITE_WARNING("Could not split geometry of edge '" + id + "' at index " + toString(i));
803  continue;
804  }
805  NBNode* node = nc.retrieve(nodeID);
806  splitAt(dc, edge, node, edge->getID(), nodeID, edge->getNumLanes(), edge->getNumLanes());
807  edge = retrieve(nodeID);
808  }
809  }
810 }
811 
812 
813 void
814 NBEdgeCont::reduceGeometries(const double minDist) {
815  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
816  (*i).second->reduceGeometry(minDist);
817  }
818 }
819 
820 
821 void
822 NBEdgeCont::checkGeometries(const double maxAngle, bool fixAngle, const double minRadius, bool fix, bool fixRailways, bool silent) {
823  if (maxAngle > 0 || minRadius > 0) {
824  for (auto& item : myEdges) {
825  if (isSidewalk(item.second->getPermissions()) || isForbidden(item.second->getPermissions())) {
826  continue;
827  }
828  item.second->checkGeometry(maxAngle, fixAngle, minRadius, fix || (fixRailways && isRailway(item.second->getPermissions())), silent);
829  }
830  }
831 }
832 
833 
834 // ----- processing methods
835 void
837  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
838  (*i).second->clearControllingTLInformation();
839  }
840 }
841 
842 
843 void
845  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
846  (*i).second->sortOutgoingConnectionsByAngle();
847  }
848 }
849 
850 
851 void
852 NBEdgeCont::computeEdge2Edges(bool noLeftMovers) {
853  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
854  (*i).second->computeEdge2Edges(noLeftMovers);
855  }
856 }
857 
858 
859 void
861  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
862  (*i).second->computeLanes2Edges();
863  }
864 }
865 
866 
867 void
869  const bool fixOppositeLengths = OptionsCont::getOptions().getBool("opposites.guess.fix-lengths");
870  for (const auto& edgeIt : myEdges) {
871  NBEdge* const edge = edgeIt.second;
872  edge->recheckLanes();
873  // check opposites
874  if (edge->getNumLanes() > 0) {
875  const int leftmostLane = edge->getNumLanes() - 1;
876  // check oppositeID stored in other lanes
877  for (int i = 0; i < leftmostLane; i++) {
878  const std::string& oppositeID = edge->getLanes()[i].oppositeID;
879  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
880  if (oppositeID != "" && oppositeID != "-") {
881  if (edge->getLanes().back().oppositeID == "" && oppEdge != nullptr) {
882  edge->getLaneStruct(leftmostLane).oppositeID = oppositeID;
883  WRITE_WARNINGF(TL("Moving opposite lane '%' from invalid lane '%' to lane index %."), oppositeID, edge->getLaneID(i), leftmostLane);
884  } else {
885  WRITE_WARNINGF(TL("Removing opposite lane '%' for invalid lane '%'."), oppositeID, edge->getLaneID(i));
886  }
887  edge->getLaneStruct(i).oppositeID = "";
888  }
889  }
890  const std::string& oppositeID = edge->getLanes().back().oppositeID;
891  if (oppositeID != "" && oppositeID != "-") {
892  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
893  if (oppEdge == nullptr) {
894  WRITE_WARNINGF(TL("Removing unknown opposite lane '%' for edge '%'."), oppositeID, edge->getID());
895  edge->getLaneStruct(leftmostLane).oppositeID = "";
896  continue;
897  } else if (oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != oppositeID) {
898  const std::string oppEdgeLeftmost = oppEdge->getLaneID(oppEdge->getNumLanes() - 1);
899  WRITE_WARNINGF(TL("Adapting invalid opposite lane '%' for edge '%' to '%'."), oppositeID, edge->getID(), oppEdgeLeftmost);
900  edge->getLaneStruct(leftmostLane).oppositeID = oppEdgeLeftmost;
901  }
902  NBEdge::Lane& oppLane = oppEdge->getLaneStruct(oppEdge->getNumLanes() - 1);
903  if (oppLane.oppositeID == "") {
904  const std::string leftmostID = edge->getLaneID(leftmostLane);
905  WRITE_WARNINGF(TL("Adapting missing opposite lane '%' for edge '%'."), leftmostID, oppEdge->getID());
906  oppLane.oppositeID = leftmostID;
907  }
908  if (fabs(oppEdge->getLoadedLength() - edge->getLoadedLength()) > NUMERICAL_EPS) {
909  if (fixOppositeLengths) {
910  const double avgLength = 0.5 * (edge->getFinalLength() + oppEdge->getFinalLength());
911  WRITE_WARNINGF(TL("Averaging edge lengths for lane '%' (length %) and edge '%' (length %)."),
912  oppositeID, oppEdge->getLoadedLength(), edge->getID(), edge->getLoadedLength());
913  edge->setLoadedLength(avgLength);
914  oppEdge->setLoadedLength(avgLength);
915  } else {
916  WRITE_ERROR("Opposite lane '" + oppositeID + "' (length " + toString(oppEdge->getLoadedLength()) +
917  ") differs in length from edge '" + edge->getID() + "' (length " +
918  toString(edge->getLoadedLength()) + "). Set --opposites.guess.fix-lengths to fix this.");
919  edge->getLaneStruct(edge->getNumLanes() - 1).oppositeID = "";
920  continue;
921  }
922  }
923  if (oppEdge->getFromNode() != edge->getToNode() || oppEdge->getToNode() != edge->getFromNode()) {
924  WRITE_ERRORF(TL("Opposite lane '%' does not connect the same nodes as edge '%'!"), oppositeID, edge->getID());
925  edge->getLaneStruct(edge->getNumLanes() - 1).oppositeID = "";
926  }
927  }
928  }
929  // check for matching bidi lane shapes (at least for the simple case of 1-lane edges)
930  const NBEdge* bidi = edge->getBidiEdge();
931  if (bidi != nullptr && edge->getNumLanes() == 1 && bidi->getNumLanes() == 1 && edge->getID() < bidi->getID()) {
932  edge->getLaneStruct(0).shape = bidi->getLaneStruct(0).shape.reverse();
933  }
934 
935  // check for valid offset and speed
936  const double startOffset = edge->isBidiRail() ? edge->getTurnDestination(true)->getEndOffset() : 0;
937  int i = 0;
938  for (const NBEdge::Lane& l : edge->getLanes()) {
939  if (startOffset + l.endOffset > edge->getLength()) {
940  WRITE_WARNINGF(TL("Invalid endOffset % at lane '%' with length % (startOffset %)."),
941  toString(l.endOffset), edge->getLaneID(i), toString(l.shape.length()), toString(startOffset));
942  } else if (l.speed < 0.) {
943  WRITE_WARNINGF(TL("Negative allowed speed (%) on lane '%', use --speed.minimum to prevent this."), toString(l.speed), edge->getLaneID(i));
944  } else if (l.speed == 0.) {
945  WRITE_WARNINGF(TL("Lane '%' has a maximum allowed speed of 0."), edge->getLaneID(i));
946  }
947  i++;
948  }
949  }
950 }
951 
952 
953 void
954 NBEdgeCont::appendTurnarounds(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike) {
955  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
956  (*i).second->appendTurnaround(noTLSControlled, noFringe, onlyDeadends, onlyTurnlane, noGeometryLike, true);
957  }
958 }
959 
960 
961 void
962 NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
963  for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
964  myEdges[*it]->appendTurnaround(noTLSControlled, false, false, false, false, false);
965  }
966 }
967 
968 
969 void
971  std::set<std::string> stopEdgeIDs;
972  for (auto& stopItem : sc.getStops()) {
973  stopEdgeIDs.insert(stopItem.second->getEdgeId());
974  }
975  for (auto& item : myEdges) {
976  NBEdge* edge = item.second;
977  if (edge->isBidiRail()
978  && (stopEdgeIDs.count(item.first) > 0 ||
979  stopEdgeIDs.count(edge->getTurnDestination(true)->getID()) > 0)) {
980  NBEdge* to = edge->getTurnDestination(true);
981  assert(to != 0);
982  edge->setConnection(edge->getNumLanes() - 1,
983  to, to->getNumLanes() - 1, NBEdge::Lane2LaneInfoType::VALIDATED, false, false,
987  }
988  }
989 }
990 
991 void
992 NBEdgeCont::computeEdgeShapes(double smoothElevationThreshold) {
993  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
994  (*i).second->computeEdgeShape(smoothElevationThreshold);
995  }
996  // equalize length of opposite edges
997  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
998  NBEdge* edge = i->second;
999  const std::string& oppositeID = edge->getLanes().back().oppositeID;
1000  if (oppositeID != "" && oppositeID != "-") {
1001  NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
1002  if (oppEdge == nullptr || oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != oppositeID) {
1003  continue;
1004  }
1005  if (fabs(oppEdge->getLength() - edge->getLength()) > NUMERICAL_EPS) {
1006  double avgLength = (oppEdge->getLength() + edge->getLength()) / 2;
1007  edge->setAverageLengthWithOpposite(avgLength);
1008  oppEdge->setAverageLengthWithOpposite(avgLength);
1009  }
1010  }
1011  }
1012 }
1013 
1014 
1015 void
1017  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1018  (*i).second->computeLaneShapes();
1019  }
1020 }
1021 
1022 
1023 void
1026  EdgeVector edges) {
1027  // !!! Attention!
1028  // No merging of the geometry to come is being done
1029  // The connections are moved from one edge to another within
1030  // the replacement where the edge is a node's incoming edge.
1031 
1032  // count the number of lanes, the speed and the id
1033  int nolanes = 0;
1034  double speed = 0;
1035  int priority = -1;
1036  bool joinEdges = true;
1037  std::string id;
1038  sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
1039  // retrieve the connected nodes
1040  NBEdge* tpledge = *(edges.begin());
1041  NBNode* from = tpledge->getFromNode();
1042  NBNode* to = tpledge->getToNode();
1043  EdgeVector::const_iterator i;
1044  int myPriority = (*edges.begin())->getPriority();
1045  for (i = edges.begin(); i != edges.end(); i++) {
1046  // some assertions
1047  assert((*i)->getFromNode() == from);
1048  assert((*i)->getToNode() == to);
1049  // ad the number of lanes the current edge has
1050  nolanes += (*i)->getNumLanes();
1051  // build the id
1052  if (i != edges.begin()) {
1053  id += "+";
1054  }
1055  id += (*i)->getID();
1056  // compute the speed
1057  speed += (*i)->getSpeed();
1058  // build the priority
1059  // merged edges should have the same inherited priority
1060  if (myPriority == (*i)->getPriority()) {
1061  priority = myPriority;
1062  } else {
1063  priority = -1;
1064  joinEdges = false;
1065  }
1066  }
1067  if (joinEdges) {
1068  speed /= (double)edges.size();
1069  // build the new edge
1070  NBEdge* newEdge = new NBEdge(id, from, to, "", speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, priority,
1072  tpledge->myLaneSpreadFunction, tpledge->getStreetName());
1073  // copy lane attributes
1074  int laneIndex = 0;
1075  for (i = edges.begin(); i != edges.end(); ++i) {
1076  const std::vector<NBEdge::Lane>& lanes = (*i)->getLanes();
1077  for (int j = 0; j < (int)lanes.size(); ++j) {
1078  newEdge->setPermissions(lanes[j].permissions, laneIndex);
1079  newEdge->setLaneWidth(laneIndex, lanes[j].width);
1080  newEdge->setEndOffset(laneIndex, lanes[j].endOffset);
1081  laneIndex++;
1082  }
1083  }
1084  insert(newEdge, true);
1085  // replace old edge by current within the nodes
1086  // and delete the old
1087  from->replaceOutgoing(edges, newEdge);
1088  to->replaceIncoming(edges, newEdge);
1089  // patch connections
1090  // add edge2edge-information
1091  for (i = edges.begin(); i != edges.end(); i++) {
1092  EdgeVector ev = (*i)->getConnectedEdges();
1093  for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
1094  newEdge->addEdge2EdgeConnection(*j);
1095  }
1096  }
1097  // copy outgoing connections to the new edge
1098  int currLane = 0;
1099  for (i = edges.begin(); i != edges.end(); i++) {
1100  newEdge->moveOutgoingConnectionsFrom(*i, currLane);
1101  currLane += (*i)->getNumLanes();
1102  }
1103  // patch tl-information
1104  currLane = 0;
1105  for (i = edges.begin(); i != edges.end(); i++) {
1106  int noLanes = (*i)->getNumLanes();
1107  for (int j = 0; j < noLanes; j++, currLane++) {
1108  // replace in traffic lights
1109  tlc.replaceRemoved(*i, j, newEdge, currLane, true);
1110  tlc.replaceRemoved(*i, j, newEdge, currLane, false);
1111  }
1112  }
1113  // delete joined edges
1114  for (i = edges.begin(); i != edges.end(); i++) {
1115  extract(dc, *i, true);
1116  }
1117  }
1118 }
1119 
1120 
1121 void
1123  //@todo magic values
1124  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1125  NBEdge* edge = i->second;
1126  edge->guessOpposite();
1127  }
1128 }
1129 
1130 
1131 void
1133  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1134  NBEdge* opposite = getOppositeByID(i->first);
1135  if (opposite != nullptr) {
1136  i->second->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
1138  } else {
1139  i->second->setLaneSpreadFunction(LaneSpreadFunction::CENTER);
1140  }
1141  }
1142 }
1143 
1144 
1145 NBEdge*
1146 NBEdgeCont::getOppositeByID(const std::string& edgeID) const {
1147  const std::string oppositeID = edgeID[0] == '-' ? edgeID.substr(1) : "-" + edgeID;
1148  EdgeCont::const_iterator it = myEdges.find(oppositeID);
1149  return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1150 }
1151 
1152 NBEdge*
1153 NBEdgeCont::getByID(const std::string& edgeID) const {
1154  EdgeCont::const_iterator it = myEdges.find(edgeID);
1155  return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1156 }
1157 
1158 // ----- other
1159 void
1160 NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass,
1161  KeepClear keepClear, double contPos, double visibility, double speed, double friction, double length,
1162  const PositionVector& customShape, bool uncontrolled, bool warnOnly,
1163  SVCPermissions permissions, bool indirectLeft, const std::string& edgeType, SVCPermissions changeLeft, SVCPermissions changeRight) {
1164  myConnections[from].push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass, keepClear, contPos, visibility,
1165  speed, friction, length, customShape, uncontrolled, warnOnly, permissions, indirectLeft, edgeType, changeLeft, changeRight));
1166 }
1167 
1168 bool
1169 NBEdgeCont::hasPostProcessConnection(const std::string& from, const std::string& to) {
1170  if (myConnections.count(from) == 0) {
1171  return false;
1172  } else {
1173  if (to == "") {
1174  // wildcard
1175  return true;
1176  }
1177  for (const auto& ppc : myConnections[from]) {
1178  if (ppc.to == to) {
1179  return true;
1180  }
1181  }
1182  return false;
1183  }
1184 }
1185 
1186 void
1188  const bool warnOnly = OptionsCont::getOptions().exists("ignore-errors.connections") && OptionsCont::getOptions().getBool("ignore-errors.connections");
1189  for (const auto& item : myConnections) {
1190  for (std::vector<PostProcessConnection>::const_iterator i = item.second.begin(); i != item.second.end(); ++i) {
1191  NBEdge* from = retrievePossiblySplit((*i).from, true);
1192  NBEdge* to = retrievePossiblySplit((*i).to, false);
1193  if (from == nullptr || to == nullptr ||
1194  !from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::Lane2LaneInfoType::USER, true, (*i).mayDefinitelyPass,
1195  (*i).keepClear, (*i).contPos, (*i).visibility, (*i).speed, (*i).friction, (*i).customLength, (*i).customShape,
1196  (*i).uncontrolled, (*i).permissions, (*i).indirectLeft, (*i).edgeType, (*i).changeLeft, (*i).changeRight,
1197  true)) {
1198  const std::string msg = "Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.";
1199  if (warnOnly || (*i).warnOnly) {
1200  WRITE_WARNING(msg);
1201  } else {
1202  WRITE_ERROR(msg);
1203  }
1204  }
1205  }
1206  }
1207  // during loading we also kept some ambiguous connections in hope they might be valid after processing
1208  // we need to make sure that all invalid connections are removed now
1209  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
1210  NBEdge* edge = it->second;
1211  NBNode* to = edge->getToNode();
1212  // make a copy because we may delete connections
1213  std::vector<NBEdge::Connection> connections = edge->getConnections();
1214  for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1215  NBEdge::Connection& c = *it_con;
1216  if (c.toEdge != nullptr && c.toEdge->getFromNode() != to) {
1217  WRITE_WARNING("Found and removed invalid connection from edge '" + edge->getID() +
1218  "' to edge '" + c.toEdge->getID() + "' via junction '" + to->getID() + "'.");
1219  edge->removeFromConnections(c.toEdge);
1220  }
1221  }
1222  }
1223 }
1224 
1225 
1226 EdgeVector
1227 NBEdgeCont::getGeneratedFrom(const std::string& id) const {
1228  int len = (int)id.length();
1229  EdgeVector ret;
1230  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1231  std::string curr = (*i).first;
1232  // the next check makes it possibly faster - we don not have
1233  // to compare the names
1234  if ((int)curr.length() <= len) {
1235  continue;
1236  }
1237  // the name must be the same as the given id but something
1238  // beginning with a '[' must be appended to it
1239  if (curr.substr(0, len) == id && curr[len] == '[') {
1240  ret.push_back((*i).second);
1241  continue;
1242  }
1243  // ok, maybe the edge is a compound made during joining of edges
1244  std::string::size_type pos = curr.find(id);
1245  // surely not
1246  if (pos == std::string::npos) {
1247  continue;
1248  }
1249  // check leading char
1250  if (pos > 0) {
1251  if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
1252  // actually, this is another id
1253  continue;
1254  }
1255  }
1256  if (pos + id.length() < curr.length()) {
1257  if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
1258  // actually, this is another id
1259  continue;
1260  }
1261  }
1262  ret.push_back((*i).second);
1263  }
1264  return ret;
1265 }
1266 
1267 
1268 int
1270  myGuessedRoundabouts.clear();
1271  std::set<NBEdge*> loadedRoundaboutEdges;
1272  for (std::set<EdgeSet>::const_iterator it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1273  loadedRoundaboutEdges.insert(it->begin(), it->end());
1274  }
1275  // step 1: keep only those edges which have no turnarounds and which are not
1276  // part of a loaded roundabout
1277  std::set<NBEdge*> candidates;
1279  for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1280  NBEdge* e = (*i).second;
1281  NBNode* const to = e->getToNode();
1282  if (e->getTurnDestination() == nullptr
1283  && to->getConnectionTo(e->getFromNode()) == nullptr
1284  && (e->getPermissions() & valid) != 0) {
1285  candidates.insert(e);
1286  }
1287  }
1288 
1289  // step 2:
1290  std::set<NBEdge*> visited;
1291  for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
1292  EdgeVector loopEdges;
1293  // start with a random edge (this doesn't have to be a roundabout edge)
1294  // loop over connected edges (using always the leftmost one)
1295  // and keep the list in loopEdges
1296  // continue until we loop back onto a loopEdges and extract the loop
1297  NBEdge* e = (*i);
1298  if (visited.count(e) > 0) {
1299  // already seen
1300  continue;
1301  }
1302  loopEdges.push_back(e);
1303  bool doLoop = true;
1304 #ifdef DEBUG_GUESS_ROUNDABOUT
1305  gDebugFlag1 = e->getID() == DEBUG_EDGE_ID;
1306 #endif
1307  do {
1308 #ifdef DEBUG_GUESS_ROUNDABOUT
1309  if (gDebugFlag1) {
1310  std::cout << " e=" << e->getID() << " loopEdges=" << toString(loopEdges) << "\n";
1311  gDebugFlag1 = true;
1312  }
1313 #endif
1314  visited.insert(e);
1315  const EdgeVector& edges = e->getToNode()->getEdges();
1317  && !e->getToNode()->typeWasGuessed()) {
1318  doLoop = false;
1319 #ifdef DEBUG_GUESS_ROUNDABOUT
1320  if (gDebugFlag1) {
1321  std::cout << " rbl\n";
1322  }
1323  gDebugFlag1 = false;
1324 #endif
1325  break;
1326  }
1327  if (edges.size() < 2) {
1328  doLoop = false;
1329 #ifdef DEBUG_GUESS_ROUNDABOUT
1330  if (gDebugFlag1) {
1331  std::cout << " deadend\n";
1332  }
1333  gDebugFlag1 = false;
1334 #endif
1335  break;
1336  }
1337  if (e->getTurnDestination() != nullptr || e->getToNode()->getConnectionTo(e->getFromNode()) != nullptr) {
1338  // do not follow turn-arounds while in a (tentative) loop
1339  doLoop = false;
1340 #ifdef DEBUG_GUESS_ROUNDABOUT
1341  if (gDebugFlag1) {
1342  std::cout << " invalid turnAround e=" << e->getID() << " dest=" << Named::getIDSecure(e->getTurnDestination()) << "\n";
1343  }
1344  gDebugFlag1 = false;
1345 #endif
1346  break;
1347  }
1348  EdgeVector::const_iterator me = std::find(edges.begin(), edges.end(), e);
1349  NBContHelper::nextCW(edges, me);
1350  NBEdge* left = *me;
1351  while ((left->getPermissions() & valid) == 0 && left != e) {
1352  NBContHelper::nextCW(edges, me);
1353  left = *me;
1354  }
1355  if (left == e) {
1356  // no usable continuation edge found
1357  doLoop = false;
1358 #ifdef DEBUG_GUESS_ROUNDABOUT
1359  if (gDebugFlag1) {
1360  std::cout << " noContinuation\n";
1361  }
1362  gDebugFlag1 = false;
1363 #endif
1364  break;
1365  }
1366  NBContHelper::nextCW(edges, me);
1367  NBEdge* nextLeft = *me;
1368  double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
1369  double nextAngle = nextLeft == e ? 180 : fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), nextLeft->getAngleAtNode(e->getToNode())));
1370 #ifdef DEBUG_GUESS_ROUNDABOUT
1371  if (gDebugFlag1) {
1372  std::cout << " e=" << e->getID() << " left=" << left->getID() << " nextLeft=" << nextLeft->getID() << " angle=" << angle << " nextAngle=" << nextAngle << " eLength=" << e->getLength() << " lLength=" << left->getLength() << " dist=" << e->getLaneShape(0).back().distanceTo2D(left->getLaneShape(0).front()) << "\n";
1373  }
1374 #endif
1375  if (angle >= 120
1376  || (angle >= 90 &&
1377  // if the edges are long or the junction shape is small we should expect roundness (low angles)
1378  (MAX2(e->getLength(), left->getLength()) > 5
1379  || e->getLaneShape(0).back().distanceTo2D(left->getLaneShape(0).front()) < 10
1380  // there should be no straigher edge further left
1381  || (nextAngle < 45)
1382  ))) {
1383  // roundabouts do not have sharp turns (or they wouldn't be called 'round')
1384  // 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
1385  doLoop = false;
1386 #ifdef DEBUG_GUESS_ROUNDABOUT
1387  if (gDebugFlag1) {
1388  std::cout << " failed angle=" << angle << "\n";
1389  }
1390  gDebugFlag1 = false;
1391 #endif
1392  break;
1393  }
1394  EdgeVector::const_iterator loopClosed = std::find(loopEdges.begin(), loopEdges.end(), left);
1395  const int loopSize = (int)(loopEdges.end() - loopClosed);
1396  if (loopSize > 0) {
1397  // loop found
1398  if (loopSize < 3) {
1399  doLoop = false; // need at least 3 edges for a roundabout
1400  } else if (loopSize < (int)loopEdges.size()) {
1401  // remove initial edges not belonging to the loop
1402  EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
1403  }
1404  // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
1405  int attachments = 0;
1406  for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
1407  if ((*j)->getToNode()->getEdges().size() > 2) {
1408  attachments++;
1409  }
1410  }
1411  if (attachments < 3) {
1412  doLoop = false;
1413 #ifdef DEBUG_GUESS_ROUNDABOUT
1414  if (gDebugFlag1) {
1415  std::cout << " attachments=" << attachments << "\n";
1416  }
1417  gDebugFlag1 = false;
1418 #endif
1419  }
1420  break;
1421  }
1422  if (visited.count(left) > 0) {
1423  doLoop = false;
1424  } else {
1425  // keep going
1426  loopEdges.push_back(left);
1427  e = left;
1428  }
1429  } while (doLoop);
1430  if (doLoop) {
1431  // check form factor to avoid elongated shapes (circle: 1, square: ~0.79)
1432 #ifdef DEBUG_GUESS_ROUNDABOUT
1433  if (gDebugFlag1) {
1434  std::cout << " formFactor=" << formFactor(loopEdges) << "\n";
1435  }
1436 #endif
1437  double loopLength = 0;
1438  for (const NBEdge* const le : loopEdges) {
1439  loopLength += le->getLoadedLength();
1440  }
1441  if (formFactor(loopEdges) > 0.6
1442  && loopLength < OptionsCont::getOptions().getFloat("roundabouts.guess.max-length")) {
1443  // collected edges are marked in markRoundabouts
1444  EdgeSet guessed(loopEdges.begin(), loopEdges.end());
1445  if (loadedRoundaboutEdges.count(loopEdges.front()) != 0) {
1446  if (find(myRoundabouts.begin(), myRoundabouts.end(), guessed) == myRoundabouts.end()) {
1447  for (auto it = myRoundabouts.begin(); it != myRoundabouts.end(); it++) {
1448  if ((*it).count(loopEdges.front()) != 0) {
1449  WRITE_WARNINGF(TL("Replacing loaded roundabout '%' with '%'."), toString(*it), toString(guessed));
1450  myRoundabouts.erase(it);
1451  break;
1452  }
1453  }
1454  myGuessedRoundabouts.insert(guessed);
1455  }
1456  } else {
1457  myGuessedRoundabouts.insert(guessed);
1458 #ifdef DEBUG_GUESS_ROUNDABOUT
1459  if (gDebugFlag1) {
1460  std::cout << " foundRoundabout=" << toString(loopEdges) << "\n";
1461  }
1462 #endif
1463  }
1464  }
1465  }
1466 #ifdef DEBUG_GUESS_ROUNDABOUT
1467  gDebugFlag1 = false;
1468 #endif
1469  }
1470  return (int)myGuessedRoundabouts.size();
1471 }
1472 
1473 
1474 int
1476  std::set<NBEdge*> candidateEdges;
1477  for (const auto& edge : myEdges) {
1478  NBEdge* const e = edge.second;
1479  if (e->getJunctionPriority(e->getToNode()) == NBEdge::JunctionPriority::ROUNDABOUT || e->getJunctionPriority(e->getFromNode()) == NBEdge::JunctionPriority::ROUNDABOUT) {
1480  candidateEdges.insert(e);
1481  }
1482  }
1483  std::set<NBEdge*> visited;
1484  int extracted = 0;
1485  for (const auto& edgeIt : candidateEdges) {
1486  EdgeVector loopEdges;
1487  NBEdge* e = edgeIt;
1488  if (visited.count(e) > 0) {
1489  // already seen
1490  continue;
1491  }
1492  loopEdges.push_back(e);
1493  bool doLoop = true;
1494  //
1495  do {
1496  if (std::find(visited.begin(), visited.end(), e) != visited.end()) {
1497  if (loopEdges.size() > 1) {
1498  addRoundabout(EdgeSet(loopEdges.begin(), loopEdges.end()));
1499  ++extracted;
1500  }
1501  doLoop = false;
1502  break;
1503  }
1504  visited.insert(e);
1505  loopEdges.push_back(e);
1506  const EdgeVector& outgoingEdges = e->getToNode()->getOutgoingEdges();
1507  EdgeVector::const_iterator me = std::find_if(outgoingEdges.begin(), outgoingEdges.end(), [](const NBEdge * outgoingEdge) {
1508  return outgoingEdge->getJunctionPriority(outgoingEdge->getToNode()) == NBEdge::JunctionPriority::ROUNDABOUT;
1509  });
1510  if (me == outgoingEdges.end()) { // no closed loop
1511  doLoop = false;
1512  } else {
1513  e = *me;
1514  }
1515  } while (doLoop);
1516  }
1517  return extracted;
1518 }
1519 
1520 
1521 void
1523  // only loaded roundabouts are of concern here since guessing comes later
1524  std::set<EdgeSet> validRoundabouts;
1525  std::set<NBEdge*> validEdges;
1526  for (auto item : myEdges) {
1527  validEdges.insert(item.second);
1528  }
1529  for (EdgeSet roundabout : myRoundabouts) {
1530  EdgeSet validRoundabout;
1531  for (NBEdge* cand : roundabout) {
1532  if (validEdges.count(cand) != 0) {
1533  validRoundabout.insert(cand);
1534  }
1535  }
1536  if (validRoundabout.size() > 0) {
1537  validRoundabouts.insert(validRoundabout);
1538  }
1539  }
1540  myRoundabouts = validRoundabouts;
1541 }
1542 
1543 
1544 double
1546  // A circle (which maximizes area per circumference) has a formfactor of 1, non-circular shapes have a smaller value
1547  PositionVector points;
1548  for (EdgeVector::const_iterator it = loopEdges.begin(); it != loopEdges.end(); ++it) {
1549  points.append((*it)->getGeometry());
1550  }
1551  double circumference = points.length2D();
1552  return 4 * M_PI * points.area() / (circumference * circumference);
1553 }
1554 
1555 
1556 const std::set<EdgeSet>
1558  std::set<EdgeSet> result = myRoundabouts;
1559  result.insert(myGuessedRoundabouts.begin(), myGuessedRoundabouts.end());
1560  return result;
1561 }
1562 
1563 
1564 void
1566  if (roundabout.size() > 0) {
1567  if (find(myRoundabouts.begin(), myRoundabouts.end(), roundabout) != myRoundabouts.end()) {
1568  WRITE_WARNING("Ignoring duplicate roundabout: " + toString(roundabout));
1569  } else {
1570  myRoundabouts.insert(roundabout);
1571  }
1572  }
1573 }
1574 
1575 void
1577  for (auto it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1578  for (NBEdge* e : *it) {
1579  if (e->getToNode() == node) {
1580  myRoundabouts.erase(it);
1581  return;
1582  }
1583  }
1584  }
1585 }
1586 
1587 void
1591 }
1592 
1593 void
1594 NBEdgeCont::removeRoundaboutEdges(const EdgeSet& toRemove, std::set<EdgeSet>& roundabouts) {
1595  // members of a set are constant so we have to do some tricks
1596  std::vector<EdgeSet> rList;
1597  for (const EdgeSet& r : roundabouts) {
1598  EdgeSet r2;
1599  std::set_difference(r.begin(), r.end(), toRemove.begin(), toRemove.end(), std::inserter(r2, r2.end()));
1600  rList.push_back(r2);
1601  }
1602  roundabouts.clear();
1603  roundabouts.insert(rList.begin(), rList.end());
1604 }
1605 
1606 
1607 void
1609  for (const EdgeSet& roundaboutSet : getRoundabouts()) {
1610  for (NBEdge* const edge : roundaboutSet) {
1611  // disable turnarounds on incoming edges
1612  NBNode* const node = edge->getToNode();
1613  for (NBEdge* const inEdge : node->getIncomingEdges()) {
1614  if (roundaboutSet.count(inEdge) > 0) {
1615  continue;
1616  }
1617  if (inEdge->getStep() >= NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
1618  continue;
1619  }
1620  if (inEdge->getTurnDestination() != nullptr) {
1621  inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
1622  } else {
1623  // also remove connections that are effecively a turnaround but
1624  // where not correctly detector due to geometrical quirks
1625  const std::vector<NBEdge::Connection> cons = inEdge->getConnections();
1626  for (const NBEdge::Connection& con : cons) {
1627  if (con.toEdge && roundaboutSet.count(con.toEdge) == 0) {
1628  const double angle = fabs(NBHelpers::normRelAngle(inEdge->getAngleAtNode(node), con.toEdge->getAngleAtNode(node)));
1629  if (angle > 160) {
1630  inEdge->removeFromConnections(con.toEdge, -1);
1631  }
1632  }
1633  }
1634  }
1635 
1636  }
1637  // let the connections to succeeding roundabout edge have a higher priority
1638  edge->setJunctionPriority(node, NBEdge::JunctionPriority::ROUNDABOUT);
1639  edge->setJunctionPriority(edge->getFromNode(), NBEdge::JunctionPriority::ROUNDABOUT);
1640  node->setRoundabout();
1641  }
1642  }
1643 }
1644 
1645 
1646 void
1648  for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1649  NBEdge* e = i->second;
1650  const double offset = MAX2(0., e->getLength() - 3);
1651  if (e->getToNode()->isSimpleContinuation(false)) {
1652  // not a "real" junction?
1653  continue;
1654  }
1655  const SumoXMLNodeType nodeType = e->getToNode()->getType();
1656  switch (nodeType) {
1658  // yield or major?
1659  if (e->getJunctionPriority(e->getToNode()) > 0) {
1661  } else {
1662  e->addSign(NBSign(NBSign::SIGN_TYPE_YIELD, offset));
1663  }
1664  break;
1666  // yield or major?
1667  if (e->getJunctionPriority(e->getToNode()) > 0) {
1669  } else {
1670  e->addSign(NBSign(NBSign::SIGN_TYPE_STOP, offset));
1671  }
1672  break;
1675  break;
1678  break;
1681  break;
1682  default:
1683  break;
1684  }
1685  }
1686 }
1687 
1688 
1689 int
1690 NBEdgeCont::guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string& excludeOpt,
1691  NBTrafficLightLogicCont& tlc) {
1692  int lanesCreated = 0;
1693  std::vector<std::string> edges;
1694  if (excludeOpt != "") {
1695  edges = OptionsCont::getOptions().getStringVector(excludeOpt);
1696  }
1697  std::set<std::string> exclude(edges.begin(), edges.end());
1698  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1699  NBEdge* edge = it->second;
1700  if (// not excluded
1701  exclude.count(edge->getID()) == 0
1702  // does not yet have a sidewalk
1703  && !edge->hasRestrictedLane(svc)
1704  && (
1705  // guess.from-permissions
1706  (fromPermissions && (edge->getPermissions() & svc) != 0)
1707  // guess from speed
1708  || (!fromPermissions && edge->getSpeed() > minSpeed && edge->getSpeed() <= maxSpeed)
1709  )) {
1710  edge->addRestrictedLane(width, svc);
1711  lanesCreated += 1;
1712  if (svc != SVC_PEDESTRIAN) {
1713  edge->invalidateConnections(true);
1715  edge->getFromNode()->invalidateTLS(tlc, true, true);
1716  edge->getToNode()->invalidateTLS(tlc, true, true);
1717  }
1718  }
1719  }
1720  return lanesCreated;
1721 }
1722 
1723 
1724 void
1726  for (auto item : myEdges) {
1727  item.second->updateChangeRestrictions(ignoring);
1728  }
1729 }
1730 
1731 
1732 void
1733 NBEdgeCont::addPrefix(const std::string& prefix) {
1734  // make a copy of node containers
1735  const auto nodeContainerCopy = myEdges;
1736  myEdges.clear();
1737  for (const auto& node : nodeContainerCopy) {
1738  node.second->setID(prefix + node.second->getID());
1739  myEdges[node.second->getID()] = node.second;
1740  }
1741 }
1742 
1743 
1744 int
1745 NBEdgeCont::remapIDs(bool numericaIDs, bool reservedIDs, const std::string& prefix, NBPTStopCont& sc) {
1746  bool startGiven = !OptionsCont::getOptions().isDefault("numerical-ids.edge-start");
1747  if (!numericaIDs && !reservedIDs && prefix == "" && !startGiven) {
1748  return 0;
1749  }
1750  std::vector<std::string> avoid;
1751  if (startGiven) {
1752  avoid.push_back(toString(OptionsCont::getOptions().getInt("numerical-ids.edge-start") - 1));
1753  } else {
1754  avoid = getAllNames();
1755  }
1756  std::set<std::string> reserve;
1757  if (reservedIDs) {
1758  NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "edge:", reserve);
1759  avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1760  }
1761  IDSupplier idSupplier("", avoid);
1762  std::set<NBEdge*, ComparatorIdLess> toChange;
1763  for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1764  if (startGiven) {
1765  toChange.insert(it->second);
1766  continue;
1767  }
1768  if (numericaIDs) {
1769  try {
1770  StringUtils::toLong(it->first);
1771  } catch (NumberFormatException&) {
1772  toChange.insert(it->second);
1773  }
1774  }
1775  if (reservedIDs && reserve.count(it->first) > 0) {
1776  toChange.insert(it->second);
1777  }
1778  }
1779 
1780  std::map<std::string, std::vector<std::shared_ptr<NBPTStop> > > stopsOnEdge;
1781  for (const auto& item : sc.getStops()) {
1782  stopsOnEdge[item.second->getEdgeId()].push_back(item.second);
1783  }
1784 
1785  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1786  for (NBEdge* edge : toChange) {
1787  myEdges.erase(edge->getID());
1788  }
1789  for (NBEdge* edge : toChange) {
1790  const std::string origID = edge->getID();
1791  if (origNames) {
1792  edge->setOrigID(origID, false);
1793  }
1794  edge->setID(idSupplier.getNext());
1795  myEdges[edge->getID()] = edge;
1796  for (std::shared_ptr<NBPTStop> stop : stopsOnEdge[origID]) {
1797  stop->setEdgeId(prefix + edge->getID(), *this);
1798  }
1799  }
1800  if (prefix.empty()) {
1801  return (int)toChange.size();
1802  } else {
1803  int renamed = 0;
1804  // make a copy because we will modify the map
1805  auto oldEdges = myEdges;
1806  for (auto item : oldEdges) {
1807  if (!StringUtils::startsWith(item.first, prefix)) {
1808  rename(item.second, prefix + item.first);
1809  renamed++;
1810  }
1811  }
1812  return renamed;
1813  }
1814 }
1815 
1816 
1817 void
1818 NBEdgeCont::checkOverlap(double threshold, double zThreshold) const {
1819  for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1820  const NBEdge* e1 = it->second;
1821  Boundary b1 = e1->getGeometry().getBoxBoundary();
1822  b1.grow(e1->getTotalWidth());
1823  PositionVector outline1 = e1->getCCWBoundaryLine(*e1->getFromNode());
1824  outline1.append(e1->getCCWBoundaryLine(*e1->getToNode()));
1825  // check is symmetric. only check once per pair
1826  for (EdgeCont::const_iterator it2 = it; it2 != myEdges.end(); it2++) {
1827  const NBEdge* e2 = it2->second;
1828  if (e1 == e2) {
1829  continue;
1830  }
1831  Boundary b2 = e2->getGeometry().getBoxBoundary();
1832  b2.grow(e2->getTotalWidth());
1833  if (b1.overlapsWith(b2)) {
1834  PositionVector outline2 = e2->getCCWBoundaryLine(*e2->getFromNode());
1835  outline2.append(e2->getCCWBoundaryLine(*e2->getToNode()));
1836  const double overlap = outline1.getOverlapWith(outline2, zThreshold);
1837  if (overlap > threshold) {
1838  WRITE_WARNINGF(TL("Edge '%' overlaps with edge '%' by %."), e1->getID(), e2->getID(), overlap);
1839  }
1840  }
1841  }
1842  }
1843 }
1844 
1845 
1846 void
1847 NBEdgeCont::checkGrade(double threshold) const {
1848  for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1849  const NBEdge* edge = it->second;
1850  for (int i = 0; i < (int)edge->getNumLanes(); i++) {
1851  double maxJump = 0;
1852  const double grade = edge->getLaneShape(i).getMaxGrade(maxJump);
1853  if (maxJump > 0.01) {
1854  WRITE_WARNINGF(TL("Edge '%' has a vertical jump of %m."), edge->getID(), maxJump);
1855  } else if (grade > threshold) {
1856  WRITE_WARNINGF(TL("Edge '%' has a grade of %%."), edge->getID(), grade * 100, "%");
1857  break;
1858  }
1859  }
1860  const std::vector<NBEdge::Connection>& connections = edge->getConnections();
1861  for (std::vector<NBEdge::Connection>::const_iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1862  const NBEdge::Connection& c = *it_con;
1863  double maxJump = 0;
1864  const double grade = MAX2(c.shape.getMaxGrade(maxJump), c.viaShape.getMaxGrade(maxJump));
1865  if (maxJump > 0.01) {
1866  WRITE_WARNINGF(TL("Connection '%' has a vertical jump of %m."), c.getDescription(edge), maxJump);
1867  } else if (grade > threshold) {
1868  WRITE_WARNINGF(TL("Connection '%' has a grade of %%."), c.getDescription(edge), grade * 100, "%");
1869  break;
1870  }
1871  }
1872  }
1873 }
1874 
1875 
1876 int
1878  int affectedEdges = 0;
1879  for (auto item : myEdges) {
1880  if (item.second->joinLanes(perms)) {
1881  affectedEdges++;
1882  }
1883  }
1884  return affectedEdges;
1885 }
1886 
1887 
1888 bool
1889 NBEdgeCont::MinLaneComparatorIdLess::operator()(const std::pair<NBEdge*, int>& a, const std::pair<NBEdge*, int>& b) const {
1890  if (a.first->getID() == b.first->getID()) {
1891  return a.second < b.second;
1892  }
1893  return a.first->getID() < b.first->getID();
1894 }
1895 
1896 int
1898  // this is different from joinSimilarEdges because there don't need to be
1899  // shared nodes and tram edges may be split
1900  std::vector<NBEdge*> tramEdges;
1901  std::vector<NBEdge*> targetEdges;
1902  for (auto item : myEdges) {
1903  SVCPermissions permissions = item.second->getPermissions();
1904  if (isTram(permissions)) {
1905  if (item.second->getNumLanes() == 1) {
1906  tramEdges.push_back(item.second);
1907  } else {
1908  WRITE_WARNINGF(TL("Not joining tram edge '%' with % lanes."), item.second->getID(), item.second->getNumLanes());
1909  }
1910  } else if ((permissions & (SVC_PASSENGER | SVC_BUS)) != 0) {
1911  targetEdges.push_back(item.second);
1912  }
1913  }
1914  if (tramEdges.empty() || targetEdges.empty()) {
1915  return 0;
1916  }
1917  int numJoined = 0;
1918  NamedRTree tramTree;
1919  for (NBEdge* const edge : tramEdges) {
1920  const Boundary& bound = edge->getGeometry().getBoxBoundary();
1921  float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1922  float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1923  tramTree.Insert(min, max, edge);
1924  }
1925  // {targetEdge, laneIndex : tramEdge}
1926  std::map<std::pair<NBEdge*, int>, NBEdge*, MinLaneComparatorIdLess> matches;
1927 
1928  for (NBEdge* const edge : targetEdges) {
1929  Boundary bound = edge->getGeometry().getBoxBoundary();
1930  bound.grow(maxDist + edge->getTotalWidth());
1931  float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1932  float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1933  std::set<const Named*> near;
1934  Named::StoringVisitor visitor(near);
1935  tramTree.Search(min, max, visitor);
1936  // the nearby set is actually just re-sorting according to the id to make the tests comparable
1937  std::set<NBEdge*, ComparatorIdLess> nearby;
1938  for (const Named* namedEdge : near) {
1939  nearby.insert(const_cast<NBEdge*>(static_cast<const NBEdge*>(namedEdge)));
1940  }
1941  for (NBEdge* const tramEdge : nearby) {
1942  // find a continous stretch of tramEdge that runs along one of the
1943  // lanes of the road edge
1944  const PositionVector& tramShape = tramEdge->getGeometry();
1945  double minEdgeDist = maxDist + 1;
1946  int minLane = -1;
1947  // find the lane where the maximum distance from the tram geometry
1948  // is minimal and within maxDist
1949  for (int i = 0; i < edge->getNumLanes(); i++) {
1950  double maxLaneDist = -1;
1951  if ((edge->getPermissions(i) & (SVC_PASSENGER | SVC_BUS)) != 0) {
1952  const PositionVector& laneShape = edge->getLaneShape(i);
1953  for (Position pos : laneShape) {
1954  const double dist = tramShape.distance2D(pos, false);
1955 #ifdef DEBUG_JOIN_TRAM
1956  //if (edge->getID() == "106838214#1") {
1957  // std::cout << " edge=" << edge->getID() << " tramEdge=" << tramEdge->getID() << " lane=" << i << " pos=" << pos << " dist=" << dist << "\n";
1958  //}
1959 #endif
1960  if (dist == GeomHelper::INVALID_OFFSET || dist > maxDist) {
1961  maxLaneDist = -1;
1962  break;
1963  }
1964  maxLaneDist = MAX2(maxLaneDist, dist);
1965  }
1966  if (maxLaneDist >= 0 && maxLaneDist < minEdgeDist) {
1967  minEdgeDist = maxLaneDist;
1968  minLane = i;
1969  }
1970  }
1971  }
1972  if (minLane >= 0) {
1973  // edge could run in the wrong direction and still fit the threshold we check the angle as well
1974  const PositionVector& laneShape = edge->getLaneShape(minLane);
1975  const double offset1 = tramShape.nearest_offset_to_point2D(laneShape.front(), false);
1976  const double offset2 = tramShape.nearest_offset_to_point2D(laneShape.back(), false);
1977  Position p1 = tramShape.positionAtOffset2D(offset1);
1978  Position p2 = tramShape.positionAtOffset2D(offset2);
1979  double tramAngle = GeomHelper::legacyDegree(p1.angleTo2D(p2), true);
1980  bool angleOK = GeomHelper::getMinAngleDiff(tramAngle, edge->getTotalAngle()) < JOIN_TRAM_MAX_ANGLE;
1981  if (angleOK && offset2 > offset1) {
1982  std::pair<NBEdge*, int> key = std::make_pair(edge, minLane);
1983  if (matches.count(key) == 0) {
1984  matches[key] = tramEdge;
1985  } else {
1986  WRITE_WARNINGF(TL("Ambiguous tram edges '%' and '%' for lane '%'."), matches[key]->getID(), tramEdge->getID(), edge->getLaneID(minLane));
1987  }
1988 #ifdef DEBUG_JOIN_TRAM
1989  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";
1990 #endif
1991  }
1992  }
1993  }
1994  }
1995  if (matches.size() == 0) {
1996  return 0;
1997  }
1998  const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1999  // find continous runs of matched edges for each tramEdge
2000  for (NBEdge* tramEdge : tramEdges) {
2001  std::vector<std::pair<double, std::pair<NBEdge*, int> > > roads;
2002  for (auto item : matches) {
2003  if (item.second == tramEdge) {
2004  NBEdge* road = item.first.first;
2005  int laneIndex = item.first.second;
2006  const PositionVector& laneShape = road->getLaneShape(laneIndex);
2007  double tramPos = tramEdge->getGeometry().nearest_offset_to_point2D(laneShape.front(), false);
2008  roads.push_back(std::make_pair(tramPos, item.first));
2009  }
2010  }
2011  if (roads.size() != 0) {
2012 
2013  sort(roads.begin(), roads.end());
2014 #ifdef DEBUG_JOIN_TRAM
2015  std::cout << " tramEdge=" << tramEdge->getID() << " roads=";
2016  for (auto item : roads) {
2017  std::cout << item.second.first->getLaneID(item.second.second) << ",";
2018  }
2019  std::cout << " offsets=";
2020  for (auto item : roads) {
2021  std::cout << item.first << ",";
2022  }
2023  std::cout << "\n";
2024 #endif
2025  // merge tramEdge into road lanes
2026  EdgeVector replacement;
2027  double pos = 0;
2028  int tramPart = 0;
2029  std::string tramEdgeID = tramEdge->getID();
2030  NBNode* tramFrom = tramEdge->getFromNode();
2031  PositionVector tramShape = tramEdge->getGeometry();
2032  const double tramLength = tramShape.length();
2033  EdgeVector incoming = tramFrom->getIncomingEdges();
2034  bool erasedLast = false;
2035  for (const auto& item : roads) {
2036  const double gap = item.first - pos;
2037  NBEdge* road = item.second.first;
2038  int laneIndex = item.second.second;
2039  if (gap >= JOIN_TRAM_MIN_LENGTH) {
2040 #ifdef DEBUG_JOIN_TRAM
2041  std::cout << " splitting tramEdge=" << tramEdge->getID() << " at " << item.first << " (gap=" << gap << ")\n";
2042 #endif
2043  const std::string firstPartID = tramEdgeID + "#" + toString(tramPart++);
2044  splitAt(dc, tramEdge, gap, road->getFromNode(), firstPartID, tramEdgeID, 1, 1);
2045  tramEdge = retrieve(tramEdgeID); // second part;
2046  NBEdge* firstPart = retrieve(firstPartID);
2047  firstPart->invalidateConnections(true);
2048  incoming.clear();
2049  incoming.push_back(firstPart);
2050  replacement.push_back(firstPart);
2051  }
2052  pos = item.first + road->getGeometry().length();
2053  numJoined++;
2054  replacement.push_back(road);
2055  // merge section of tramEdge into road lane
2056  if (road->getToNode() != tramEdge->getToNode() && (tramLength - pos) >= JOIN_TRAM_MIN_LENGTH) {
2057  tramEdge->reinitNodes(road->getToNode(), tramEdge->getToNode());
2058  tramEdge->setGeometry(tramShape.getSubpart(pos, tramShape.length()));
2059  erasedLast = false;
2060 #ifdef DEBUG_JOIN_TRAM
2061  std::cout << " shorted tramEdge=" << tramEdge->getID() << " (joined with roadEdge=" << road->getID() << "\n";
2062 #endif
2063  } else {
2064 #ifdef DEBUG_JOIN_TRAM
2065  std::cout << " erased tramEdge=" << tramEdge->getID() << "\n";
2066 #endif
2067  extract(dc, tramEdge, true);
2068  erasedLast = true;
2069  }
2070  road->setPermissions(road->getPermissions(laneIndex) | SVC_TRAM, laneIndex);
2071  if (origNames) {
2072  road->setOrigID(tramEdgeID, true, laneIndex);
2073  }
2074  for (NBEdge* in : incoming) {
2075  if (isTram(in->getPermissions()) && !in->isConnectedTo(road)) {
2076  if (in->getFromNode() != road->getFromNode()) {
2077  in->reinitNodes(in->getFromNode(), road->getFromNode());
2078  } else {
2079  extract(dc, in, true);
2080 #ifdef DEBUG_JOIN_TRAM
2081  std::cout << " erased incoming tramEdge=" << in->getID() << "\n";
2082 #endif
2083  }
2084  }
2085  }
2086  incoming.clear();
2087  }
2088  NBEdge* lastRoad = roads.back().second.first;
2089  if (erasedLast) {
2090  // copy to avoid concurrent modification
2091  auto outEdges = tramEdge->getToNode()->getOutgoingEdges();
2092  for (NBEdge* out : outEdges) {
2093  if (isTram(out->getPermissions()) && !lastRoad->isConnectedTo(out)) {
2094  if (lastRoad->getToNode() != out->getToNode()) {
2095  out->reinitNodes(lastRoad->getToNode(), out->getToNode());
2096  } else {
2097  extract(dc, out, true);
2098 #ifdef DEBUG_JOIN_TRAM
2099  std::cout << " erased outgoing tramEdge=" << out->getID() << "\n";
2100 #endif
2101 
2102  }
2103  }
2104  }
2105  } else {
2106  replacement.push_back(tramEdge);
2107  }
2108  // update ptstops and ptlines
2109  sc.replaceEdge(tramEdgeID, replacement);
2110  lc.replaceEdge(tramEdgeID, replacement);
2111  }
2112  }
2113 
2114  return numJoined;
2115 }
2116 
2117 
2118 EdgeVector
2120  EdgeVector result;
2121  for (auto item : myEdges) {
2122  item.second->setNumericalID((int)result.size());
2123  result.push_back(item.second);
2124  }
2125  return result;
2126 }
2127 
2130  EdgeVector all = getAllEdges();
2131  return RouterEdgeVector(all.begin(), all.end());
2132 }
2133 
2134 bool
2136  bool ok = true;
2137  for (const auto& item : myEdges) {
2138  NBEdge* e = item.second;
2139  if (nc.retrieve(e->getFromNode()->getID()) == nullptr) {
2140  WRITE_ERRORF(TL("Edge's '%' from-node '%' is not known."), e->getID(), e->getFromNode()->getID());
2141  ok = false;
2142  }
2143  if (nc.retrieve(e->getToNode()->getID()) == nullptr) {
2144  WRITE_ERRORF(TL("Edge's '%' to-node '%' is not known."), e->getID(), e->getToNode()->getID());
2145  ok = false;
2146  }
2147 
2148  }
2149  return ok;
2150 }
2151 
2152 
2153 void
2155  for (auto item : myEdges) {
2156  NBEdge* e = item.second;
2157  if (e->hasLoadedLength() && myWasSplit.count(e) != 0) {
2158  // subtract half the length of the longest incoming / outgoing connection
2159  double maxLengthOut = 0;
2160  for (const NBEdge::Connection& c : e->getConnections()) {
2161  maxLengthOut = MAX2(maxLengthOut, c.length + c.viaLength);
2162  }
2163  double maxLengthIn = 0;
2164  for (const NBEdge* in : e->getIncomingEdges()) {
2165  for (const NBEdge::Connection& c : in->getConnectionsFromLane(-1, e, -1)) {
2166  maxLengthIn = MAX2(maxLengthIn, c.length + c.viaLength);
2167  }
2168  }
2169  e->setLoadedLength(MAX2(POSITION_EPS, e->getLoadedLength() - (maxLengthIn + maxLengthOut) / 2));
2170  }
2171  }
2172 }
2173 
2174 void
2176  for (auto item : myEdges) {
2177  item.second->computeAngle();
2178  }
2179 }
2180 
2181 
2182 std::set<std::string>
2184  std::set<std::string> result;
2185  for (auto item : myEdges) {
2186  if (item.second->getTypeID() != "") {
2187  result.insert(item.second->getTypeID());
2188  }
2189  }
2190  return result;
2191 }
2192 
2193 
2194 int
2196  EdgeSet toRemove;
2197  for (auto item : myEdges) {
2198  NBEdge* edge = item.second;
2199  // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
2200  if (edge->getSpeed() < myEdgesMinSpeed) {
2201  toRemove.insert(edge);
2202  }
2203  }
2204  int numRemoved = 0;
2205  for (NBEdge* edge : toRemove) {
2206  // explicit whitelist overrides removal
2207  if (myEdges2Keep.size() == 0 || myEdges2Keep.count(edge->getID()) == 0) {
2208  extract(dc, edge);
2209  numRemoved++;
2210  }
2211  }
2212  return numRemoved;
2213 }
2214 
2215 
2216 int
2218  EdgeSet toRemove;
2219  for (auto item : myEdges) {
2220  NBEdge* edge = item.second;
2221  // check whether the edge shall be removed because it does not allow any of the wished classes
2222  if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
2223  toRemove.insert(edge);
2224  }
2225  // check whether the edge shall be removed due to allowing unwished classes only
2227  toRemove.insert(edge);
2228  }
2229  }
2230  int numRemoved = 0;
2231  for (NBEdge* edge : toRemove) {
2232  // explicit whitelist overrides removal
2233  if (myEdges2Keep.size() == 0 || myEdges2Keep.count(edge->getID()) == 0) {
2234  extract(dc, edge);
2235  numRemoved++;
2236  }
2237  }
2238  return numRemoved;
2239 }
2240 
2241 
2242 int
2243 NBEdgeCont::removeLanesByWidth(NBDistrictCont& dc, const double minWidth) {
2244  EdgeSet toRemove;
2245  for (auto item : myEdges) {
2246  NBEdge* const edge = item.second;
2247  std::vector<int> indices;
2248  int idx = 0;
2249  for (const auto& lane : edge->getLanes()) {
2250  if (lane.width != NBEdge::UNSPECIFIED_WIDTH && lane.width < minWidth) {
2251  indices.push_back(idx);
2252  }
2253  idx++;
2254  }
2255  if ((int)indices.size() == edge->getNumLanes()) {
2256  toRemove.insert(edge);
2257  } else {
2258  for (const int i : indices) {
2259  edge->deleteLane(i, false, true);
2260  }
2261  }
2262  }
2263  int numRemoved = 0;
2264  for (NBEdge* edge : toRemove) {
2265  // explicit whitelist overrides removal
2266  if (myEdges2Keep.size() == 0 || myEdges2Keep.count(edge->getID()) == 0) {
2267  extract(dc, edge);
2268  numRemoved++;
2269  }
2270  }
2271  return numRemoved;
2272 }
2273 
2274 
2275 /****************************************************************************/
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
std::set< NBEdge * > EdgeSet
container for unique edges
Definition: NBCont.h:50
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
KeepClear
keepClear status of connections
Definition: NBCont.h:58
@ KEEPCLEAR_UNSPECIFIED
Definition: NBCont.h:61
std::vector< NBRouterEdge * > RouterEdgeVector
Definition: NBCont.h:43
#define JOIN_TRAM_MIN_LENGTH
Definition: NBEdgeCont.cpp:55
#define JOIN_TRAM_MAX_ANGLE
Definition: NBEdgeCont.cpp:54
#define DEBUG_EDGE_ID
Definition: NBEdgeCont.cpp:59
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge.
bool isTram(SVCPermissions permissions)
Returns whether an edge with the given permissions is a tram edge.
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permissions 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 permissions is a sidewalk.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
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_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
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:37
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN2(T a, T b)
Definition: StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
T MAX2(T a, T b)
Definition: StdDefs.h:82
const double SUMO_const_halfLaneWidth
Definition: StdDefs.h:49
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:130
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:118
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:319
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns whether the boundary overlaps with the given polygon.
Definition: Boundary.cpp:189
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:136
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:124
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:214
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:172
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:797
void patchRoundabouts(NBEdge *orig, NBEdge *part1, NBEdge *part2, std::set< EdgeSet > &roundabouts)
fix roundabout information after splitting an edge
Definition: NBEdgeCont.cpp:740
void computeEdgeShapes(double smoothElevationThreshold=-1)
Computes the shapes of all edges stored in the container.
Definition: NBEdgeCont.cpp:992
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:852
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:785
~NBEdgeCont()
Destructor.
Definition: NBEdgeCont.cpp:72
void sortOutgoingLanesConnections()
Sorts all lanes of all edges within the container by their direction.
Definition: NBEdgeCont.cpp:844
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:789
void appendRailwayTurnarounds(const NBPTStopCont &sc)
Appends turnarounds to all bidiRail edges with stops.
Definition: NBEdgeCont.cpp:970
std::set< std::string > myEdges2Remove
Set of ids of edges which shall explicitly be removed.
Definition: NBEdgeCont.h:767
std::set< std::string > myIgnoredEdges
The ids of ignored edges.
Definition: NBEdgeCont.h:747
void updateAllChangeRestrictions(SVCPermissions ignoring)
modify all restrictions on lane changing for edges and connections
double myEdgesMinSpeed
The minimum speed an edge may have in order to be kept (default: -1)
Definition: NBEdgeCont.h:758
void recheckPostProcessConnections()
Try to set any stored connections.
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:418
void processSplits(NBEdge *e, std::vector< Split > splits, NBNodeCont &nc, NBDistrictCont &dc, NBTrafficLightLogicCont &tlc)
process splits
Definition: NBEdgeCont.cpp:458
EdgeVector getAllEdges() const
return all edges
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:411
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:281
std::set< std::string > myTypes2Keep
Set of edges types which shall be kept.
Definition: NBEdgeCont.h:776
void recheckLanes()
Rechecks whether all lanes have a successor for each of the stored edges.
Definition: NBEdgeCont.cpp:868
NBEdge * getOppositeByID(const std::string &edgeID) const
Returns the edge with negated id if it exists.
void checkGeometries(const double maxAngle, bool fixAngle, const double minRadius, bool fix, bool fixRailways, bool silent=false)
Definition: NBEdgeCont.cpp:822
EdgeCont myExtractedEdges
The extracted edges which are kept for reference.
Definition: NBEdgeCont.h:741
void reduceGeometries(const double minDist)
Definition: NBEdgeCont.cpp:814
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:203
void removeRoundabout(const NBNode *node)
remove roundabout that contains the given node
void cleanupRoundabouts()
void splitGeometry(NBDistrictCont &dc, NBNodeCont &nc)
Splits edges into multiple if they have a complex geometry.
Definition: NBEdgeCont.cpp:787
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 friction, double length, const PositionVector &customShape, bool uncontrolled, bool warnOnly, SVCPermissions permissions=SVC_UNSPECIFIED, bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED)
Adds a connection which could not be set during loading.
std::set< std::string > getUsedTypes() const
return all edge types in used
void computeLanes2Edges()
Computes for each edge which lanes approach the next edges.
Definition: NBEdgeCont.cpp:860
int extractRoundabouts()
Determines which edges have been marked as roundabouts and stores them internally.
NBEdge * retrievePossiblySplit(const std::string &id, bool downstream) const
Tries to retrieve an edge, even if it is splitted.
Definition: NBEdgeCont.cpp:317
RouterEdgeVector getAllRouterEdges() const
return all router edges
std::set< const NBEdge * > myWasSplit
the edges that were created as result of splitting
Definition: NBEdgeCont.h:752
void rename(NBEdge *edge, const std::string &newID)
Renames the edge. Throws exception if newID already exists.
Definition: NBEdgeCont.cpp:438
int joinTramEdges(NBDistrictCont &dc, NBPTStopCont &sc, NBPTLineCont &lc, double maxDist)
join tram edges into adjacent lanes
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
add post process connections
EdgeCont myEdges
The instance of the dictionary (id->edge)
Definition: NBEdgeCont.h:738
int removeUnwishedEdges(NBDistrictCont &dc)
Removes unwished edges (not in keep-edges)
Definition: NBEdgeCont.cpp:769
std::set< std::string > myEdges2Keep
Set of ids of edges which shall explicitly be kept.
Definition: NBEdgeCont.h:764
NBTypeCont & myTypeCont
The network builder; used to obtain type information.
Definition: NBEdgeCont.h:628
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:836
std::set< EdgeSet > myGuessedRoundabouts
Edges marked as belonging to a roundabout after guessing.
Definition: NBEdgeCont.h:792
void computeAngles()
compute all edge angles
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:779
void applyOptions(OptionsCont &oc)
Initialises the storage by applying given options.
Definition: NBEdgeCont.cpp:78
void removeRoundaboutEdges(const EdgeSet &toRemove)
remove edges from all stored roundabouts
PositionVector myPruningBoundary
Boundary within which an edge must be located in order to be kept.
Definition: NBEdgeCont.h:782
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:773
int guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string &excludeOpt, NBTrafficLightLogicCont &tlc)
add sidwalks to edges within the given limits or permissions and return the number of edges affected
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:954
SVCPermissions myVehicleClasses2Keep
Set of vehicle types which must be allowed on edges in order to keep them.
Definition: NBEdgeCont.h:770
void computeLaneShapes()
Computes the shapes of all lanes of all edges stored in the container.
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
std::map< std::string, NBEdge * > EdgeCont
The type of the dictionary where an edge may be found by its id.
Definition: NBEdgeCont.h:735
void addPrefix(const std::string &prefix)
add prefix to all edges
void fixSplitCustomLength()
adapt custom lengths of split edges to account for intersection size
std::map< const NBEdge *, std::pair< NBEdge *, NBEdge * > > myEdgesSplit
the number of splits of edges during the building
Definition: NBEdgeCont.h:750
std::map< std::string, std::vector< PostProcessConnection > > myConnections
The list of connections to recheck.
Definition: NBEdgeCont.h:732
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:182
NBEdgeCont(NBTypeCont &tc)
Constructor.
Definition: NBEdgeCont.cpp:64
std::set< NBEdge * > myEdgeCemetery
The edges which got extracted twice but may still be referenced somewhere TODO smart_ptr?
Definition: NBEdgeCont.h:744
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
int removeLanesByWidth(NBDistrictCont &dc, const double minWidth)
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
Definition: NBEdgeCont.cpp:604
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
Definition: NBEdgeCont.cpp:758
int removeEdgesBySpeed(NBDistrictCont &dc)
return number of edges removed
void checkGrade(double threshold) const
check whether edges are to steep
int removeEdgesByPermissions(NBDistrictCont &dc)
bool myRemoveEdgesAfterLoading
Whether edges shall be joined and patched first, then removed.
Definition: NBEdgeCont.h:761
The representation of a single edge during network building.
Definition: NBEdge.h:92
NBEdge * guessOpposite(bool reguess=false)
set oppositeID and return opposite edge if found
Definition: NBEdge.cpp:4878
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:589
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4368
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:4331
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:598
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4283
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:3805
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Definition: NBEdge.h:351
void incLaneNo(int by)
increment lane
Definition: NBEdge.cpp:4064
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:665
void setAverageLengthWithOpposite(double val)
patch average lane length in regard to the opposite edge
Definition: NBEdge.cpp:4388
bool isBidi()
return whether this edge should be a bidi edge
Definition: NBEdge.h:1419
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition: NBEdge.cpp:992
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:743
void dismissVehicleClassInformation()
dimiss vehicle class information
Definition: NBEdge.cpp:4394
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1787
bool hasLoadedLength() const
Returns whether a length was set explicitly.
Definition: NBEdge.h:608
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false, SVCPermissions permission=SVC_UNSPECIFIED)
Adds a connection to another edge.
Definition: NBEdge.cpp:1091
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 friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, const bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition: NBEdge.cpp:1126
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
Definition: NBEdge.h:1409
const std::string & getID() const
Definition: NBEdge.h:1524
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:726
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:542
@ 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:615
NBNode * myTo
Definition: NBEdge.h:1736
double getDistance() const
get distance
Definition: NBEdge.h:675
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4154
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:986
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1804
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:516
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:779
void setFriction(int lane, double friction)
set lane specific friction (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4299
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition: NBEdge.h:354
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:4596
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:1441
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1522
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:4206
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
Definition: NBEdge.h:357
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:1324
void addSign(NBSign sign)
add Sign
Definition: NBEdge.h:1456
void deleteLane(int index, bool recompute, bool shiftIndices)
delete lane
Definition: NBEdge.cpp:4075
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition: NBEdge.cpp:3681
std::string getLaneID(int lane) const
get lane ID
Definition: NBEdge.cpp:4006
@ USER
The connection was given by the user.
@ VALIDATED
The connection was computed and validated.
@ COMPUTED
The connection was computed.
const NBEdge * getBidiEdge() const
Definition: NBEdge.h:1510
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 friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1179
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:2122
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3997
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:2148
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:342
bool hasRestrictedLane(SUMOVehicleClass vclass) const
returns whether any lane already allows the given vclass exclusively
Definition: NBEdge.cpp:4585
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:1037
void copyConnectionsFrom(NBEdge *src)
copy connections from antoher edge
Definition: NBEdge.cpp:1637
const std::string & getTypeID() const
get ID of type
Definition: NBEdge.h:1177
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:685
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4237
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:345
bool recheckLanes()
recheck whether all lanes within the edge are all right and optimises the connections once again
Definition: NBEdge.cpp:2901
void setOrigID(const std::string origID, const bool append, const int laneIdx=-1)
set origID for all lanes or for a specific lane
Definition: NBEdge.cpp:4726
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:980
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1424
void setLoadedLength(double val)
set loaded length
Definition: NBEdge.cpp:4383
void decLaneNo(int by)
decrement lane
Definition: NBEdge.cpp:4095
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1736
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:4704
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:631
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:535
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1386
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 double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:58
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=nullptr)
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:57
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:87
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:116
void markAsSplit(const NBNode *node)
mark a node as being created form a split
Definition: NBNodeCont.h:363
Represents a single node (junction) during network building.
Definition: NBNode.h:66
void invalidateOutgoingConnections(bool reallowSetting=false)
invalidate outgoing connections
Definition: NBNode.cpp:1998
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1929
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition: NBNode.cpp:510
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:285
void replaceOutgoing(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of outgoing by the second Connections are rema...
Definition: NBNode.cpp:1714
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:273
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:278
void setRoundabout()
update the type of this node as a roundabout
Definition: NBNode.cpp:3820
void invalidateTLS(NBTrafficLightLogicCont &tlCont, bool removedConnections, bool addedConnections)
causes the traffic light to be computed anew
Definition: NBNode.cpp:426
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:268
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of incoming by the second Connections are rema...
Definition: NBNode.cpp:1750
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:336
bool typeWasGuessed() const
return whether a priority road turns at this node
Definition: NBNode.h:840
const Position & getPosition() const
Definition: NBNode.h:260
void removeDoubleEdges()
remove duble edges
Definition: NBNode.cpp:1818
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:2632
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the given edge list in all lines
Container for public transport stops during the net building process.
Definition: NBPTStopCont.h:44
void replaceEdge(const std::string &edgeID, const std::vector< NBEdge * > &replacement)
replace the edge with the closes edge on the given edge list in all stops
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
Definition: NBPTStopCont.h:62
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
@ SIGN_TYPE_LEFT_BEFORE_RIGHT
Definition: NBSign.h:52
The base class for traffic light logic definitions.
A container for traffic light definitions and built programs.
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces occurrences 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:526
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Definition: NBTypeCont.cpp:303
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:90
Base class for objects which have an id.
Definition: Named.h:54
virtual void setID(const std::string &newID)
resets the id
Definition: Named.h:82
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A RT-tree for efficient storing of SUMO's Named objects.
Definition: NamedRTree.h:61
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:79
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:112
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:60
virtual 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:37
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition: Position.h:286
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::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 amount
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.
PositionVector reverse() const
reverse position vector
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 std::string getEdgeIDFromLane(const std::string laneID)
return edge id when given the lane ID
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.
#define M_PI
Definition: odrSpiral.cpp:45
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:201
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:213
PositionVector viaShape
shape of via
Definition: NBEdge.h:282
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:98
PositionVector shape
shape of Connection
Definition: NBEdge.h:270
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:143
std::string oppositeID
An opposite lane ID, if given.
Definition: NBEdge.h:179
PositionVector shape
The lane's shape.
Definition: NBEdge.h:148
bool operator()(const std::pair< NBEdge *, int > &a, const std::pair< NBEdge *, int > &b) const
A structure representing a connection between two lanes.
Definition: NBEdgeCont.h:633
A structure which describes changes of lane number or speed along the road.
Definition: NBEdgeCont.h:189
int offsetFactor
direction in which to apply the offset (used by netgenerate for lefthand networks)
Definition: NBEdgeCont.h:209
double offset
lateral offset to edge geometry
Definition: NBEdgeCont.h:207
double pos
The position of this change.
Definition: NBEdgeCont.h:193
std::vector< int > lanes
The lanes after this change.
Definition: NBEdgeCont.h:191