SUMO - Simulation of Urban MObility
NBEdge.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
20 // Methods for the representation of a single edge
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #include <config.h>
28 
29 #include <vector>
30 #include <string>
31 #include <algorithm>
32 #include "NBEdgeCont.h"
33 #include "NBNode.h"
34 #include "NBNodeCont.h"
35 #include "NBContHelper.h"
36 #include "NBHelpers.h"
38 #include <cmath>
39 #include <iomanip>
40 #include "NBTypeCont.h"
41 #include <utils/geom/GeomHelper.h>
45 #include <utils/common/ToString.h>
47 #include <utils/common/StdDefs.h>
48 #include "NBEdge.h"
51 
52 //#define DEBUG_CONNECTION_GUESSING
53 //#define DEBUG_ANGLES
54 //#define DEBUG_NODE_BORDER
55 //#define DEBUGCOND (getID() == "disabled")
56 //#define DEBUGCOND (getID() == "22762377#1" || getID() == "146511467")
57 //#define DEBUGCOND2(obj) ((obj != 0 && (obj)->getID() == "disabled"))
58 
59 // ===========================================================================
60 // static members
61 // ===========================================================================
62 const double NBEdge::UNSPECIFIED_WIDTH = -1;
63 const double NBEdge::UNSPECIFIED_OFFSET = 0;
64 const double NBEdge::UNSPECIFIED_SPEED = -1;
65 const double NBEdge::UNSPECIFIED_CONTPOS = -1;
67 
68 const double NBEdge::UNSPECIFIED_SIGNAL_OFFSET = -1;
69 const double NBEdge::UNSPECIFIED_LOADED_LENGTH = -1;
70 const double NBEdge::ANGLE_LOOKAHEAD = 10.0;
73 
75 
76 // ===========================================================================
77 // method definitions
78 // ===========================================================================
79 std::string
81  return id + "_" + toString(internalLaneIndex);
82 }
83 
84 
85 std::string
87  return Named::getIDSecure(parent) + "_" + toString(fromLane) + "->" + Named::getIDSecure(toEdge) + "_" + toString(toLane);
88 }
89 
90 
91 NBEdge::Connection::Connection(int fromLane_, NBEdge* toEdge_, int toLane_) :
92  fromLane(fromLane_),
93  toEdge(toEdge_),
94  toLane(toLane_),
95  tlLinkIndex(-1),
96  mayDefinitelyPass(false),
97  keepClear(true),
101  id(toEdge_ == nullptr ? "" : toEdge->getFromNode()->getID()),
102  haveVia(false),
104  uncontrolled(false) {
105 }
106 
107 
108 NBEdge::Connection::Connection(int fromLane_, NBEdge* toEdge_, int toLane_, bool mayDefinitelyPass_, bool keepClear_, double contPos_,
109  double visibility_, double speed_, bool haveVia_, bool uncontrolled_, const PositionVector& customShape_) :
110  fromLane(fromLane_),
111  toEdge(toEdge_),
112  toLane(toLane_),
113  tlLinkIndex(-1),
114  mayDefinitelyPass(mayDefinitelyPass_),
115  keepClear(keepClear_),
116  contPos(contPos_),
117  visibility(visibility_),
118  speed(speed_),
119  customShape(customShape_),
120  id(toEdge_ == nullptr ? "" : toEdge->getFromNode()->getID()),
122  haveVia(haveVia_),
124  uncontrolled(uncontrolled_) {
125 }
126 
127 
128 NBEdge::Lane::Lane(NBEdge* e, const std::string& origID_) :
129  speed(e->getSpeed()),
130  permissions(SVCAll),
131  preferred(0),
132  endOffset(e->getEndOffset()),
133  stopOffsets(e->getStopOffsets()),
134  width(e->getLaneWidth()),
135  accelRamp(false),
136  connectionsDone(false) {
137  if (origID_ != "") {
139  }
140 }
141 
142 
143 /* -------------------------------------------------------------------------
144  * NBEdge::ToEdgeConnectionsAdder-methods
145  * ----------------------------------------------------------------------- */
146 void
147 NBEdge::ToEdgeConnectionsAdder::execute(const int lane, const int virtEdge) {
148  // check
149  assert((int)myTransitions.size() > virtEdge);
150  // get the approached edge
151  NBEdge* succEdge = myTransitions[virtEdge];
152  std::vector<int> lanes;
153 
154  // check whether the currently regarded, approached edge has already
155  // a connection starting at the edge which is currently being build
156  std::map<NBEdge*, std::vector<int> >::iterator i = myConnections.find(succEdge);
157  if (i != myConnections.end()) {
158  // if there were already lanes assigned, get them
159  lanes = (*i).second;
160  }
161 
162  // check whether the current lane was already used to connect the currently
163  // regarded approached edge
164  std::vector<int>::iterator j = find(lanes.begin(), lanes.end(), lane);
165  if (j == lanes.end()) {
166  // if not, add it to the list
167  lanes.push_back(lane);
168  }
169  // set information about connecting lanes
170  myConnections[succEdge] = lanes;
171 }
172 
173 
174 
175 /* -------------------------------------------------------------------------
176  * NBEdge::MainDirections-methods
177  * ----------------------------------------------------------------------- */
179  NBEdge* parent, NBNode* to, int indexOfStraightest) {
180  if (outgoing.size() == 0) {
181  return;
182  }
183  // check whether the right turn has a higher priority
184  assert(outgoing.size() > 0);
185  const LinkDirection straightestDir = to->getDirection(parent, outgoing[indexOfStraightest]);
186 #ifdef DEBUG_CONNECTION_GUESSING
187  if (DEBUGCOND2(parent)) {
188  std::cout << " MainDirections edge=" << parent->getID() << " straightest=" << outgoing[indexOfStraightest]->getID() << " dir=" << toString(straightestDir) << "\n";
189  }
190 #endif
191  if (NBNode::isTrafficLight(to->getType()) &&
192  (straightestDir == LINKDIR_STRAIGHT || straightestDir == LINKDIR_PARTLEFT || straightestDir == LINKDIR_PARTRIGHT)) {
193  myDirs.push_back(MainDirections::DIR_FORWARD);
194  return;
195  }
196  if (outgoing[0]->getJunctionPriority(to) == 1) {
197  myDirs.push_back(MainDirections::DIR_RIGHTMOST);
198  }
199  // check whether the left turn has a higher priority
200  if (outgoing.back()->getJunctionPriority(to) == 1) {
201  // ok, the left turn belongs to the higher priorised edges on the junction
202  // let's check, whether it has also a higher priority (lane number/speed)
203  // than the current
204  EdgeVector tmp(outgoing);
205  sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
206  if (outgoing.back()->getPriority() > tmp[0]->getPriority()) {
207  myDirs.push_back(MainDirections::DIR_LEFTMOST);
208  } else {
209  if (outgoing.back()->getNumLanes() > tmp[0]->getNumLanes()) {
210  myDirs.push_back(MainDirections::DIR_LEFTMOST);
211  }
212  }
213  }
214  // check whether the forward direction has a higher priority
215  // try to get the forward direction
216  EdgeVector tmp(outgoing);
217  sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
218  NBEdge* edge = *(tmp.begin());
219  // check whether it has a higher priority and is going straight
220  if (edge->getJunctionPriority(to) == 1 && to->getDirection(parent, edge) == LINKDIR_STRAIGHT) {
221  myDirs.push_back(MainDirections::DIR_FORWARD);
222  }
223 }
224 
225 
227 
228 
229 bool
231  return myDirs.empty();
232 }
233 
234 
235 bool
237  return find(myDirs.begin(), myDirs.end(), d) != myDirs.end();
238 }
239 
240 
241 /* -------------------------------------------------------------------------
242  * NBEdge::connections_relative_edgelane_sorter-methods
243  * ----------------------------------------------------------------------- */
244 int
246  if (c1.toEdge != c2.toEdge) {
248  }
249  return c1.toLane < c2.toLane;
250 }
251 
252 
253 /* -------------------------------------------------------------------------
254  * NBEdge-methods
255  * ----------------------------------------------------------------------- */
256 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
257  std::string type, double speed, int nolanes,
258  int priority, double laneWidth, double endOffset,
259  const std::string& streetName,
260  LaneSpreadFunction spread) :
261  Named(StringUtils::convertUmlaute(id)),
262  myStep(INIT),
263  myType(StringUtils::convertUmlaute(type)),
264  myFrom(from), myTo(to),
266  myPriority(priority), mySpeed(speed),
267  myTurnDestination(nullptr),
268  myPossibleTurnDestination(nullptr),
270  myLaneSpreadFunction(spread), myEndOffset(endOffset),
271  myStopOffsets(),
272  myLaneWidth(laneWidth),
275  myStreetName(streetName),
277  myIndex(-1) {
278  init(nolanes, false, "");
279 }
280 
281 
282 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
283  std::string type, double speed, int nolanes,
284  int priority, double laneWidth, double endOffset,
285  PositionVector geom,
286  const std::string& streetName,
287  const std::string& origID,
288  LaneSpreadFunction spread, bool tryIgnoreNodePositions) :
289  Named(StringUtils::convertUmlaute(id)),
290  myStep(INIT),
291  myType(StringUtils::convertUmlaute(type)),
292  myFrom(from), myTo(to),
294  myPriority(priority), mySpeed(speed),
295  myTurnDestination(nullptr),
296  myPossibleTurnDestination(nullptr),
298  myGeom(geom), myLaneSpreadFunction(spread), myEndOffset(endOffset),
299  myStopOffsets(),
300  myLaneWidth(laneWidth),
303  myStreetName(streetName),
305  myIndex(-1) {
306  init(nolanes, tryIgnoreNodePositions, origID);
307 }
308 
309 
310 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to, const NBEdge* tpl, const PositionVector& geom, int numLanes) :
311  Named(StringUtils::convertUmlaute(id)),
312  myStep(INIT),
313  myType(tpl->getTypeID()),
314  myFrom(from), myTo(to),
316  myPriority(tpl->getPriority()), mySpeed(tpl->getSpeed()),
317  myTurnDestination(nullptr),
318  myPossibleTurnDestination(nullptr),
320  myGeom(geom),
322  myEndOffset(tpl->getEndOffset()),
324  myLaneWidth(tpl->getLaneWidth()),
326  myAmInnerEdge(false),
328  myStreetName(tpl->getStreetName()),
330  init(numLanes > 0 ? numLanes : tpl->getNumLanes(), myGeom.size() > 0, "");
331  for (int i = 0; i < getNumLanes(); i++) {
332  const int tplIndex = MIN2(i, tpl->getNumLanes() - 1);
333  setSpeed(i, tpl->getLaneSpeed(tplIndex));
334  setPermissions(tpl->getPermissions(tplIndex), i);
335  setLaneWidth(i, tpl->myLanes[tplIndex].width);
336  myLanes[i].updateParameter(tpl->myLanes[tplIndex].getParametersMap());
337  if (to == tpl->myTo) {
338  setEndOffset(i, tpl->myLanes[tplIndex].endOffset);
339  setStopOffsets(i, tpl->myLanes[tplIndex].stopOffsets);
340  }
341  }
342 }
343 
344 
346  Named("DUMMY")
347 {
348 }
349 
350 void
351 NBEdge::reinit(NBNode* from, NBNode* to, const std::string& type,
352  double speed, int nolanes, int priority,
353  PositionVector geom, double laneWidth, double endOffset,
354  const std::string& streetName,
355  LaneSpreadFunction spread,
356  bool tryIgnoreNodePositions) {
357  if (myFrom != from) {
358  myFrom->removeEdge(this, false);
359  }
360  if (myTo != to) {
361  myTo->removeEdge(this, false);
362  }
364  myFrom = from;
365  myTo = to;
366  myPriority = priority;
367  //?myTurnDestination(0),
368  //?myFromJunctionPriority(-1), myToJunctionPriority(-1),
369  myGeom = geom;
370  myLaneSpreadFunction = spread;
372  myStreetName = streetName;
373  //?, myAmTurningWithAngle(0), myAmTurningOf(0),
374  //?myAmInnerEdge(false), myAmMacroscopicConnector(false)
375 
376  // preserve lane-specific settings (geometry must be recomputed)
377  // if new lanes are added they copy the values from the leftmost lane (if specified)
378  const std::vector<Lane> oldLanes = myLanes;
379  init(nolanes, tryIgnoreNodePositions, oldLanes.empty() ? "" : oldLanes[0].getParameter(SUMO_PARAM_ORIGID));
380  for (int i = 0; i < (int)nolanes; ++i) {
381  PositionVector newShape = myLanes[i].shape;
382  myLanes[i] = oldLanes[MIN2(i, (int)oldLanes.size() - 1)];
383  myLanes[i].shape = newShape;
384  }
385  // however, if the new edge defaults are explicityly given, they override the old settings
386  if (endOffset != UNSPECIFIED_OFFSET) {
387  setEndOffset(-1, endOffset);
388  }
389  if (laneWidth != UNSPECIFIED_WIDTH) {
390  setLaneWidth(-1, laneWidth);
391  }
392  if (speed != UNSPECIFIED_SPEED) {
393  setSpeed(-1, speed);
394  }
395 }
396 
397 
398 void
400  // connections may still be valid
401  if (from == nullptr || to == nullptr) {
402  throw ProcessError("At least one of edge's '" + myID + "' nodes is not known.");
403  }
404  if (myFrom != from) {
405  myFrom->removeEdge(this, false);
406  }
407  if (myTo != to) {
408  myTo->removeEdge(this, false);
409  }
410  // remove first from both nodes and then add to the new nodes
411  // (otherwise reversing does not work)
412  if (myFrom != from) {
413  myFrom = from;
414  myFrom->addOutgoingEdge(this);
415  }
416  if (myTo != to) {
417  myTo = to;
418  myTo->addIncomingEdge(this);
419  }
420  computeAngle();
421 }
422 
423 
424 void
425 NBEdge::init(int noLanes, bool tryIgnoreNodePositions, const std::string& origID) {
426  if (noLanes == 0) {
427  throw ProcessError("Edge '" + myID + "' needs at least one lane.");
428  }
429  if (myFrom == nullptr || myTo == nullptr) {
430  throw ProcessError("At least one of edge's '" + myID + "' nodes is not known.");
431  }
433  throw ProcessError("Invalid edge id '" + myID + "'.");
434  }
435  // revisit geometry
436  // should have at least two points at the end...
437  // and in dome cases, the node positions must be added
439  if (!tryIgnoreNodePositions || myGeom.size() < 2) {
440  if (myGeom.size() == 0) {
441  myGeom.push_back(myFrom->getPosition());
442  myGeom.push_back(myTo->getPosition());
443  } else {
446  }
447  }
448  if (myGeom.size() < 2) {
449  myGeom.clear();
450  myGeom.push_back(myFrom->getPosition());
451  myGeom.push_back(myTo->getPosition());
452  }
453  if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
454  WRITE_WARNING("Edge's '" + myID + "' from- and to-node are at the same position.");
456  }
457  //
458  myFrom->addOutgoingEdge(this);
459  myTo->addIncomingEdge(this);
460  // prepare container
462  assert(myGeom.size() >= 2);
463  if ((int)myLanes.size() > noLanes) {
464  // remove connections starting at the removed lanes
465  for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
466  removeFromConnections(nullptr, lane, -1);
467  }
468  // remove connections targeting the removed lanes
469  const EdgeVector& incoming = myFrom->getIncomingEdges();
470  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
471  for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
472  (*i)->removeFromConnections(this, -1, lane);
473  }
474  }
475  }
476  myLanes.clear();
477  for (int i = 0; i < noLanes; i++) {
478  myLanes.push_back(Lane(this, origID));
479  }
481  computeAngle();
482 
483 #ifdef DEBUG_CONNECTION_GUESSING
484  if (DEBUGCOND) {
485  std::cout << "init edge=" << getID() << "\n";
486  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
487  std::cout << " conn " << getID() << "_" << (*i).fromLane << " to " << Named::getIDSecure((*i).toEdge) << "_" << (*i).toLane << "\n";
488  (*i).shape.mirrorX();
489  (*i).viaShape.mirrorX();
490  }
491  }
492 #endif
493 }
494 
495 
497 
498 
499 // ----------- Applying offset
500 void
501 NBEdge::reshiftPosition(double xoff, double yoff) {
502  myGeom.add(xoff, yoff, 0);
503  for (int i = 0; i < (int)myLanes.size(); i++) {
504  myLanes[i].shape.add(xoff, yoff, 0);
505  }
506  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
507  (*i).customShape.add(xoff, yoff, 0);
508  }
509  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
510 }
511 
512 
513 void
515  myGeom.mirrorX();
516  for (int i = 0; i < (int)myLanes.size(); i++) {
517  myLanes[i].shape.mirrorX();
518  }
519  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
520  (*i).shape.mirrorX();
521  (*i).viaShape.mirrorX();
522  }
523  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
524 }
525 
526 
527 // ----------- Edge geometry access and computation
528 const PositionVector
530  return myGeom.getSubpartByIndex(1, (int)myGeom.size() - 2);
531 }
532 
533 
534 bool
536  return myGeom.size() == 2 && hasDefaultGeometryEndpoints();
537 }
538 
539 
540 bool
542  return myGeom.front() == myFrom->getPosition() &&
543  myGeom.back() == myTo->getPosition();
544 }
545 
546 
547 bool
549  // do not extend past the node position
550  if (node == myFrom) {
551  return myGeom.front() == node->getPosition();
552  } else {
553  assert(node == myTo);
554  return myGeom.back() == node->getPosition();
555  }
556 }
557 
558 void
559 NBEdge::setGeometry(const PositionVector& s, bool inner) {
560  Position begin = myGeom.front(); // may differ from node position
561  Position end = myGeom.back(); // may differ from node position
562  myGeom = s;
563  if (inner) {
564  myGeom.insert(myGeom.begin(), begin);
565  myGeom.push_back(end);
566  }
568  computeAngle();
569 }
570 
571 
572 void
573 NBEdge::extendGeometryAtNode(const NBNode* node, double maxExtent) {
574  //std::cout << "extendGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " extent=" << maxExtent << " geom=" << myGeom;
575  if (node == myFrom) {
576  myGeom.extrapolate(maxExtent, true);
577  double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
578  //std::cout << " geom2=" << myGeom << " offset=" << offset;
579  if (offset != GeomHelper::INVALID_OFFSET) {
581  }
582  } else {
583  assert(node == myTo);
584  myGeom.extrapolate(maxExtent, false, true);
585  double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
586  //std::cout << " geom2=" << myGeom << " offset=" << offset;
587  if (offset != GeomHelper::INVALID_OFFSET) {
588  myGeom = myGeom.getSubpart2D(0, MAX2(offset, 2 * POSITION_EPS));
589  }
590  }
591  //std::cout << " geom3=" << myGeom << "\n";
592 }
593 
594 
595 void
596 NBEdge::shortenGeometryAtNode(const NBNode* node, double reduction) {
597  //std::cout << "shortenGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " reduction=" << reduction << " geom=" << myGeom;
598  reduction = MIN2(reduction, myGeom.length2D() - 2 * POSITION_EPS);
599  if (node == myFrom) {
600  myGeom = myGeom.getSubpart2D(reduction, myGeom.length2D());
601  } else {
602  myGeom = myGeom.getSubpart2D(0, myGeom.length2D() - reduction);
603  }
605  //std::cout << " geom2=" << myGeom << "\n";
606 }
607 
608 
609 void
610 NBEdge::setNodeBorder(const NBNode* node, const Position& p, const Position& p2, bool rectangularCut) {
611  PositionVector border;
612  if (rectangularCut) {
613  const double extend = 100;
614  border = myGeom.getOrthogonal(p, extend, node == myTo);
615  } else {
616  border.push_back(p);
617  border.push_back(p2);
618  }
619  if (border.size() == 2) {
620  double edgeWidth = 0;
621  for (int i = 0; i < (int)myLanes.size(); i++) {
622  edgeWidth += getLaneWidth(i);
623  }
624  border.extrapolate2D(getTotalWidth());
625  if (node == myFrom) {
626  myFromBorder = border;
627  } else {
628  assert(node == myTo);
629  myToBorder = border;
630  }
631  }
632 #ifdef DEBUG_NODE_BORDER
634  if (DEBUGCOND) std::cout << "setNodeBorder edge=" << getID() << " node=" << node->getID()
635  << " rect=" << rectangularCut
636  << " p=" << p << " p2=" << p2
637  << " border=" << border
638  << " myGeom=" << myGeom
639  << "\n";
640 
641 #endif
642 }
643 
644 
645 const PositionVector&
647  if (node == myFrom) {
648  return myFromBorder;
649  } else {
650  assert(node == myTo);
651  return myToBorder;
652  }
653 }
654 
655 
656 void
658  if (node == myFrom) {
659  myFromBorder.clear();
660  } else {
661  assert(node == myTo);
662  myToBorder.clear();
663  }
664 }
665 
666 
667 bool
668 NBEdge::isBidiRail(bool ignoreSpread) const {
669  return (isRailway(getPermissions())
670  && (ignoreSpread || myLaneSpreadFunction == LANESPREAD_CENTER)
671  && myPossibleTurnDestination != nullptr
675 }
676 
677 
678 bool
680  if (!isRailway(getPermissions())) {
681  return false;
682  }
683  for (NBEdge* out : myTo->getOutgoingEdges()) {
684  if (isRailway(out->getPermissions()) &&
685  out != getTurnDestination(true)) {
686  return true;
687  }
688  }
689  return true;
690 }
691 
692 
695  PositionVector shape = old;
696  shape = startShapeAt(shape, myFrom, myFromBorder);
697  if (shape.size() < 2) {
698  // only keep the last snippet
699  const double oldLength = old.length();
700  shape = old.getSubpart(oldLength - 2 * POSITION_EPS, oldLength);
701  }
702  shape = startShapeAt(shape.reverse(), myTo, myToBorder).reverse();
703  // sanity checks
704  if (shape.length() < POSITION_EPS) {
705  if (old.length() < 2 * POSITION_EPS) {
706  shape = old;
707  } else {
708  const double midpoint = old.length() / 2;
709  // EPS*2 because otherwhise shape has only a single point
710  shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
711  assert(shape.size() >= 2);
712  assert(shape.length() > 0);
713  }
714  } else {
715  // @note If the node shapes are overlapping we may get a shape which goes in the wrong direction
716  // in this case the result shape should shortened
717  if (DEG2RAD(135) < fabs(GeomHelper::angleDiff(shape.beginEndAngle(), old.beginEndAngle()))) {
718  // eliminate intermediate points
719  PositionVector tmp;
720  tmp.push_back(shape[0]);
721  tmp.push_back(shape[-1]);
722  // 3D geometry may be messed up since positions were extrapolated rather than interpolated due to cutting in the wrong direction
723  // make the edge level with one of the intersections (try to pick one that needs to be flat as well)
724  if (myTo->geometryLike()) {
725  tmp[0].setz(myFrom->getPosition().z());
726  tmp[1].setz(myFrom->getPosition().z());
727  } else {
728  tmp[0].setz(myTo->getPosition().z());
729  tmp[1].setz(myTo->getPosition().z());
730  }
731  shape = tmp;
732  if (tmp.length() < POSITION_EPS) {
733  // fall back to original shape
734  if (old.length() < 2 * POSITION_EPS) {
735  shape = old;
736  } else {
737  const double midpoint = old.length() / 2;
738  // EPS*2 because otherwhise shape has only a single point
739  shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
740  assert(shape.size() >= 2);
741  assert(shape.length() > 0);
742  }
743  } else {
744  const double midpoint = shape.length() / 2;
745  // cut to size and reverse
746  shape = shape.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
747  if (shape.length() < POSITION_EPS) {
748  assert(false);
749  // the shape has a sharp turn near the midpoint
750  }
751  shape = shape.reverse();
752  }
753  }
754  }
755  return shape;
756 }
757 
758 
759 void
760 NBEdge::computeEdgeShape(double smoothElevationThreshold) {
761  if (smoothElevationThreshold > 0 && myGeom.hasElevation()) {
763  // cutting and patching z-coordinate may cause steep grades which should be smoothed
764  if (!myFrom->geometryLike()) {
765  cut[0].setz(myFrom->getPosition().z());
766  const double d = cut[0].distanceTo2D(cut[1]);
767  const double dZ = fabs(cut[0].z() - cut[1].z());
768  if (dZ / smoothElevationThreshold > d) {
769  cut = cut.smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold));
770  }
771  }
772  if (!myTo->geometryLike()) {
773  cut[-1].setz(myTo->getPosition().z());
774  const double d = cut[-1].distanceTo2D(cut[-2]);
775  const double dZ = fabs(cut[-1].z() - cut[-2].z());
776  if (dZ / smoothElevationThreshold > d) {
777  cut = cut.reverse().smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold)).reverse();
778  }
779  }
780  cut[0] = myGeom[0];
781  cut[-1] = myGeom[-1];
782  if (cut != myGeom) {
783  myGeom = cut;
785  }
786  }
787  for (int i = 0; i < (int)myLanes.size(); i++) {
788  myLanes[i].shape = cutAtIntersection(myLanes[i].shape);
789  }
790  // recompute edge's length as the average of lane lenghts
791  double avgLength = 0;
792  for (int i = 0; i < (int)myLanes.size(); i++) {
793  avgLength += myLanes[i].shape.length();
794  }
795  myLength = avgLength / (double) myLanes.size();
796  computeAngle(); // update angles using the finalized node and lane shapes
797 }
798 
799 
801 NBEdge::startShapeAt(const PositionVector& laneShape, const NBNode* startNode, PositionVector nodeShape) {
802  if (nodeShape.size() == 0) {
803  nodeShape = startNode->getShape();
804  nodeShape.closePolygon();
805  }
806  PositionVector lb = laneShape;
807  lb.extrapolate2D(100.0);
808  if (nodeShape.intersects(laneShape)) {
809  // shape intersects directly
810  std::vector<double> pbv = laneShape.intersectsAtLengths2D(nodeShape);
811  assert(pbv.size() > 0);
812  // ensure that the subpart has at least two points
813  double pb = MIN2(laneShape.length2D() - POSITION_EPS - NUMERICAL_EPS, VectorHelper<double>::maxValue(pbv));
814  if (pb < 0) {
815  return laneShape;
816  }
817  PositionVector ns = laneShape.getSubpart2D(pb, laneShape.length2D());
818  //PositionVector ns = pb < (laneShape.length() - POSITION_EPS) ? laneShape.getSubpart2D(pb, laneShape.length()) : laneShape;
819  if (!startNode->geometryLike() || pb < 1) {
820  // make "real" intersections and small intersections flat
821  ns[0].setz(startNode->getPosition().z());
822  }
823  assert(ns.size() >= 2);
824  return ns;
825  } else if (nodeShape.intersects(lb)) {
826  // extension of first segment intersects
827  std::vector<double> pbv = lb.intersectsAtLengths2D(nodeShape);
828  assert(pbv.size() > 0);
829  double pb = VectorHelper<double>::maxValue(pbv);
830  assert(pb >= 0);
831  PositionVector result = laneShape.getSubpartByIndex(1, (int)laneShape.size() - 1);
832  Position np = lb.positionAtOffset2D(pb);
833  if (!startNode->geometryLike()) {
834  // make "real" intersections flat
835  np.setz(startNode->getPosition().z());
836  }
837  result.push_front_noDoublePos(np);
838  return result;
839  //if (result.size() >= 2) {
840  // return result;
841  //} else {
842  // WRITE_WARNING(error + " (resulting shape is too short)");
843  // return laneShape;
844  //}
845  } else {
846  // could not find proper intersection. Probably the edge is very short
847  // and lies within nodeShape
848  // @todo enable warning WRITE_WARNING(error + " (laneShape lies within nodeShape)");
849  return laneShape;
850  }
851 }
852 
853 
854 const PositionVector&
855 NBEdge::getLaneShape(int i) const {
856  return myLanes[i].shape;
857 }
858 
859 
860 void
862  myLaneSpreadFunction = spread;
863 }
864 
865 
866 void
867 NBEdge::addGeometryPoint(int index, const Position& p) {
868  if (index >= 0) {
869  myGeom.insert_noDoublePos(myGeom.begin() + index, p);
870  } else {
871  myGeom.insert_noDoublePos(myGeom.end() + index, p);
872  }
873 }
874 
875 
876 bool
878  // check whether there any splits to perform
879  if (myGeom.size() < 3) {
880  return false;
881  }
882  // ok, split
883  NBNode* newFrom = myFrom;
884  NBNode* myLastNode = myTo;
885  NBNode* newTo = nullptr;
886  NBEdge* currentEdge = this;
887  for (int i = 1; i < (int) myGeom.size() - 1; i++) {
888  // build the node first
889  if (i != (int)myGeom.size() - 2) {
890  std::string nodename = myID + "_in_between#" + toString(i);
891  if (!nc.insert(nodename, myGeom[i])) {
892  throw ProcessError("Error on adding in-between node '" + nodename + "'.");
893  }
894  newTo = nc.retrieve(nodename);
895  } else {
896  newTo = myLastNode;
897  }
898  if (i == 1) {
899  currentEdge->myTo->removeEdge(this);
900  currentEdge->myTo = newTo;
901  newTo->addIncomingEdge(currentEdge);
902  } else {
903  std::string edgename = myID + "[" + toString(i - 1) + "]";
904  // @bug lane-specific width, speed, overall offset and restrictions are ignored
905  currentEdge = new NBEdge(edgename, newFrom, newTo, myType, mySpeed, (int) myLanes.size(),
907  if (!ec.insert(currentEdge, true)) {
908  throw ProcessError("Error on adding splitted edge '" + edgename + "'.");
909  }
910  }
911  newFrom = newTo;
912  }
913  myGeom.clear();
914  myGeom.push_back(myFrom->getPosition());
915  myGeom.push_back(myTo->getPosition());
916  myStep = INIT;
917  return true;
918 }
919 
920 
921 void
922 NBEdge::reduceGeometry(const double minDist) {
923  myGeom.removeDoublePoints(minDist, true);
924 }
925 
926 
927 void
928 NBEdge::checkGeometry(const double maxAngle, const double minRadius, bool fix) {
929  if (myGeom.size() < 3) {
930  return;
931  }
932  //std::cout << "checking geometry of " << getID() << " geometry = " << toString(myGeom) << "\n";
933  std::vector<double> angles; // absolute segment angles
934  //std::cout << " absolute angles:";
935  for (int i = 0; i < (int)myGeom.size() - 1; ++i) {
936  angles.push_back(myGeom.angleAt2D(i));
937  //std::cout << " " << angles.back();
938  }
939  //std::cout << "\n relative angles: ";
940  for (int i = 0; i < (int)angles.size() - 1; ++i) {
941  const double relAngle = fabs(GeomHelper::angleDiff(angles[i], angles[i + 1]));
942  //std::cout << relAngle << " ";
943  if (maxAngle > 0 && relAngle > maxAngle) {
944  WRITE_WARNING("Found angle of " + toString(RAD2DEG(relAngle)) + " degrees at edge '" + getID() + "', segment " + toString(i));
945  }
946  if (relAngle < DEG2RAD(1)) {
947  continue;
948  }
949  if (i == 0 || i == (int)angles.size() - 2) {
950  const bool start = i == 0;
951  const double dist = (start ? myGeom[0].distanceTo2D(myGeom[1]) : myGeom[-2].distanceTo2D(myGeom[-1]));
952  const double r = tan(0.5 * (M_PI - relAngle)) * dist;
953  //std::cout << (start ? " start" : " end") << " length=" << dist << " radius=" << r << " ";
954  if (minRadius > 0 && r < minRadius) {
955  if (fix) {
956  WRITE_MESSAGE("Removing sharp turn with radius " + toString(r) + " at the " +
957  (start ? "start" : "end") + " of edge '" + getID() + "'.");
958  myGeom.erase(myGeom.begin() + (start ? 1 : i + 1));
959  checkGeometry(maxAngle, minRadius, fix);
960  return;
961  } else {
962  WRITE_WARNING("Found sharp turn with radius " + toString(r) + " at the " +
963  (start ? "start" : "end") + " of edge '" + getID() + "'.");
964  }
965  }
966  }
967  }
968  //std::cout << "\n";
969 }
970 
971 
972 // ----------- Setting and getting connections
973 bool
976  return true;
977  }
978  // check whether the node was merged and now a connection between
979  // not matching edges is tried to be added
980  // This happens f.e. within the ptv VISSIM-example "Beijing"
981  if (dest != nullptr && myTo != dest->myFrom) {
982  return false;
983  }
984  if (dest == nullptr) {
986  myConnections.push_back(Connection(-1, dest, -1));
987  } else if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(dest)) == myConnections.end()) {
988  myConnections.push_back(Connection(-1, dest, -1));
989  }
990  if (myStep < EDGE2EDGES) {
991  myStep = EDGE2EDGES;
992  }
993  return true;
994 }
995 
996 
997 bool
999  int toLane, Lane2LaneInfoType type,
1000  bool mayUseSameDestination,
1001  bool mayDefinitelyPass,
1002  bool keepClear,
1003  double contPos,
1004  double visibility,
1005  double speed,
1006  const PositionVector& customShape,
1007  bool uncontrolled) {
1009  return true;
1010  }
1011  // check whether the node was merged and now a connection between
1012  // not matching edges is tried to be added
1013  // This happens f.e. within the ptv VISSIM-example "Beijing"
1014  if (myTo != dest->myFrom) {
1015  return false;
1016  }
1017  if (!addEdge2EdgeConnection(dest)) {
1018  return false;
1019  }
1020  return setConnection(from, dest, toLane, type, mayUseSameDestination, mayDefinitelyPass, keepClear, contPos, visibility, speed, customShape, uncontrolled);
1021 }
1022 
1023 
1024 bool
1026  NBEdge* dest, int toLane,
1027  int no, Lane2LaneInfoType type,
1028  bool invalidatePrevious,
1029  bool mayDefinitelyPass) {
1030  if (invalidatePrevious) {
1031  invalidateConnections(true);
1032  }
1033  bool ok = true;
1034  for (int i = 0; i < no && ok; i++) {
1035  ok &= addLane2LaneConnection(fromLane + i, dest, toLane + i, type, false, mayDefinitelyPass);
1036  }
1037  return ok;
1038 }
1039 
1040 
1041 bool
1042 NBEdge::setConnection(int lane, NBEdge* destEdge,
1043  int destLane, Lane2LaneInfoType type,
1044  bool mayUseSameDestination,
1045  bool mayDefinitelyPass,
1046  bool keepClear,
1047  double contPos,
1048  double visibility,
1049  double speed,
1050  const PositionVector& customShape,
1051  bool uncontrolled) {
1053  return false;
1054  }
1055  // some kind of a misbehaviour which may occure when the junction's outgoing
1056  // edge priorities were not properly computed, what may happen due to
1057  // an incomplete or not proper input
1058  // what happens is that under some circumstances a single lane may set to
1059  // be approached more than once by the one of our lanes.
1060  // This must not be!
1061  // we test whether it is the case and do nothing if so - the connection
1062  // will be refused
1063  //
1064  if (!mayUseSameDestination && hasConnectionTo(destEdge, destLane)) {
1065  return false;
1066  }
1067  if (find_if(myConnections.begin(), myConnections.end(), connections_finder(lane, destEdge, destLane)) != myConnections.end()) {
1068  return true;
1069  }
1070  if ((int)myLanes.size() <= lane || destEdge->getNumLanes() <= (int)destLane) {
1071  // problem might be corrigible in post-processing
1072  WRITE_WARNING("Could not set connection from '" + getLaneIDInsecure(lane) + "' to '" + destEdge->getLaneIDInsecure(destLane) + "'.");
1073  return false;
1074  }
1075  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1076  if ((*i).toEdge == destEdge && ((*i).fromLane == -1 || (*i).toLane == -1)) {
1077  i = myConnections.erase(i);
1078  } else {
1079  ++i;
1080  }
1081  }
1082  myConnections.push_back(Connection(lane, destEdge, destLane));
1083  if (mayDefinitelyPass) {
1084  myConnections.back().mayDefinitelyPass = true;
1085  }
1086  myConnections.back().keepClear = keepClear;
1087  myConnections.back().contPos = contPos;
1088  myConnections.back().visibility = visibility;
1089  myConnections.back().speed = speed;
1090  myConnections.back().customShape = customShape;
1091  myConnections.back().uncontrolled = uncontrolled;
1092  if (type == L2L_USER) {
1094  } else {
1095  // check whether we have to take another look at it later
1096  if (type == L2L_COMPUTED) {
1097  // yes, the connection was set using an algorithm which requires a recheck
1099  } else {
1100  // ok, let's only not recheck it if we did no add something that has to be rechecked
1101  if (myStep != LANES2LANES_RECHECK) {
1103  }
1104  }
1105  }
1106  return true;
1107 }
1108 
1109 
1110 void
1112  myConnections.push_back(connection);
1113 }
1114 
1115 
1116 std::vector<NBEdge::Connection>
1118  std::vector<NBEdge::Connection> ret;
1119  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1120  if ((*i).fromLane == lane) {
1121  ret.push_back(*i);
1122  }
1123  }
1124  return ret;
1125 }
1126 
1127 
1129 NBEdge::getConnection(int fromLane, const NBEdge* to, int toLane) const {
1130  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1131  if (
1132  (*i).fromLane == fromLane
1133  && (*i).toEdge == to
1134  && (*i).toLane == toLane) {
1135  return *i;
1136  }
1137  }
1138  throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1139  + " to " + to->getID() + "_" + toString(toLane) + " not found");
1140 }
1141 
1143 NBEdge::getConnectionRef(int fromLane, const NBEdge* to, int toLane) {
1144  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1145  if (
1146  (*i).fromLane == fromLane
1147  && (*i).toEdge == to
1148  && (*i).toLane == toLane) {
1149  return *i;
1150  }
1151  }
1152  throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1153  + " to " + to->getID() + "_" + toString(toLane) + " not found");
1154 }
1155 
1156 
1157 bool
1158 NBEdge::hasConnectionTo(NBEdge* destEdge, int destLane, int fromLane) const {
1159  return destEdge != nullptr && find_if(myConnections.begin(), myConnections.end(), connections_toedgelane_finder(destEdge, destLane, fromLane)) != myConnections.end();
1160 }
1161 
1162 
1163 bool
1165  if (e == myTurnDestination) {
1166  return true;
1167  }
1168  return
1169  find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(e))
1170  !=
1171  myConnections.end();
1172 
1173 }
1174 
1175 
1176 const EdgeVector*
1178  // check whether connections exist and if not, use edges from the node
1179  EdgeVector outgoing;
1180  if (myConnections.size() == 0) {
1181  outgoing = myTo->getOutgoingEdges();
1182  } else {
1183  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1184  if (find(outgoing.begin(), outgoing.end(), (*i).toEdge) == outgoing.end()) {
1185  outgoing.push_back((*i).toEdge);
1186  }
1187  }
1188  }
1189  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
1190  if (it->fromLane < 0 && it->toLane < 0) {
1191  // found an edge that shall not be connected
1192  EdgeVector::iterator forbidden = find(outgoing.begin(), outgoing.end(), it->toEdge);
1193  if (forbidden != outgoing.end()) {
1194  outgoing.erase(forbidden);
1195  }
1196  }
1197  }
1198  // allocate the sorted container
1199  int size = (int) outgoing.size();
1200  EdgeVector* edges = new EdgeVector();
1201  edges->reserve(size);
1202  for (EdgeVector::const_iterator i = outgoing.begin(); i != outgoing.end(); i++) {
1203  NBEdge* outedge = *i;
1204  if (outedge != nullptr && outedge != myTurnDestination) {
1205  edges->push_back(outedge);
1206  }
1207  }
1208  sort(edges->begin(), edges->end(), NBContHelper::relative_outgoing_edge_sorter(this));
1209  return edges;
1210 }
1211 
1212 
1213 EdgeVector
1215  EdgeVector ret;
1216  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1217  if (find(ret.begin(), ret.end(), (*i).toEdge) == ret.end()) {
1218  ret.push_back((*i).toEdge);
1219  }
1220  }
1221  return ret;
1222 }
1223 
1224 
1225 EdgeVector
1227  EdgeVector ret;
1228  const EdgeVector& candidates = myFrom->getIncomingEdges();
1229  for (EdgeVector::const_iterator i = candidates.begin(); i != candidates.end(); i++) {
1230  if ((*i)->isConnectedTo(this)) {
1231  ret.push_back(*i);
1232  }
1233  }
1234  return ret;
1235 }
1236 
1237 
1238 std::vector<int>
1239 NBEdge::getConnectionLanes(NBEdge* currentOutgoing) const {
1240  std::vector<int> ret;
1241  if (currentOutgoing != myTurnDestination) {
1242  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1243  if ((*i).toEdge == currentOutgoing) {
1244  ret.push_back((*i).fromLane);
1245  }
1246  }
1247  }
1248  return ret;
1249 }
1250 
1251 
1252 void
1255 }
1256 
1257 
1258 void
1260  sort(myConnections.begin(), myConnections.end(), connections_sorter);
1261 }
1262 
1263 
1264 void
1266  EdgeVector connected = getConnectedEdges();
1267  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
1268  NBEdge* inc = *i;
1269  // We have to do this
1270  inc->myStep = EDGE2EDGES;
1271  // add all connections
1272  for (EdgeVector::iterator j = connected.begin(); j != connected.end(); j++) {
1273  inc->addEdge2EdgeConnection(*j);
1274  }
1275  inc->removeFromConnections(this);
1276  }
1277 }
1278 
1279 
1280 void
1281 NBEdge::removeFromConnections(NBEdge* toEdge, int fromLane, int toLane, bool tryLater, const bool adaptToLaneRemoval) {
1282  // remove from "myConnections"
1283  const int fromLaneRemoved = adaptToLaneRemoval && fromLane >= 0 ? fromLane : -1;
1284  const int toLaneRemoved = adaptToLaneRemoval && toLane >= 0 ? toLane : -1;
1285  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1286  Connection& c = *i;
1287  if ((toEdge == nullptr || c.toEdge == toEdge)
1288  && (fromLane < 0 || c.fromLane == fromLane)
1289  && (toLane < 0 || c.toLane == toLane)) {
1290  if (myTo->isTLControlled()) {
1291  std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1292  for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1293  (*it)->removeConnection(NBConnection(this, c.fromLane, c.toEdge, c.toLane));
1294  }
1295  }
1296  i = myConnections.erase(i);
1297  tryLater = false;
1298  } else {
1299  if (fromLaneRemoved >= 0 && c.fromLane > fromLaneRemoved) {
1300  if (myTo->isTLControlled()) {
1301  std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1302  for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1303  for (NBConnectionVector::iterator tlcon = (*it)->getControlledLinks().begin(); tlcon != (*it)->getControlledLinks().end(); ++tlcon) {
1304  NBConnection& tc = *tlcon;
1305  if (tc.getTo() == c.toEdge && tc.getFromLane() == c.fromLane && tc.getToLane() == c.toLane) {
1306  tc.shiftLaneIndex(this, -1);
1307  }
1308  }
1309  }
1310  }
1311  c.fromLane--;
1312  }
1313  if (toLaneRemoved >= 0 && c.toLane > toLaneRemoved) {
1314  c.toLane--;
1315  }
1316  ++i;
1317  }
1318  }
1319  // check whether it was the turn destination
1320  if (myTurnDestination == toEdge && fromLane < 0) {
1321  myTurnDestination = nullptr;
1322  }
1323  if (myPossibleTurnDestination == toEdge && fromLane < 0) {
1324  myPossibleTurnDestination = nullptr;
1325  }
1326  if (tryLater) {
1327  myConnectionsToDelete.push_back(Connection(fromLane, toEdge, toLane));
1328  }
1329 }
1330 
1331 
1332 bool
1334  // iterate over connections
1335  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
1336  if (((*i).toEdge == connectionToRemove.toEdge) && ((*i).fromLane == connectionToRemove.fromLane) && ((*i).toLane == connectionToRemove.toLane)) {
1337  // remove connection
1338  myConnections.erase(i);
1339  return true;
1340  }
1341  }
1342  assert(false);
1343  return false;
1344 }
1345 
1346 
1347 void
1348 NBEdge::invalidateConnections(bool reallowSetting) {
1349  myTurnDestination = nullptr;
1350  myConnections.clear();
1351  if (reallowSetting) {
1352  myStep = INIT;
1353  } else {
1355  }
1356 }
1357 
1358 
1359 void
1360 NBEdge::replaceInConnections(NBEdge* which, NBEdge* by, int laneOff) {
1361  // replace in "_connectedEdges"
1362  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1363  if ((*i).toEdge == which) {
1364  (*i).toEdge = by;
1365  (*i).toLane += laneOff;
1366  }
1367  }
1368  // check whether it was the turn destination
1369  if (myTurnDestination == which) {
1370  myTurnDestination = by;
1371  }
1372 }
1373 
1374 void
1375 NBEdge::replaceInConnections(NBEdge* which, const std::vector<NBEdge::Connection>& origConns) {
1376  std::map<int, int> laneMap;
1377  int minLane = -1;
1378  int maxLane = -1;
1379  // get lanes used to approach the edge to remap
1380  bool wasConnected = false;
1381  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1382  if ((*i).toEdge != which) {
1383  continue;
1384  }
1385  wasConnected = true;
1386  if ((*i).fromLane != -1) {
1387  int fromLane = (*i).fromLane;
1388  laneMap[(*i).toLane] = fromLane;
1389  if (minLane == -1 || minLane > fromLane) {
1390  minLane = fromLane;
1391  }
1392  if (maxLane == -1 || maxLane < fromLane) {
1393  maxLane = fromLane;
1394  }
1395  }
1396  }
1397  if (!wasConnected) {
1398  return;
1399  }
1400  // add new connections
1401  std::vector<NBEdge::Connection> conns = origConns;
1402  for (std::vector<NBEdge::Connection>::iterator i = conns.begin(); i != conns.end(); ++i) {
1403  if ((*i).toEdge == which || (*i).toEdge == this) {
1404  continue;
1405  }
1406  if (which->getStep() == EDGE2EDGES) {
1407  // do not set lane-level connections
1408  replaceInConnections(which, (*i).toEdge, 0);
1409  continue;
1410  }
1411  int fromLane = (*i).fromLane;
1412  int toUse = -1;
1413  if (laneMap.find(fromLane) == laneMap.end()) {
1414  if (fromLane >= 0 && fromLane <= minLane) {
1415  toUse = minLane;
1416  }
1417  if (fromLane >= 0 && fromLane >= maxLane) {
1418  toUse = maxLane;
1419  }
1420  } else {
1421  toUse = laneMap[fromLane];
1422  }
1423  if (toUse == -1) {
1424  toUse = 0;
1425  }
1426  setConnection(toUse, i->toEdge, i->toLane, L2L_COMPUTED, false, i->mayDefinitelyPass, i->keepClear,
1427  i->contPos, i->visibility, i->speed, i->customShape, i->uncontrolled);
1428  }
1429  // remove the remapped edge from connections
1430  removeFromConnections(which);
1431 }
1432 
1433 
1434 void
1436  myStep = src->myStep;
1438 }
1439 
1440 
1441 bool
1442 NBEdge::canMoveConnection(const Connection& con, int newFromLane) const {
1443  // only allow using newFromLane if at least 1 vClass is permitted to use
1444  // this connection. If the connection shall be moved to a sidewalk, only create the connection if there is no walking area
1445  const SVCPermissions common = (getPermissions(newFromLane) & con.toEdge->getPermissions(con.toLane));
1446  return (common > 0 && common != SVC_PEDESTRIAN);
1447 }
1448 
1449 
1450 void
1452  int index = 0;
1453  for (int i = 0; i < (int)myConnections.size(); ++i) {
1454  if (myConnections[i].fromLane == (int)(lane) && canMoveConnection(myConnections[i], lane + 1)) {
1455  index = i;
1456  }
1457  }
1458  std::vector<Connection>::iterator i = myConnections.begin() + index;
1459  Connection c = *i;
1460  myConnections.erase(i);
1461  setConnection(lane + 1, c.toEdge, c.toLane, L2L_VALIDATED, false);
1462 }
1463 
1464 
1465 void
1467  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1468  if ((*i).fromLane == (int)lane && canMoveConnection(*i, lane - 1)) {
1469  Connection c = *i;
1470  i = myConnections.erase(i);
1471  setConnection(lane - 1, c.toEdge, c.toLane, L2L_VALIDATED, false);
1472  return;
1473  }
1474  }
1475 }
1476 
1477 
1478 void
1479 NBEdge::buildInnerEdges(const NBNode& n, int noInternalNoSplits, int& linkIndex, int& splitIndex) {
1480  const int numPoints = OptionsCont::getOptions().getInt("junctions.internal-link-detail");
1481  const bool joinTurns = OptionsCont::getOptions().getBool("junctions.join-turns");
1482  const double limitTurnSpeed = OptionsCont::getOptions().getFloat("junctions.limit-turn-speed");
1483  const double limitTurnSpeedMinAngle = DEG2RAD(OptionsCont::getOptions().getFloat("junctions.limit-turn-speed.min-angle"));
1484  const double limitTurnSpeedMinAngleRail = DEG2RAD(OptionsCont::getOptions().getFloat("junctions.limit-turn-speed.min-angle.railway"));
1485  const double limitTurnSpeedWarnStraight = OptionsCont::getOptions().getFloat("junctions.limit-turn-speed.warn.straight");
1486  const double limitTurnSpeedWarnTurn = OptionsCont::getOptions().getFloat("junctions.limit-turn-speed.warn.turn");
1487  const bool fromRail = isRailway(getPermissions());
1488  std::string innerID = ":" + n.getID();
1489  NBEdge* toEdge = nullptr;
1490  int edgeIndex = linkIndex;
1491  int internalLaneIndex = 0;
1492  int numLanes = 0; // number of lanes that share the same edge
1493  double lengthSum = 0; // total shape length of all lanes that share the same edge
1494  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1495  Connection& con = *i;
1496  con.haveVia = false; // reset first since this may be called multiple times
1497  if (con.toEdge == nullptr) {
1498  continue;
1499  }
1500  LinkDirection dir = n.getDirection(this, con.toEdge);
1501  const bool isRightTurn = (dir == LINKDIR_RIGHT || dir == LINKDIR_PARTRIGHT);
1502  const bool isTurn = (isRightTurn || dir == LINKDIR_LEFT || dir == LINKDIR_PARTLEFT);
1503 
1504  // put turning internal lanes on separate edges
1505  if (con.toEdge != toEdge || (isTurn && !joinTurns)) {
1506  // skip indices to keep some correspondence between edge ids and link indices:
1507  // internalEdgeIndex + internalLaneIndex = linkIndex
1508  edgeIndex = linkIndex;
1509  toEdge = (*i).toEdge;
1510  internalLaneIndex = 0;
1511  assignInternalLaneLength(i, numLanes, lengthSum);
1512  numLanes = 0;
1513  lengthSum = 0;
1514  }
1515  PositionVector shape = n.computeInternalLaneShape(this, con, numPoints, myTo);
1516  std::vector<int> foeInternalLinks;
1517 
1518  if (dir != LINKDIR_STRAIGHT && shape.length() < POSITION_EPS && !(isBidiRail() && getTurnDestination(true) == con.toEdge)) {
1519  WRITE_WARNING("Connection '" + getID() + "_" + toString(con.fromLane) + "->" + con.toEdge->getID() + "_" + toString(con.toLane) + "' is only " + toString(shape.length()) + " short.");
1520  }
1521 
1522  // crossingPosition, list of foe link indices
1523  std::pair<double, std::vector<int> > crossingPositions(-1, std::vector<int>());
1524  std::set<std::string> tmpFoeIncomingLanes;
1525  switch (dir) {
1526  case LINKDIR_RIGHT:
1527  case LINKDIR_PARTRIGHT:
1528  case LINKDIR_LEFT:
1529  case LINKDIR_PARTLEFT:
1530  case LINKDIR_TURN: {
1531  int index = 0;
1532  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
1533  for (EdgeVector::const_iterator i2 = incoming.begin(); i2 != incoming.end(); ++i2) {
1534  const std::vector<Connection>& elv = (*i2)->getConnections();
1535  for (std::vector<NBEdge::Connection>::const_iterator k2 = elv.begin(); k2 != elv.end(); k2++) {
1536  if ((*k2).toEdge == nullptr) {
1537  continue;
1538  }
1539  // vehicles are typically less wide than the lane
1540  // they drive on but but bicycle lanes should be kept clear for their whole width
1541  double width2 = (*k2).toEdge->getLaneWidth((*k2).toLane);
1542  if ((*k2).toEdge->getPermissions((*k2).toLane) != SVC_BICYCLE) {
1543  width2 *= 0.5;
1544  }
1545  const bool foes = n.foes(this, con.toEdge, *i2, (*k2).toEdge);
1546  bool needsCont = n.needsCont(this, *i2, con, *k2);
1547  const bool oppositeLeftIntersect = !foes && bothLeftIntersect(n, shape, dir, *i2, *k2, numPoints, width2);
1548  const bool bothPrio = getJunctionPriority(&n) > 0 && (*i2)->getJunctionPriority(&n) > 0;
1549  //std::cout << "n=" << n.getID() << " e1=" << getID() << " prio=" << getJunctionPriority(&n) << " e2=" << (*i2)->getID() << " prio2=" << (*i2)->getJunctionPriority(&n) << " both=" << bothPrio << " bothLeftIntersect=" << bothLeftIntersect(n, shape, dir, *i2, *k2, numPoints, width2) << " needsCont=" << needsCont << "\n";
1550  // compute the crossing point
1551  if (needsCont || (bothPrio && oppositeLeftIntersect)) {
1552  crossingPositions.second.push_back(index);
1553  const PositionVector otherShape = n.computeInternalLaneShape(*i2, *k2, numPoints);
1554  const double minDV = firstIntersection(shape, otherShape, width2);
1555  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1556  assert(minDV >= 0);
1557  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1558  crossingPositions.first = minDV;
1559  }
1560  }
1561  }
1562  const bool rightTurnConflict = NBNode::rightTurnConflict(
1563  this, con.toEdge, con.fromLane, (*i2), (*k2).toEdge, (*k2).fromLane);
1564  // compute foe internal lanes
1565  if (foes || rightTurnConflict || oppositeLeftIntersect) {
1566  foeInternalLinks.push_back(index);
1567  }
1568  // only warn once per pair of intersecting turns
1569  // do not warn if only bicycles pedestrians or delivery vehicles are involved as this is a typical occurence
1571  if (oppositeLeftIntersect && getID() > (*i2)->getID()
1572  && (getPermissions(con.fromLane) & warn) != 0
1573  && (con.toEdge->getPermissions(con.toLane) & warn) != 0
1574  && ((*i2)->getPermissions((*k2).fromLane) & warn) != 0
1575  && ((*k2).toEdge->getPermissions((*k2).toLane) & warn) != 0
1576  // do not warn for unregulated nodes
1577  && n.getType() != NODETYPE_NOJUNCTION
1578  ) {
1579  WRITE_WARNING("Intersecting left turns at junction '" + n.getID() + "' from lane '" + getLaneID(con.fromLane) + "' and lane '" + (*i2)->getLaneID((*k2).fromLane) + "'. (increase junction radius to avoid this)");
1580  }
1581  // compute foe incoming lanes
1582  const bool signalised = hasSignalisedConnectionTo(con.toEdge);
1583  if ((n.forbids(*i2, (*k2).toEdge, this, con.toEdge, signalised) || rightTurnConflict) && (needsCont || dir == LINKDIR_TURN)) {
1584  tmpFoeIncomingLanes.insert((*i2)->getID() + "_" + toString((*k2).fromLane));
1585  }
1586  if (bothPrio && oppositeLeftIntersect && getID() < (*i2)->getID()) {
1587  //std::cout << " c1=" << con.getDescription(this) << " c2=" << (*k2).getDescription(*i2) << " bothPrio=" << bothPrio << " oppositeLeftIntersect=" << oppositeLeftIntersect << "\n";
1588  // break symmetry using edge id
1589  tmpFoeIncomingLanes.insert(innerID + "_" + toString(index) + "_0");
1590  }
1591  index++;
1592  }
1593  }
1594  // foe pedestrian crossings
1595  std::vector<NBNode::Crossing*> crossings = n.getCrossings();
1596  for (auto c : crossings) {
1597  const NBNode::Crossing& crossing = *c;
1598  for (EdgeVector::const_iterator it_e = crossing.edges.begin(); it_e != crossing.edges.end(); ++it_e) {
1599  const NBEdge* edge = *it_e;
1600  // compute foe internal lanes
1601  if (this == edge || con.toEdge == edge) {
1602  foeInternalLinks.push_back(index);
1603  if (con.toEdge == edge &&
1604  ((isRightTurn && getJunctionPriority(&n) > 0) || (isTurn && n.isTLControlled()))) {
1605  // build internal junctions (not for left turns at uncontrolled intersections)
1606  PositionVector crossingShape = crossing.shape;
1607  crossingShape.extrapolate(5.0); // sometimes shapes miss each other by a small margin
1608  const double minDV = firstIntersection(shape, crossingShape, crossing.width / 2);
1609  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) {
1610  assert(minDV >= 0);
1611  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1612  crossingPositions.first = minDV;
1613  }
1614  }
1615  }
1616  }
1617  }
1618  index++;
1619  }
1620 
1621  if (dir == LINKDIR_TURN && crossingPositions.first < 0 && crossingPositions.second.size() != 0 && shape.length() > 2. * POSITION_EPS) {
1622  // let turnarounds wait in the middle if no other crossing point was found and it has a sensible length
1623  // (if endOffset is used, the crossing point is in the middle of the part within the junction shape)
1624  crossingPositions.first = (double)(shape.length() + getEndOffset(con.fromLane)) / 2.;
1625  }
1626  }
1627  break;
1628  default:
1629  break;
1630  }
1631  if (con.contPos != UNSPECIFIED_CONTPOS) {
1632  // apply custom internal junction position
1633  if (con.contPos <= 0 || con.contPos >= shape.length()) {
1634  // disable internal junction
1635  crossingPositions.first = -1;
1636  } else {
1637  // set custom position
1638  crossingPositions.first = con.contPos;
1639  }
1640  }
1641 
1642  // @todo compute the maximum speed allowed based on angular velocity
1643  // see !!! for an explanation (with a_lat_mean ~0.3)
1644  /*
1645  double vmax = (double) 0.3 * (double) 9.80778 *
1646  getLaneShape(con.fromLane).back().distanceTo(
1647  con.toEdge->getLaneShape(con.toLane).front())
1648  / (double) 2.0 / (double) M_PI;
1649  vmax = MIN2(vmax, ((getSpeed() + con.toEdge->getSpeed()) / (double) 2.0));
1650  */
1651  if (con.speed == UNSPECIFIED_SPEED) {
1652  con.vmax = (myLanes[con.fromLane].speed + con.toEdge->getLanes()[con.toLane].speed) / (double) 2.0;
1653  if (limitTurnSpeed > 0) {
1654  // see [Odhams and Cole, Models of Driver Speed Choice in Curves, 2004]
1655  const double angleRaw = fabs(GeomHelper::angleDiff(
1656  getLaneShape(con.fromLane).angleAt2D(-2),
1657  con.toEdge->getLaneShape(con.toLane).angleAt2D(0)));
1658  const double angle = MAX2(0.0, angleRaw - (fromRail ? limitTurnSpeedMinAngleRail : limitTurnSpeedMinAngle));
1659  const double length = shape.length2D();
1660  // do not trust the radius of tiny junctions
1661  // formula adapted from [Odhams, Andre and Cole, David, Models of Driver Speed Choice in Curves, 2004]
1662  if (angle > 0 && length > 1) {
1663  // permit higher turning speed on wide lanes
1664  const double radius = length / angle + getLaneWidth(con.fromLane) / 4;
1665  const double limit = sqrt(limitTurnSpeed * radius);
1666  const double reduction = con.vmax - limit;
1667  // always treat connctions at roundabout as turns when warning
1668  const bool atRoundabout = getJunctionPriority(myTo) == ROUNDABOUT || con.toEdge->getJunctionPriority(myFrom) == ROUNDABOUT;
1669  int dir2 = atRoundabout ? LINKDIR_LEFT : dir;
1670  if ((dir2 == LINKDIR_STRAIGHT && reduction > limitTurnSpeedWarnStraight)
1671  || (dir2 != LINKDIR_TURN && reduction > limitTurnSpeedWarnTurn)) {
1672  std::string dirType = std::string(dir == LINKDIR_STRAIGHT ? "straight" : "turning");
1673  if (atRoundabout) {
1674  dirType = "roundabout";
1675  }
1676  WRITE_WARNING("Speed of " + dirType + " connection '" + con.getDescription(this)
1677  + "' reduced by " + toString(reduction) + " due to turning radius of " + toString(radius)
1678  + " (length=" + toString(length) + " angle=" + toString(RAD2DEG(angleRaw)) + ")");
1679  }
1680  con.vmax = MIN2(con.vmax, limit);
1681  // value is saved in <net> attribute. Must be set again when importing from .con.xml
1682  // con.speed = con.vmax;
1683  }
1684  assert(con.vmax > 0);
1685  //if (getID() == "-1017000.0.00") {
1686  // std::cout << con.getDescription(this) << " angleRaw=" << angleRaw << " angle=" << RAD2DEG(angle) << " length=" << length << " radius=" << length / angle
1687  // << " vmaxTurn=" << sqrt(limitTurnSpeed * length / angle) << " vmax=" << con.vmax << "\n";
1688  //}
1689  }
1690  } else {
1691  con.vmax = con.speed;
1692  }
1693  //
1694  assert(shape.size() >= 2);
1695  // get internal splits if any
1696  con.id = innerID + "_" + toString(edgeIndex);
1697  if (crossingPositions.first >= 0) {
1698  std::pair<PositionVector, PositionVector> split = shape.splitAt(crossingPositions.first);
1699  con.shape = split.first;
1700  con.foeIncomingLanes = std::vector<std::string>(tmpFoeIncomingLanes.begin(), tmpFoeIncomingLanes.end());
1701  con.foeInternalLinks = foeInternalLinks; // resolve link indices to lane ids later
1702  con.viaID = innerID + "_" + toString(splitIndex + noInternalNoSplits);
1703  ++splitIndex;
1704  con.viaShape = split.second;
1705  con.haveVia = true;
1706  } else {
1707  con.shape = shape;
1708  }
1709  con.internalLaneIndex = internalLaneIndex;
1710  ++internalLaneIndex;
1711  ++linkIndex;
1712  ++numLanes;
1713  lengthSum += MAX2(POSITION_EPS, con.shape.length());
1714  }
1715  assignInternalLaneLength(myConnections.end(), numLanes, lengthSum);
1716 }
1717 
1718 
1719 void
1720 NBEdge::assignInternalLaneLength(std::vector<Connection>::iterator i, int numLanes, double lengthSum) {
1721  // assign average length to all lanes of the same internal edge
1722  // @note the actual length should be used once sumo supports lanes of
1723  // varying length within the same edge
1724  assert(i - myConnections.begin() >= numLanes);
1725  for (int prevIndex = 1; prevIndex <= numLanes; prevIndex++) {
1726  //std::cout << " con=" << (*(i - prevIndex)).getDescription(this) << " numLanes=" << numLanes << " avgLength=" << lengthSum / numLanes << "\n";
1727  (*(i - prevIndex)).length = lengthSum / numLanes;
1728  }
1729 }
1730 
1731 double
1732 NBEdge::firstIntersection(const PositionVector& v1, const PositionVector& v2, double width2) {
1733  double intersect = std::numeric_limits<double>::max();
1734  if (v2.length() < POSITION_EPS) {
1735  return intersect;
1736  }
1737  PositionVector v2Right = v2;
1738  v2Right.move2side(width2);
1739 
1740  PositionVector v2Left = v2;
1741  v2Left.move2side(-width2);
1742 
1743  // intersect center line of v1 with left and right border of v2
1744  for (double cand : v1.intersectsAtLengths2D(v2Right)) {
1745  intersect = MIN2(intersect, cand);
1746  }
1747  for (double cand : v1.intersectsAtLengths2D(v2Left)) {
1748  intersect = MIN2(intersect, cand);
1749  }
1750  //std::cout << " v1=" << v1 << " v2Right=" << v2Right << " v2Left=" << v2Left << "\n";
1751  //std::cout << " intersectsRight=" << toString(v1.intersectsAtLengths2D(v2Right)) << "\n";
1752  //std::cout << " intersectsLeft=" << toString(v1.intersectsAtLengths2D(v2Left)) << "\n";
1753  return intersect;
1754 }
1755 
1756 
1757 bool
1758 NBEdge::bothLeftIntersect(const NBNode& n, const PositionVector& shape, LinkDirection dir, NBEdge* otherFrom, const NBEdge::Connection& otherCon, int numPoints, double width2) const {
1759  if (otherFrom == this) {
1760  // not an opposite pair
1761  return false;
1762  }
1763  LinkDirection dir2 = n.getDirection(otherFrom, otherCon.toEdge);
1764  const bool bothLeft = (dir == LINKDIR_LEFT || dir == LINKDIR_PARTLEFT) && (dir2 == LINKDIR_LEFT || dir2 == LINKDIR_PARTLEFT);
1765  if (bothLeft) {
1766  const PositionVector otherShape = n.computeInternalLaneShape(otherFrom, otherCon, numPoints);
1767  const double minDV = firstIntersection(shape, otherShape, width2);
1768  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) {
1769  return true;
1770  } else {
1771  return false;
1772  }
1773  } else {
1774  return false;
1775  }
1776 }
1777 
1778 
1779 // -----------
1780 int
1781 NBEdge::getJunctionPriority(const NBNode* const node) const {
1782  if (node == myFrom) {
1783  return myFromJunctionPriority;
1784  } else {
1785  return myToJunctionPriority;
1786  }
1787 }
1788 
1789 
1790 void
1791 NBEdge::setJunctionPriority(const NBNode* const node, int prio) {
1792  if (node == myFrom) {
1793  myFromJunctionPriority = prio;
1794  } else {
1795  myToJunctionPriority = prio;
1796  }
1797 }
1798 
1799 
1800 double
1801 NBEdge::getAngleAtNode(const NBNode* const atNode) const {
1802  // myStartAngle, myEndAngle are in [0,360] and this returns results in [-180,180]
1803  if (atNode == myFrom) {
1805  } else {
1806  assert(atNode == myTo);
1808  }
1809 }
1810 
1811 
1812 double
1813 NBEdge::getAngleAtNodeToCenter(const NBNode* const atNode) const {
1814  if (atNode == myFrom) {
1815  double res = myStartAngle - 180;
1816  if (res < 0) {
1817  res += 360;
1818  }
1819  return res;
1820  } else {
1821  assert(atNode == myTo);
1822  return myEndAngle;
1823  }
1824 }
1825 
1826 
1827 void
1828 NBEdge::setTurningDestination(NBEdge* e, bool onlyPossible) {
1829  if (!onlyPossible) {
1830  myTurnDestination = e;
1831  }
1833 }
1834 
1835 
1836 double
1837 NBEdge::getLaneSpeed(int lane) const {
1838  return myLanes[lane].speed;
1839 }
1840 
1841 
1842 void
1844  // vissim needs this
1845  if (myFrom == myTo) {
1846  return;
1847  }
1848  // compute lane offset, first
1849  std::vector<double> offsets(myLanes.size(), 0.);
1850  double offset = 0;
1851  for (int i = (int)myLanes.size() - 2; i >= 0; --i) {
1852  offset += (getLaneWidth(i) + getLaneWidth(i + 1)) / 2. + SUMO_const_laneOffset;
1853  offsets[i] = offset;
1854  }
1856  double laneWidth = myLanes.back().width != UNSPECIFIED_WIDTH ? myLanes.back().width : SUMO_const_laneWidth;
1857  offset = (laneWidth + SUMO_const_laneOffset) / 2.; // @note: offset for half of the center-line marking of the road
1858  } else {
1859  double width = 0;
1860  for (int i = 0; i < (int)myLanes.size(); ++i) {
1861  width += getLaneWidth(i);
1862  }
1863  width += SUMO_const_laneOffset * double(myLanes.size() - 1);
1864  offset = -width / 2. + getLaneWidth((int)myLanes.size() - 1) / 2.;
1865  }
1866  for (int i = 0; i < (int)myLanes.size(); ++i) {
1867  offsets[i] += offset;
1868  }
1869 
1870  // build the shape of each lane
1871  for (int i = 0; i < (int)myLanes.size(); ++i) {
1872  if (myLanes[i].customShape.size() != 0) {
1873  myLanes[i].shape = myLanes[i].customShape;
1874  continue;
1875  }
1876  try {
1877  myLanes[i].shape = computeLaneShape(i, offsets[i]);
1878  } catch (InvalidArgument& e) {
1879  WRITE_WARNING("In edge '" + getID() + "': lane shape could not be determined (" + e.what() + ").");
1880  myLanes[i].shape = myGeom;
1881  }
1882  }
1883 }
1884 
1885 
1887 NBEdge::computeLaneShape(int lane, double offset) const {
1888  PositionVector shape = myGeom;
1889  try {
1890  shape.move2side(offset);
1891  } catch (InvalidArgument& e) {
1892  WRITE_WARNING("In lane '" + getLaneID(lane) + "': Could not build shape (" + e.what() + ").");
1893  }
1894  return shape;
1895 }
1896 
1897 
1898 void
1900  // taking the angle at the first might be unstable, thus we take the angle
1901  // at a certain distance. (To compare two edges, additional geometry
1902  // segments are considered to resolve ambiguities)
1903  const bool hasFromShape = myFrom->getShape().size() > 0;
1904  const bool hasToShape = myTo->getShape().size() > 0;
1905  Position fromCenter = (hasFromShape ? myFrom->getShape().getCentroid() : myFrom->getPosition());
1906  Position toCenter = (hasToShape ? myTo->getShape().getCentroid() : myTo->getPosition());
1907  PositionVector shape = myGeom;
1908  if ((hasFromShape || hasToShape) && getNumLanes() > 0) {
1910  shape = myLanes[getNumLanes() - 1].shape ;
1911  } else {
1912  shape = myLanes[getNumLanes() / 2].shape;
1913  if (getNumLanes() % 2 == 0) {
1914  // there is no center lane. shift to get the center
1915  shape.move2side(getLaneWidth(getNumLanes() / 2) * 0.5);
1916  }
1917  }
1918  }
1919 
1920  // if the junction shape is suspicious we cannot trust the angle to the centroid
1921  if (hasFromShape && (myFrom->getShape().distance2D(shape[0]) > 2 * POSITION_EPS
1922  || myFrom->getShape().around(shape[-1])
1923  || !(myFrom->getShape().around(fromCenter)))) {
1924  fromCenter = myFrom->getPosition();
1925  }
1926  if (hasToShape && (myTo->getShape().distance2D(shape[-1]) > 2 * POSITION_EPS
1927  || myTo->getShape().around(shape[0])
1928  || !(myTo->getShape().around(toCenter)))) {
1929  toCenter = myTo->getPosition();
1930  }
1931 
1932  const double angleLookahead = MIN2(shape.length2D() / 2, ANGLE_LOOKAHEAD);
1933  const Position referencePosStart = shape.positionAtOffset2D(angleLookahead);
1934  myStartAngle = GeomHelper::legacyDegree(fromCenter.angleTo2D(referencePosStart), true);
1935  const Position referencePosEnd = shape.positionAtOffset2D(shape.length() - angleLookahead);
1936  myEndAngle = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(toCenter), true);
1938 #ifdef DEBUG_ANGLES
1939  if (DEBUGCOND) std::cout << "computeAngle edge=" << getID() << " fromCenter=" << fromCenter << " toCenter=" << toCenter
1940  << " refStart=" << referencePosStart << " refEnd=" << referencePosEnd << " shape=" << shape
1941  << " hasFromShape=" << hasFromShape
1942  << " hasToShape=" << hasToShape
1943  << " numLanes=" << getNumLanes()
1944  << " shapeLane=" << getNumLanes() / 2
1945  << " startA=" << myStartAngle << " endA=" << myEndAngle << " totA=" << myTotalAngle << "\n";
1946 #endif
1947 }
1948 
1949 
1950 double
1952  const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
1953  const Position referencePosStart = myGeom.positionAtOffset2D(angleLookahead);
1954  return GeomHelper::legacyDegree(myGeom.front().angleTo2D(referencePosStart), true);
1955 }
1956 
1957 
1958 double
1960  const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
1961  const Position referencePosEnd = myGeom.positionAtOffset2D(myGeom.length() - angleLookahead);
1962  return GeomHelper::legacyDegree(referencePosEnd.angleTo2D(myGeom.back()), true);
1963 }
1964 
1965 
1966 bool
1968  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1969  if ((*i).permissions != SVCAll) {
1970  return true;
1971  }
1972  }
1973  return false;
1974 }
1975 
1976 
1977 bool
1979  std::vector<Lane>::const_iterator i = myLanes.begin();
1980  SVCPermissions firstLanePermissions = i->permissions;
1981  i++;
1982  for (; i != myLanes.end(); ++i) {
1983  if (i->permissions != firstLanePermissions) {
1984  return true;
1985  }
1986  }
1987  return false;
1988 }
1989 
1990 
1991 bool
1993  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1994  if (i->speed != getSpeed()) {
1995  return true;
1996  }
1997  }
1998  return false;
1999 }
2000 
2001 
2002 bool
2004  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2005  if (i->width != myLanes.begin()->width) {
2006  return true;
2007  }
2008  }
2009  return false;
2010 }
2011 
2012 
2013 bool
2015  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2016  if (i->endOffset != myLanes.begin()->endOffset) {
2017  return true;
2018  }
2019  }
2020  return false;
2021 }
2022 
2023 
2024 bool
2026  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2027  if (!i->stopOffsets.empty()) {
2028  const std::pair<const int, double>& offsets = *(i->stopOffsets.begin());
2029  if (myStopOffsets.empty() || offsets != *(myStopOffsets.begin())) {
2030  return true;
2031  }
2032  }
2033  }
2034  return false;
2035 }
2036 
2037 
2038 bool
2040  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2041  if (i->accelRamp) {
2042  return true;
2043  }
2044  }
2045  return false;
2046 }
2047 
2048 
2049 bool
2051  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2052  if (i->customShape.size() > 0) {
2053  return true;
2054  }
2055  }
2056  return false;
2057 }
2058 
2059 
2060 bool
2062  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2063  if (i->getParametersMap().size() > 0) {
2064  return true;
2065  }
2066  }
2067  return false;
2068 }
2069 
2070 bool
2072  return (hasLaneSpecificPermissions()
2077  || hasAccelLane()
2078  || hasCustomLaneShape()
2079  || hasLaneParams()
2080  || (!myLanes.empty() && myLanes.back().oppositeID != ""));
2081 }
2082 
2083 
2084 
2085 bool
2086 NBEdge::computeEdge2Edges(bool noLeftMovers) {
2087  // return if this relationship has been build in previous steps or
2088  // during the import
2089  if (myStep >= EDGE2EDGES) {
2090  return true;
2091  }
2092  const EdgeVector& o = myTo->getOutgoingEdges();
2093  const bool fromRail = isRailway(getPermissions());
2094  for (EdgeVector::const_iterator i = o.begin(); i != o.end(); ++i) {
2095  if (noLeftMovers && myTo->isLeftMover(this, *i)) {
2096  continue;
2097  }
2098  // avoid sharp railway turns
2099  if (fromRail && isRailway((*i)->getPermissions()) &&
2100  fabs(NBHelpers::normRelAngle(getAngleAtNode(myTo), (*i)->getAngleAtNode(myTo))) > 90) {
2101  continue;
2102  };
2103  myConnections.push_back(Connection(-1, *i, -1));
2104  }
2105  myStep = EDGE2EDGES;
2106  return true;
2107 }
2108 
2109 
2110 bool
2112  // return if this relationship has been build in previous steps or
2113  // during the import
2114  if (myStep >= LANES2EDGES) {
2115  return true;
2116  }
2117  assert(myStep == EDGE2EDGES);
2118  // get list of possible outgoing edges sorted by direction clockwise
2119  // the edge in the backward direction (turnaround) is not in the list
2120  const EdgeVector* edges = getConnectedSorted();
2121  if (myConnections.size() != 0 && edges->size() == 0) {
2122  // dead end per definition!?
2123  myConnections.clear();
2124  } else {
2125  // divide the lanes on reachable edges
2126  divideOnEdges(edges);
2127  }
2128  delete edges;
2129  myStep = LANES2EDGES;
2130  return true;
2131 }
2132 
2133 
2134 bool
2136 #ifdef DEBUG_CONNECTION_GUESSING
2137  if (DEBUGCOND) {
2138  std::cout << "recheckLanes (initial) edge=" << getID() << "\n";
2139  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
2140  std::cout << " conn " << getID() << "_" << (*i).fromLane << " to " << Named::getIDSecure((*i).toEdge) << "_" << (*i).toLane << "\n";
2141  (*i).shape.mirrorX();
2142  (*i).viaShape.mirrorX();
2143  }
2144  }
2145 #endif
2146  std::vector<int> connNumbersPerLane(myLanes.size(), 0);
2147  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
2148  if ((*i).toEdge == nullptr || (*i).fromLane < 0 || (*i).toLane < 0) {
2149  i = myConnections.erase(i);
2150  } else {
2151  if ((*i).fromLane >= 0) {
2152  ++connNumbersPerLane[(*i).fromLane];
2153  }
2154  ++i;
2155  }
2156  }
2158  // check #1:
2159  // If there is a lane with no connections and any neighbour lane has
2160  // more than one connections, try to move one of them.
2161  // This check is only done for edges which connections were assigned
2162  // using the standard algorithm.
2163  for (int i = 0; i < (int)myLanes.size(); i++) {
2164  if (connNumbersPerLane[i] == 0 && !isForbidden(getPermissions((int)i))) {
2165  if (i > 0 && connNumbersPerLane[i - 1] > 1 && getPermissions(i) == getPermissions(i - 1)) {
2166  moveConnectionToLeft(i - 1);
2167  } else if (i < (int)myLanes.size() - 1 && connNumbersPerLane[i + 1] > 1 && getPermissions(i) == getPermissions(i + 1)) {
2168  moveConnectionToRight(i + 1);
2169  }
2170  }
2171  }
2172  // check restrictions
2173  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
2174  Connection& c = *i;
2176  if (common == SVC_PEDESTRIAN || getPermissions(c.fromLane) == SVC_PEDESTRIAN) {
2177  // these are computed in NBNode::buildWalkingAreas
2178  i = myConnections.erase(i);
2179  } else if (common == 0) {
2180  // no common permissions.
2181  // try to find a suitable target lane to the right
2182  const int origToLane = c.toLane;
2183  c.toLane = -1; // ignore this connection when calling hasConnectionTo
2184  int toLane = origToLane;
2185  while (toLane > 0
2186  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
2187  && !hasConnectionTo(c.toEdge, toLane)
2188  ) {
2189  toLane--;
2190  }
2191  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
2192  && !hasConnectionTo(c.toEdge, toLane)) {
2193  c.toLane = toLane;
2194  ++i;
2195  } else {
2196  // try to find a suitable target lane to the left
2197  int toLane = origToLane;
2198  while (toLane < (int)c.toEdge->getNumLanes() - 1
2199  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
2200  && !hasConnectionTo(c.toEdge, toLane)
2201  ) {
2202  toLane++;
2203  }
2204  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
2205  && !hasConnectionTo(c.toEdge, toLane)) {
2206  c.toLane = toLane;
2207  ++i;
2208  } else {
2209  // no alternative target found
2210  i = myConnections.erase(i);
2211  }
2212  }
2214  && isTurningDirectionAt(c.toEdge)) {
2215  // do not allow sharp rail turns
2216  i = myConnections.erase(i);
2217  } else {
2218  ++i;
2219  }
2220  }
2221  }
2222  // check delayed removals
2223  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
2224  removeFromConnections(it->toEdge, it->fromLane, it->toLane);
2225  }
2226  // check involuntary dead end at "real" junctions
2227  if (getPermissions() != SVC_PEDESTRIAN) {
2228  if (myConnections.empty() && myTo->getOutgoingEdges().size() > 1) {
2229  WRITE_WARNING("Edge '" + getID() + "' is not connected to outgoing edges at junction '" + myTo->getID() + "'.");
2230  }
2231  const EdgeVector& incoming = myFrom->getIncomingEdges();
2232  if (incoming.size() > 1) {
2233  for (int i = 0; i < (int)myLanes.size(); i++) {
2234  if (getPermissions(i) != 0 && getPermissions(i) != SVC_PEDESTRIAN) {
2235  bool connected = false;
2236  for (std::vector<NBEdge*>::const_iterator in = incoming.begin(); in != incoming.end(); ++in) {
2237  if ((*in)->hasConnectionTo(this, i)) {
2238  connected = true;
2239  break;
2240  }
2241  }
2242  if (!connected) {
2243  WRITE_WARNING("Lane '" + getID() + "_" + toString(i) + "' is not connected from any incoming edge at junction '" + myFrom->getID() + "'.");
2244  }
2245  }
2246  }
2247  }
2248  }
2249 #ifdef DEBUG_CONNECTION_GUESSING
2250  if (DEBUGCOND) {
2251  std::cout << "recheckLanes (final) edge=" << getID() << "\n";
2252  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
2253  std::cout << " conn " << getID() << "_" << (*i).fromLane << " to " << Named::getIDSecure((*i).toEdge) << "_" << (*i).toLane << "\n";
2254  (*i).shape.mirrorX();
2255  (*i).viaShape.mirrorX();
2256  }
2257  }
2258 #endif
2259  return true;
2260 }
2261 
2262 
2263 void
2265  if (outgoing->size() == 0) {
2266  // we have to do this, because the turnaround may have been added before
2267  myConnections.clear();
2268  return;
2269  }
2270  // precompute edge priorities; needed as some kind of assumptions for
2271  // priorities of directions (see preparePriorities)
2272  std::vector<int>* priorities = prepareEdgePriorities(outgoing);
2273  // compute the indices of lanes that should have connections (excluding
2274  // forbidden lanes and pedestrian lanes that will be connected via walkingAreas)
2275 
2276 
2277 #ifdef DEBUG_CONNECTION_GUESSING
2278  if (DEBUGCOND) {
2279  std::cout << " divideOnEdges " << getID() << " outgoing=" << toString(*outgoing) << " prios=" << toString(*priorities) << "\n";
2280  }
2281 #endif
2282 
2283  // build connections for miv lanes
2284  std::vector<int> availableLanes;
2285  for (int i = 0; i < (int)myLanes.size(); ++i) {
2286  if ((getPermissions(i) & SVC_PASSENGER) != 0) {
2287  availableLanes.push_back(i);
2288  }
2289  }
2290  if (availableLanes.size() > 0) {
2291  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
2292  }
2293  // build connections for miscellaneous further modes (more than bike,peds,bus and without passenger)
2294  availableLanes.clear();
2295  for (int i = 0; i < (int)myLanes.size(); ++i) {
2296  const SVCPermissions perms = getPermissions(i);
2297  if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) == 0 || (perms & SVC_PASSENGER) != 0 || isForbidden(perms)) {
2298  continue;
2299  }
2300  availableLanes.push_back(i);
2301  }
2302  if (availableLanes.size() > 0) {
2303  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
2304  }
2305  // build connections for busses (possibly combined with bicycles)
2306  availableLanes.clear();
2307  for (int i = 0; i < (int)myLanes.size(); ++i) {
2308  const SVCPermissions perms = getPermissions(i);
2309  if (perms != SVC_BUS && perms != (SVC_BUS | SVC_BICYCLE)) {
2310  continue;
2311  }
2312  availableLanes.push_back(i);
2313  }
2314  if (availableLanes.size() > 0) {
2315  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
2316  }
2317  // build connections for bicycles (possibly combined with pedestrians)
2318  availableLanes.clear();
2319  for (int i = 0; i < (int)myLanes.size(); ++i) {
2320  const SVCPermissions perms = getPermissions(i);
2321  if (perms != SVC_BICYCLE && perms != (SVC_BICYCLE | SVC_PEDESTRIAN)) {
2322  continue;
2323  }
2324  availableLanes.push_back(i);
2325  }
2326  if (availableLanes.size() > 0) {
2327  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
2328  }
2329  // clean up unassigned fromLanes
2330  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
2331  if ((*i).fromLane == -1) {
2332  i = myConnections.erase(i);
2333  } else {
2334  ++i;
2335  }
2336  }
2338 
2339  delete priorities;
2340 }
2341 
2342 
2343 void
2344 NBEdge::divideSelectedLanesOnEdges(const EdgeVector* outgoing, const std::vector<int>& availableLanes, const std::vector<int>* priorities) {
2345  //std::cout << "divideSelectedLanesOnEdges " << getID() << " out=" << toString(*outgoing) << " prios=" << toString(*priorities) << " avail=" << toString(availableLanes) << "\n";
2346  // compute the sum of priorities (needed for normalisation)
2347  int prioSum = computePrioritySum(*priorities);
2348  // compute the resulting number of lanes that should be used to
2349  // reach the following edge
2350  const int numOutgoing = (int) outgoing->size();
2351  std::vector<double> resultingLanes;
2352  resultingLanes.reserve(numOutgoing);
2353  double sumResulting = 0.; // the sum of resulting lanes
2354  double minResulting = 10000.; // the least number of lanes to reach an edge
2355  for (int i = 0; i < numOutgoing; i++) {
2356  // res will be the number of lanes which are meant to reach the
2357  // current outgoing edge
2358  double res =
2359  (double)(*priorities)[i] *
2360  (double) availableLanes.size() / (double) prioSum;
2361  // do not let this number be greater than the number of available lanes
2362  if (res > availableLanes.size()) {
2363  res = (double) availableLanes.size();
2364  }
2365  // add it to the list
2366  resultingLanes.push_back(res);
2367  sumResulting += res;
2368  if (minResulting > res && res > 0) {
2369  // prevent minResulting from becoming 0
2370  minResulting = res;
2371  }
2372  }
2373  // compute the number of virtual edges
2374  // a virtual edge is used as a replacement for a real edge from now on
2375  // it shall allow to divide the existing lanes on this structure without
2376  // regarding the structure of outgoing edges
2377  int numVirtual = 0;
2378  // compute the transition from virtual to real edges
2379  EdgeVector transition;
2380  transition.reserve(numOutgoing);
2381  for (int i = 0; i < numOutgoing; i++) {
2382  // tmpNo will be the number of connections from this edge
2383  // to the next edge
2384  assert(i < (int)resultingLanes.size());
2385  const int tmpNum = (int)std::ceil(resultingLanes[i] / minResulting);
2386  numVirtual += tmpNum;
2387  for (double j = 0; j < tmpNum; j++) {
2388  transition.push_back((*outgoing)[i]);
2389  }
2390  }
2391 #ifdef DEBUG_CONNECTION_GUESSING
2392  if (DEBUGCOND) {
2393  std::cout << " prioSum=" << prioSum << " sumResulting=" << sumResulting << " minResulting=" << minResulting << " numVirtual=" << numVirtual << " availLanes=" << toString(availableLanes) << " resLanes=" << toString(resultingLanes) << " transition=" << toString(transition) << "\n";
2394  }
2395 #endif
2396 
2397  // assign lanes to edges
2398  // (conversion from virtual to real edges is done)
2399  ToEdgeConnectionsAdder adder(transition);
2400  Bresenham::compute(&adder, static_cast<int>(availableLanes.size()), numVirtual);
2401  const std::map<NBEdge*, std::vector<int> >& l2eConns = adder.getBuiltConnections();
2402  for (EdgeVector::const_iterator i = outgoing->begin(); i != outgoing->end(); ++i) {
2403  NBEdge* target = (*i);
2404  assert(l2eConns.find(target) != l2eConns.end());
2405  const std::vector<int> lanes = (l2eConns.find(target))->second;
2406  for (std::vector<int>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
2407  const int fromIndex = availableLanes[*j];
2408  if ((getPermissions(fromIndex) & target->getPermissions()) == 0) {
2409  // exclude connection if fromLane and toEdge have no common permissions
2410  continue;
2411  }
2412  if ((getPermissions(fromIndex) & target->getPermissions()) == SVC_PEDESTRIAN) {
2413  // exclude connection if the only commonly permitted class are pedestrians
2414  // these connections are later built in NBNode::buildWalkingAreas
2415  continue;
2416  }
2417  // avoid building more connections than the edge has viable lanes (earlier
2418  // ones have precedence). This is necessary when running divideSelectedLanesOnEdges more than once.
2419  // @todo To decide which target lanes are still available we need to do a
2420  // preliminary lane-to-lane assignment in regard to permissions (rather than to ordering)
2421  const int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
2422  int targetLanes = (int)target->getNumLanes();
2423  if (target->getPermissions(0) == SVC_PEDESTRIAN) {
2424  --targetLanes;
2425  }
2426  if (numConsToTarget >= targetLanes) {
2427  // let bicycles move onto the road to allow continuation
2428  // the speed limit is taken from rural roads (which allow cycles)
2429  // (pending implementation of #1859)
2430  if (getPermissions(fromIndex) == SVC_BICYCLE && getSpeed() <= (101 / 3.6)) {
2431  for (int ii = 0; ii < (int)myLanes.size(); ++ii) {
2432  if (myLanes[ii].permissions != SVC_PEDESTRIAN) {
2433  myLanes[ii].permissions |= SVC_BICYCLE;
2434  }
2435  }
2436  }
2437  continue;
2438  }
2439  if (myLanes[fromIndex].connectionsDone) {
2440  // we already have complete information about connections from
2441  // this lane. do not add anything else
2442  continue;
2443  }
2444  myConnections.push_back(Connection(fromIndex, target, -1));
2445 #ifdef DEBUG_CONNECTION_GUESSING
2446  if (DEBUGCOND) {
2447  std::cout << " request connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
2448  }
2449 #endif
2450  }
2451  }
2452 
2453  addStraightConnections(outgoing, availableLanes, priorities);
2454 }
2455 
2456 
2457 void
2458 NBEdge::addStraightConnections(const EdgeVector* outgoing, const std::vector<int>& availableLanes, const std::vector<int>* priorities) {
2459  // ensure sufficient straight connections for the (hightest-priority straight target)
2460  const int numOutgoing = (int) outgoing->size();
2461  NBEdge* target = nullptr;
2462  NBEdge* rightOfTarget = nullptr;
2463  NBEdge* leftOfTarget = nullptr;
2464  int maxPrio = 0;
2465  for (int i = 0; i < numOutgoing; i++) {
2466  if (maxPrio < (*priorities)[i]) {
2467  const LinkDirection dir = myTo->getDirection(this, (*outgoing)[i]);
2468  if (dir == LINKDIR_STRAIGHT) {
2469  maxPrio = (*priorities)[i];
2470  target = (*outgoing)[i];
2471  rightOfTarget = i == 0 ? outgoing->back() : (*outgoing)[i - 1];
2472  leftOfTarget = i + 1 == numOutgoing ? outgoing->front() : (*outgoing)[i + 1];
2473  }
2474  }
2475  }
2476  if (target == nullptr) {
2477  return;
2478  }
2479  int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
2480  int targetLanes = (int)target->getNumLanes();
2481  if (target->getPermissions(0) == SVC_PEDESTRIAN) {
2482  --targetLanes;
2483  }
2484  const int numDesiredConsToTarget = MIN2(targetLanes, (int)availableLanes.size());
2485 #ifdef DEBUG_CONNECTION_GUESSING
2486  if (DEBUGCOND) {
2487  std::cout << " checking extra lanes for target=" << target->getID() << " cons=" << numConsToTarget << " desired=" << numDesiredConsToTarget << "\n";
2488  }
2489 #endif
2490  std::vector<int>::const_iterator it_avail = availableLanes.begin();
2491  while (numConsToTarget < numDesiredConsToTarget && it_avail != availableLanes.end()) {
2492  const int fromIndex = *it_avail;
2493  if (
2494  // not yet connected
2495  (count_if(myConnections.begin(), myConnections.end(), connections_finder(fromIndex, target, -1)) == 0)
2496  // matching permissions
2497  && ((getPermissions(fromIndex) & target->getPermissions()) != 0)
2498  // more than pedestrians
2499  && ((getPermissions(fromIndex) & target->getPermissions()) != SVC_PEDESTRIAN)
2500  // lane not yet fully defined
2501  && !myLanes[fromIndex].connectionsDone
2502  ) {
2503 #ifdef DEBUG_CONNECTION_GUESSING
2504  if (DEBUGCOND) {
2505  std::cout << " candidate from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
2506  }
2507 #endif
2508  // prevent same-edge conflicts
2509  if (
2510  // no outgoing connections to the right from further left
2511  ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
2512  // no outgoing connections to the left from further right
2513  && (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)) {
2514 #ifdef DEBUG_CONNECTION_GUESSING
2515  if (DEBUGCOND) {
2516  std::cout << " request additional connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
2517  }
2518 #endif
2519  myConnections.push_back(Connection(fromIndex, target, -1));
2520  numConsToTarget++;
2521  } else {
2522 #ifdef DEBUG_CONNECTION_GUESSING
2523  if (DEBUGCOND) std::cout
2524  << " fail check1="
2525  << ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
2526  << " check2=" << (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)
2527  << " rightOfTarget=" << rightOfTarget->getID()
2528  << " leftOfTarget=" << leftOfTarget->getID()
2529  << "\n";
2530 #endif
2531 
2532  }
2533  }
2534  ++it_avail;
2535  }
2536 }
2537 
2538 
2539 std::vector<int>*
2541  // copy the priorities first
2542  std::vector<int>* priorities = new std::vector<int>();
2543  if (outgoing->size() == 0) {
2544  return priorities;
2545  }
2546  priorities->reserve(outgoing->size());
2547  EdgeVector::const_iterator i;
2548  for (i = outgoing->begin(); i != outgoing->end(); i++) {
2549  //int prio = (*i)->getJunctionPriority(myTo);
2550  int prio = NBNode::isTrafficLight(myTo->getType()) ? 0 : (*i)->getJunctionPriority(myTo);
2551  assert((prio + 1) * 2 > 0);
2552  prio = (prio + 1) * 2;
2553  priorities->push_back(prio);
2554  }
2555  // when the right turning direction has not a higher priority, divide
2556  // the importance by 2 due to the possibility to leave the junction
2557  // faster from this lane
2558  EdgeVector tmp(*outgoing);
2559  sort(tmp.begin(), tmp.end(), NBContHelper::straightness_sorter(myTo, this));
2560  i = find(outgoing->begin(), outgoing->end(), *(tmp.begin()));
2561  int dist = (int) distance(outgoing->begin(), i);
2562  MainDirections mainDirections(*outgoing, this, myTo, dist);
2563 #ifdef DEBUG_CONNECTION_GUESSING
2564  if (DEBUGCOND) std::cout << " prepareEdgePriorities " << getID()
2565  << " outgoing=" << toString(*outgoing)
2566  << " priorities1=" << toString(*priorities)
2567  << " tmp=" << toString(tmp)
2568  << " mainDirs=" << toString(mainDirections.myDirs)
2569  << " dist=" << dist
2570  << "\n";
2571 #endif
2572  if (dist != 0 && !mainDirections.includes(MainDirections::DIR_RIGHTMOST)) {
2573  assert(priorities->size() > 0);
2574  (*priorities)[0] /= 2;
2575 #ifdef DEBUG_CONNECTION_GUESSING
2576  if (DEBUGCOND) {
2577  std::cout << " priorities2=" << toString(*priorities) << "\n";
2578  }
2579 #endif
2580  }
2581  // HEURISTIC:
2582  // when no higher priority exists, let the forward direction be
2583  // the main direction
2584  if (mainDirections.empty()) {
2585  assert(dist < (int)priorities->size());
2586  (*priorities)[dist] *= 2;
2587 #ifdef DEBUG_CONNECTION_GUESSING
2588  if (DEBUGCOND) {
2589  std::cout << " priorities3=" << toString(*priorities) << "\n";
2590  }
2591 #endif
2592  }
2594  (*priorities)[dist] += 1;
2595  } else {
2596  // try to ensure separation of left turns
2597  if (mainDirections.includes(MainDirections::DIR_RIGHTMOST) && mainDirections.includes(MainDirections::DIR_LEFTMOST)) {
2598  (*priorities)[0] /= 4;
2599  (*priorities)[(int)priorities->size() - 1] /= 2;
2600 #ifdef DEBUG_CONNECTION_GUESSING
2601  if (DEBUGCOND) {
2602  std::cout << " priorities6=" << toString(*priorities) << "\n";
2603  }
2604 #endif
2605  }
2606  }
2607  if (mainDirections.includes(MainDirections::DIR_FORWARD)) {
2608  if (myLanes.size() > 2) {
2609  (*priorities)[dist] *= 2;
2610 #ifdef DEBUG_CONNECTION_GUESSING
2611  if (DEBUGCOND) {
2612  std::cout << " priorities4=" << toString(*priorities) << "\n";
2613  }
2614 #endif
2615  } else {
2616  (*priorities)[dist] *= 3;
2617 #ifdef DEBUG_CONNECTION_GUESSING
2618  if (DEBUGCOND) {
2619  std::cout << " priorities5=" << toString(*priorities) << "\n";
2620  }
2621 #endif
2622  }
2623  }
2624  // return
2625  return priorities;
2626 }
2627 
2628 
2629 int
2630 NBEdge::computePrioritySum(const std::vector<int>& priorities) {
2631  int sum = 0;
2632  for (std::vector<int>::const_iterator i = priorities.begin(); i != priorities.end(); i++) {
2633  sum += *i;
2634  }
2635  return sum;
2636 }
2637 
2638 
2639 void
2640 NBEdge::appendTurnaround(bool noTLSControlled, bool onlyDeadends, bool checkPermissions) {
2641  // do nothing if no turnaround is known
2642  if (myTurnDestination == nullptr || myTo->getType() == NODETYPE_RAIL_CROSSING) {
2643  return;
2644  }
2645  // do nothing if the destination node is controlled by a tls and no turnarounds
2646  // shall be appended for such junctions
2647  if (noTLSControlled && myTo->isTLControlled()) {
2648  return;
2649  }
2650  if (onlyDeadends && myTo->getOutgoingEdges().size() > 1) {
2651  return;
2652  }
2653  const int fromLane = (int)myLanes.size() - 1;
2654  const int toLane = (int)myTurnDestination->getNumLanes() - 1;
2655  if (checkPermissions) {
2656  if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == 0) {
2657  // exclude connection if fromLane and toEdge have no common permissions
2658  return;
2659  }
2660  if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == SVC_PEDESTRIAN) {
2661  // exclude connection if the only commonly permitted class are pedestrians
2662  // these connections are later built in NBNode::buildWalkingAreas
2663  return;
2664  }
2665  }
2666  // avoid railway turn-arounds
2669  // except at dead-ends on bidi-edges where they model a reversal in train direction
2670  // @todo #4382: once the network fringe is tagged, it also should not receive turn-arounds)
2671  if (isBidiRail() && isRailDeadEnd()) {
2672  // add a slow connection because direction-reversal implies stopping
2674  return;
2675  } else {
2676  return;
2677  }
2678  };
2679  setConnection(fromLane, myTurnDestination, toLane, L2L_VALIDATED);
2680 }
2681 
2682 
2683 bool
2684 NBEdge::isTurningDirectionAt(const NBEdge* const edge) const {
2685  // maybe it was already set as the turning direction
2686  if (edge == myTurnDestination) {
2687  return true;
2688  } else if (myTurnDestination != nullptr) {
2689  // otherwise - it's not if a turning direction exists
2690  return false;
2691  }
2692  return edge == myPossibleTurnDestination;
2693 }
2694 
2695 
2696 NBNode*
2697 NBEdge::tryGetNodeAtPosition(double pos, double tolerance) const {
2698  // return the from-node when the position is at the begin of the edge
2699  if (pos < tolerance) {
2700  return myFrom;
2701  }
2702  // return the to-node when the position is at the end of the edge
2703  if (pos > myLength - tolerance) {
2704  return myTo;
2705  }
2706  return nullptr;
2707 }
2708 
2709 
2710 void
2712  int lanes = e->getNumLanes();
2713  for (int i = 0; i < lanes; i++) {
2714  std::vector<NBEdge::Connection> elv = e->getConnectionsFromLane(i);
2715  for (std::vector<NBEdge::Connection>::iterator j = elv.begin(); j != elv.end(); j++) {
2716  NBEdge::Connection el = *j;
2717  assert(el.tlID == "");
2718  addLane2LaneConnection(i + laneOff, el.toEdge, el.toLane, L2L_COMPUTED);
2719  }
2720  }
2721 }
2722 
2723 
2724 bool
2727 }
2728 
2729 
2730 double
2732  return (double) SUMO_const_laneWidthAndOffset * myLanes.size();
2733 }
2734 
2735 
2736 bool
2737 NBEdge::mayBeTLSControlled(int fromLane, NBEdge* toEdge, int toLane) const {
2739  tpl.fromLane = fromLane;
2740  tpl.to = toEdge;
2741  tpl.toLane = toLane;
2742  std::vector<TLSDisabledConnection>::const_iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
2743  return i == myTLSDisabledConnections.end();
2744 }
2745 
2746 
2747 bool
2748 NBEdge::setControllingTLInformation(const NBConnection& c, const std::string& tlID) {
2749  const int fromLane = c.getFromLane();
2750  NBEdge* toEdge = c.getTo();
2751  const int toLane = c.getToLane();
2752  const int tlIndex = c.getTLIndex();
2753  // check whether the connection was not set as not to be controled previously
2755  tpl.fromLane = fromLane;
2756  tpl.to = toEdge;
2757  tpl.toLane = toLane;
2758  std::vector<TLSDisabledConnection>::iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
2759  if (i != myTLSDisabledConnections.end()) {
2760  return false;
2761  }
2762 
2763  assert(fromLane < 0 || fromLane < (int) myLanes.size());
2764  // try to use information about the connections if given
2765  if (fromLane >= 0 && toLane >= 0) {
2766  // find the specified connection
2767  std::vector<Connection>::iterator i =
2768  find_if(myConnections.begin(), myConnections.end(), connections_finder(fromLane, toEdge, toLane));
2769  // ok, we have to test this as on the removal of self-loop edges some connections
2770  // will be reassigned
2771  if (i != myConnections.end()) {
2772  // get the connection
2773  Connection& connection = *i;
2774  // set the information about the tl
2775  connection.tlID = tlID;
2776  connection.tlLinkIndex = tlIndex;
2777  return true;
2778  }
2779  }
2780  // if the original connection was not found, set the information for all
2781  // connections
2782  int no = 0;
2783  bool hadError = false;
2784  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
2785  if ((*i).toEdge != toEdge) {
2786  continue;
2787  }
2788  if (fromLane >= 0 && fromLane != (*i).fromLane) {
2789  continue;
2790  }
2791  if (toLane >= 0 && toLane != (*i).toLane) {
2792  continue;
2793  }
2794  if ((*i).tlID == "") {
2795  (*i).tlID = tlID;
2796  (*i).tlLinkIndex = tlIndex;
2797  no++;
2798  } else {
2799  if ((*i).tlID != tlID && (*i).tlLinkIndex == tlIndex) {
2800  WRITE_WARNING("The lane '" + toString<int>((*i).fromLane) + "' on edge '" + getID() + "' already had a traffic light signal.");
2801  hadError = true;
2802  }
2803  }
2804  }
2805  if (hadError && no == 0) {
2806  WRITE_WARNING("Could not set any signal of the tlLogic '" + tlID + "' (unknown group)");
2807  }
2808  return true;
2809 }
2810 
2811 
2812 void
2814  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); it++) {
2815  it->tlID = "";
2816  }
2817 }
2818 
2819 
2820 void
2821 NBEdge::disableConnection4TLS(int fromLane, NBEdge* toEdge, int toLane) {
2823  c.fromLane = fromLane;
2824  c.to = toEdge;
2825  c.toLane = toLane;
2826  myTLSDisabledConnections.push_back(c);
2827 }
2828 
2829 
2832  PositionVector ret;
2833  double width;
2834  int lane;
2835  if (myFrom == (&n)) {
2836  // outgoing
2838  ret = myLanes[lane].shape;
2839  } else {
2840  // incoming
2842  ret = myLanes[lane].shape.reverse();
2843  }
2844  width = getLaneWidth(lane);
2845  ret.move2side(width * 0.5);
2846  return ret;
2847 }
2848 
2849 
2852  PositionVector ret;
2853  double width;
2854  int lane;
2855  if (myFrom == (&n)) {
2856  // outgoing
2858  ret = myLanes[lane].shape;
2859  } else {
2860  // incoming
2862  ret = myLanes[lane].shape.reverse();
2863  }
2864  width = getLaneWidth(lane);
2865  ret.move2side(-width * 0.5);
2866  return ret;
2867 }
2868 
2869 
2870 bool
2871 NBEdge::expandableBy(NBEdge* possContinuation, std::string& reason) const {
2872  // ok, the number of lanes must match
2873  if (myLanes.size() != possContinuation->myLanes.size()) {
2874  reason = "laneNumber";
2875  return false;
2876  }
2877  // the priority, too (?)
2878  if (getPriority() != possContinuation->getPriority()) {
2879  reason = "priority";
2880  return false;
2881  }
2882  // the speed allowed
2883  if (mySpeed != possContinuation->mySpeed) {
2884  reason = "speed";
2885  return false;
2886  }
2887  // spreadtype should match or it will look ugly
2888  if (myLaneSpreadFunction != possContinuation->myLaneSpreadFunction) {
2889  reason = "spreadType";
2890  return false;
2891  }
2892  // do not create self loops
2893  if (myFrom == possContinuation->myTo) {
2894  reason = "loop";
2895  return false;
2896  }
2897  // matching lanes must have identical properties
2898  for (int i = 0; i < (int)myLanes.size(); i++) {
2899  if (myLanes[i].speed != possContinuation->myLanes[i].speed) {
2900  reason = "lane " + toString(i) + " speed";
2901  return false;
2902  } else if (myLanes[i].permissions != possContinuation->myLanes[i].permissions) {
2903  reason = "lane " + toString(i) + " permissions";
2904  return false;
2905  } else if (myLanes[i].width != possContinuation->myLanes[i].width) {
2906  reason = "lane " + toString(i) + " width";
2907  return false;
2908  }
2909  }
2910  // conserve bidi-rails
2911  if (isBidiRail() != possContinuation->isBidiRail()) {
2912  reason = "bidi-rail";
2913  return false;
2914  }
2915 
2916  // the vehicle class constraints, too
2924  // also, check whether the connections - if any exit do allow to join
2925  // both edges
2926  // This edge must have a one-to-one connection to the following lanes
2927  switch (myStep) {
2929  break;
2930  case INIT:
2931  break;
2932  case EDGE2EDGES: {
2933  // the following edge must be connected
2934  const EdgeVector& conn = getConnectedEdges();
2935  if (find(conn.begin(), conn.end(), possContinuation) == conn.end()) {
2936  reason = "disconnected";
2937  return false;
2938  }
2939  }
2940  break;
2941  case LANES2EDGES:
2942  case LANES2LANES_RECHECK:
2943  case LANES2LANES_DONE:
2944  case LANES2LANES_USER: {
2945  // the possible continuation must be connected
2946  if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(possContinuation)) == myConnections.end()) {
2947  reason = "disconnected";
2948  return false;
2949  }
2950  // all lanes must go to the possible continuation
2951  std::vector<int> conns = getConnectionLanes(possContinuation);
2952  const int offset = MAX2(0, getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true));
2953  if (conns.size() != myLanes.size() - offset) {
2954  reason = "some lanes disconnected";
2955  return false;
2956  }
2957  }
2958  break;
2959  default:
2960  break;
2961  }
2962  return true;
2963 }
2964 
2965 
2966 void
2968  // append geometry
2969  myGeom.append(e->myGeom);
2970  for (int i = 0; i < (int)myLanes.size(); i++) {
2971  myLanes[i].shape.append(e->myLanes[i].shape);
2972  if (myLanes[i].knowsParameter(SUMO_PARAM_ORIGID) || e->myLanes[i].knowsParameter(SUMO_PARAM_ORIGID)
2973  || OptionsCont::getOptions().getBool("output.original-names")) {
2974  const std::string origID = myLanes[i].getParameter(SUMO_PARAM_ORIGID, getID());
2975  const std::string origID2 = e->myLanes[i].getParameter(SUMO_PARAM_ORIGID, e->getID());
2976  if (origID != origID2) {
2977  myLanes[i].setParameter(SUMO_PARAM_ORIGID, origID + " " + origID2);
2978  }
2979  }
2980  myLanes[i].connectionsDone = e->myLanes[i].connectionsDone;
2981  }
2982  // recompute length
2983  myLength += e->myLength;
2984  // copy the connections and the building step if given
2985  myStep = e->myStep;
2989  // set the node
2990  myTo = e->myTo;
2991  myToBorder = e->myToBorder;
2994  } else {
2995  mySignalOffset += e->getLength();
2996  }
2997  computeAngle(); // myEndAngle may be different now
2998 }
2999 
3000 
3001 bool
3003  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
3004  if ((*i).toEdge == e && (*i).tlID != "") {
3005  return true;
3006  }
3007  }
3008  return false;
3009 }
3010 
3011 
3012 NBEdge*
3013 NBEdge::getTurnDestination(bool possibleDestination) const {
3014  if (myTurnDestination == nullptr && possibleDestination) {
3016  }
3017  return myTurnDestination;
3018 }
3019 
3020 
3021 std::string
3022 NBEdge::getLaneID(int lane) const {
3023  return myID + "_" + toString(lane);
3024 }
3025 
3026 
3027 std::string
3028 NBEdge::getLaneIDInsecure(int lane) const {
3029  return myID + "_" + toString(lane);
3030 }
3031 
3032 
3033 bool
3034 NBEdge::isNearEnough2BeJoined2(NBEdge* e, double threshold) const {
3035  std::vector<double> distances = myGeom.distances(e->getGeometry());
3036  assert(distances.size() > 0);
3037  return VectorHelper<double>::maxValue(distances) < threshold;
3038 }
3039 
3040 
3041 void
3042 NBEdge::addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices) {
3043  assert(index <= (int)myLanes.size());
3044  myLanes.insert(myLanes.begin() + index, Lane(this, ""));
3045  // copy attributes
3046  if (myLanes.size() > 1) {
3047  int templateIndex = index > 0 ? index - 1 : index + 1;
3048  myLanes[index].speed = myLanes[templateIndex].speed;
3049  myLanes[index].permissions = myLanes[templateIndex].permissions;
3050  myLanes[index].preferred = myLanes[templateIndex].preferred;
3051  myLanes[index].endOffset = myLanes[templateIndex].endOffset;
3052  myLanes[index].width = myLanes[templateIndex].width;
3053  myLanes[index].updateParameter(myLanes[templateIndex].getParametersMap());
3054  }
3055  const EdgeVector& incs = myFrom->getIncomingEdges();
3056  if (recomputeShape) {
3058  }
3059  if (recomputeConnections) {
3060  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
3061  (*i)->invalidateConnections(true);
3062  }
3063  invalidateConnections(true);
3064  } else if (shiftIndices) {
3065  // shift outgoing connections above the added lane to the left
3066  for (Connection& c : myConnections) {
3067  if (c.fromLane >= index) {
3068  c.fromLane += 1;
3069  }
3070  }
3071  // shift incoming connections above the added lane to the left
3072  for (NBEdge* inc : myFrom->getIncomingEdges()) {
3073  for (Connection& c : inc->myConnections) {
3074  if (c.toEdge == this && c.toLane >= index) {
3075  c.toLane += 1;
3076  }
3077  }
3078  }
3079  myFrom->shiftTLConnectionLaneIndex(this, +1, index - 1);
3080  myTo->shiftTLConnectionLaneIndex(this, +1, index - 1);
3081  }
3082 }
3083 
3084 void
3086  int newLaneNo = (int)myLanes.size() + by;
3087  while ((int)myLanes.size() < newLaneNo) {
3088  // recompute shapes on last addition
3089  const bool recompute = ((int)myLanes.size() == newLaneNo - 1) && myStep < LANES2LANES_USER;
3090  addLane((int)myLanes.size(), recompute, recompute, false);
3091  }
3092 }
3093 
3094 
3095 void
3096 NBEdge::deleteLane(int index, bool recompute, bool shiftIndices) {
3097  assert(index < (int)myLanes.size());
3098  myLanes.erase(myLanes.begin() + index);
3099  if (recompute) {
3101  const EdgeVector& incs = myFrom->getIncomingEdges();
3102  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
3103  (*i)->invalidateConnections(true);
3104  }
3105  invalidateConnections(true);
3106  } else if (shiftIndices) {
3107  removeFromConnections(nullptr, index, -1, false, true);
3108  for (NBEdge* inc : myFrom->getIncomingEdges()) {
3109  inc->removeFromConnections(this, -1, index, false, true);
3110  }
3111  }
3112 }
3113 
3114 
3115 void
3117  int newLaneNo = (int) myLanes.size() - by;
3118  assert(newLaneNo > 0);
3119  while ((int)myLanes.size() > newLaneNo) {
3120  // recompute shapes on last removal
3121  const bool recompute = (int)myLanes.size() == newLaneNo + 1 && myStep < LANES2LANES_USER;
3122  deleteLane((int)myLanes.size() - 1, recompute, false);
3123  }
3124 }
3125 
3126 
3127 void
3129  assert(myTo->getOutgoingEdges().size() == 0);
3131 }
3132 
3133 
3134 void
3136  if (lane < 0) { // all lanes are meant...
3137  for (int i = 0; i < (int)myLanes.size(); i++) {
3138  allowVehicleClass(i, vclass);
3139  }
3140  } else {
3141  assert(lane < (int)myLanes.size());
3142  myLanes[lane].permissions |= vclass;
3143  }
3144 }
3145 
3146 
3147 void
3149  if (lane < 0) { // all lanes are meant...
3150  for (int i = 0; i < (int)myLanes.size(); i++) {
3151  disallowVehicleClass((int) i, vclass);
3152  }
3153  } else {
3154  assert(lane < (int)myLanes.size());
3155  myLanes[lane].permissions &= ~vclass;
3156  }
3157 }
3158 
3159 
3160 void
3162  if (lane < 0) { // all lanes are meant...
3163  for (int i = 0; i < (int)myLanes.size(); i++) {
3164  allowVehicleClass(i, vclass);
3165  }
3166  } else {
3167  assert(lane < (int)myLanes.size());
3168  myLanes[lane].preferred |= vclass;
3169  }
3170 }
3171 
3172 
3173 void
3174 NBEdge::setLaneWidth(int lane, double width) {
3175  if (lane < 0) {
3176  // all lanes are meant...
3177  myLaneWidth = width;
3178  for (int i = 0; i < (int)myLanes.size(); i++) {
3179  // ... do it for each lane
3180  setLaneWidth(i, width);
3181  }
3182  return;
3183  }
3184  assert(lane < (int)myLanes.size());
3185  myLanes[lane].width = width;
3186 }
3187 
3188 
3189 double
3190 NBEdge::getLaneWidth(int lane) const {
3191  return myLanes[lane].width != UNSPECIFIED_WIDTH
3192  ? myLanes[lane].width
3194 }
3195 
3196 
3197 double
3199  double result = 0;
3200  for (int i = 0; i < (int)myLanes.size(); i++) {
3201  result += getLaneWidth(i);
3202  }
3203  return result;
3204 }
3205 
3206 double
3207 NBEdge::getEndOffset(int lane) const {
3208  return myLanes[lane].endOffset != UNSPECIFIED_OFFSET ? myLanes[lane].endOffset : getEndOffset();
3209 }
3210 
3211 
3212 const std::map<SVCPermissions, double>&
3213 NBEdge::getStopOffsets(int lane) const {
3214  if (lane == -1) {
3215  return myStopOffsets;
3216  } else {
3217  return myLanes[lane].stopOffsets;
3218  }
3219 }
3220 
3221 void
3222 NBEdge::setEndOffset(int lane, double offset) {
3223  if (lane < 0) {
3224  // all lanes are meant...
3225  myEndOffset = offset;
3226  for (int i = 0; i < (int)myLanes.size(); i++) {
3227  // ... do it for each lane
3228  setEndOffset(i, offset);
3229  }
3230  return;
3231  }
3232  assert(lane < (int)myLanes.size());
3233  myLanes[lane].endOffset = offset;
3234 }
3235 
3236 
3237 bool
3238 NBEdge::setStopOffsets(int lane, std::map<int, double> offsets, bool overwrite) {
3239  if (lane < 0) {
3240  if (!overwrite && myStopOffsets.size() != 0) {
3241  return false;
3242  }
3243  // all lanes are meant...
3244  if (offsets.size() != 0 && 0 > offsets.begin()->second) {
3245  // Edge length unknown at parsing time, thus check here.
3246  std::stringstream ss;
3247  ss << "Ignoring invalid stopOffset for edge " << getID() << " (negative offset).";
3248  WRITE_WARNING(ss.str());
3249  return false;
3250  } else {
3251  myStopOffsets = offsets;
3252  }
3253  } else {
3254  assert(lane < (int)myLanes.size());
3255  if (myLanes[lane].stopOffsets.size() == 0 || overwrite) {
3256  if (offsets.size() != 0 && 0 > offsets.begin()->second) {
3257  // Edge length unknown at parsing time, thus check here.
3258  std::stringstream ss;
3259  ss << "Ignoring invalid stopOffset for lane " << lane << " on edge " << getID() << " (negative offset).";
3260  WRITE_WARNING(ss.str());
3261  return false;
3262  } else {
3263  myLanes[lane].stopOffsets = offsets;
3264  }
3265  }
3266  }
3267  return true;
3268 }
3269 
3270 
3271 void
3272 NBEdge::setSpeed(int lane, double speed) {
3273  if (lane < 0) {
3274  // all lanes are meant...
3275  mySpeed = speed;
3276  for (int i = 0; i < (int)myLanes.size(); i++) {
3277  // ... do it for each lane
3278  setSpeed(i, speed);
3279  }
3280  return;
3281  }
3282  assert(lane < (int)myLanes.size());
3283  myLanes[lane].speed = speed;
3284 }
3285 
3286 void
3287 NBEdge::setAcceleration(int lane, bool accelRamp) {
3288  assert(lane >= 0);
3289  assert(lane < (int)myLanes.size());
3290  myLanes[lane].accelRamp = accelRamp;
3291 }
3292 
3293 
3294 void
3295 NBEdge::setLaneShape(int lane, const PositionVector& shape) {
3296  assert(lane >= 0);
3297  assert(lane < (int)myLanes.size());
3298  myLanes[lane].customShape = shape;
3299 }
3300 
3301 
3302 void
3303 NBEdge::setPermissions(SVCPermissions permissions, int lane) {
3304  if (lane < 0) {
3305  for (int i = 0; i < (int)myLanes.size(); i++) {
3306  // ... do it for each lane
3307  setPermissions(permissions, i);
3308  }
3309  } else {
3310  assert(lane < (int)myLanes.size());
3311  myLanes[lane].permissions = permissions;
3312  }
3313 }
3314 
3315 
3316 void
3318  if (lane < 0) {
3319  for (int i = 0; i < (int)myLanes.size(); i++) {
3320  // ... do it for each lane
3321  setPreferredVehicleClass(permissions, i);
3322  }
3323  } else {
3324  assert(lane < (int)myLanes.size());
3325  myLanes[lane].preferred = permissions;
3326  }
3327 }
3328 
3329 
3331 NBEdge::getPermissions(int lane) const {
3332  if (lane < 0) {
3333  SVCPermissions result = 0;
3334  for (int i = 0; i < (int)myLanes.size(); i++) {
3335  result |= getPermissions(i);
3336  }
3337  return result;
3338  } else {
3339  assert(lane < (int)myLanes.size());
3340  return myLanes[lane].permissions;
3341  }
3342 }
3343 
3344 
3345 void
3347  myLoadedLength = val;
3348 }
3349 
3350 
3351 void
3353  for (std::vector<Lane>::iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
3354  (*i).permissions = SVCAll;
3355  (*i).preferred = 0;
3356  }
3357 }
3358 
3359 
3360 bool
3362  if (c1.fromLane != c2.fromLane) {
3363  return c1.fromLane < c2.fromLane;
3364  }
3365  if (c1.toEdge != c2.toEdge) {
3366  return false; // do not change ordering among toEdges as this is determined by angle in an earlier step
3367  }
3368  return c1.toLane < c2.toLane;
3369 }
3370 
3371 
3372 int
3373 NBEdge::getFirstNonPedestrianLaneIndex(int direction, bool exclusive) const {
3374  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
3375  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
3376  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
3377  for (int i = start; i != end; i += direction) {
3378  // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
3379  // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
3380  if ((exclusive && myLanes[i].permissions != SVC_PEDESTRIAN && myLanes[i].permissions != 0)
3381  || (myLanes[i].permissions == SVCAll || ((myLanes[i].permissions & SVC_PEDESTRIAN) == 0 && myLanes[i].permissions != 0))) {
3382  return i;
3383  }
3384  }
3385  return -1;
3386 }
3387 
3388 
3389 int
3390 NBEdge::getFirstAllowedLaneIndex(int direction) const {
3391  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
3392  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
3393  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
3394  for (int i = start; i != end; i += direction) {
3395  if (myLanes[i].permissions != 0) {
3396  return i;
3397  }
3398  }
3399  return end - direction;
3400 }
3401 
3402 
3403 std::set<SVCPermissions>
3404 NBEdge::getPermissionVariants(int iStart, int iEnd) const {
3405  std::set<SVCPermissions> result;
3406  if (iStart < 0 || iStart >= getNumLanes() || iEnd > getNumLanes()) {
3407  throw ProcessError("invalid indices iStart " + toString(iStart) + " iEnd " + toString(iEnd) + " for edge with " + toString(getNumLanes()) + " lanes.");
3408  }
3409  for (int i = iStart; i < iEnd; ++i) {
3410  result.insert(getPermissions(i));
3411  }
3412  return result;
3413 }
3414 
3415 
3416 double
3418  double angle = getAngleAtNode(node) + (getFromNode() == node ? 180.0 : 0.0);
3419  if (angle < 0) {
3420  angle += 360.0;
3421  }
3422  if (angle >= 360) {
3423  angle -= 360.0;
3424  }
3425  if (gDebugFlag1) {
3426  std::cout << getID() << " angle=" << getAngleAtNode(node) << " convAngle=" << angle << "\n";
3427  }
3428  return angle;
3429 }
3430 
3431 
3434  int index = getFirstNonPedestrianLaneIndex(direction);
3435  if (index < 0) {
3436  throw ProcessError("Edge " + getID() + " allows pedestrians on all lanes");
3437  }
3438  return myLanes[index];
3439 }
3440 
3441 std::string
3443  // see IntermodalEdge::getSidewalk()
3444  for (int i = 0; i < (int)myLanes.size(); i++) {
3445  if (myLanes[i].permissions == SVC_PEDESTRIAN) {
3446  return getLaneID(i);
3447  }
3448  }
3449  for (int i = 0; i < (int)myLanes.size(); i++) {
3450  if ((myLanes[i].permissions & SVC_PEDESTRIAN) != 0) {
3451  return getLaneID(i);
3452  }
3453  }
3454  return getLaneID(0);
3455 }
3456 
3457 void
3458 NBEdge::addSidewalk(double width) {
3460 }
3461 
3462 
3463 void
3464 NBEdge::restoreSidewalk(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
3465  restoreRestrictedLane(SVC_PEDESTRIAN, oldLanes, oldGeometry, oldConnections);
3466 }
3467 
3468 
3469 void
3470 NBEdge::addBikeLane(double width) {
3472 }
3473 
3474 
3475 void
3476 NBEdge::restoreBikelane(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
3477  restoreRestrictedLane(SVC_BICYCLE, oldLanes, oldGeometry, oldConnections);
3478 }
3479 
3480 
3481 void
3483  if (myLanes[0].permissions == vclass) {
3484  WRITE_WARNING("Edge '" + getID() + "' already has a dedicated lane for " + toString(vclass) + "s. Not adding another one.");
3485  return;
3486  }
3488  myGeom.move2side(width / 2);
3489  }
3490  // disallow pedestrians on all lanes to ensure that sidewalks are used and
3491  // crossings can be guessed
3492  disallowVehicleClass(-1, vclass);
3493  // add new lane
3494  myLanes.insert(myLanes.begin(), Lane(this, myLanes[0].getParameter(SUMO_PARAM_ORIGID)));
3495  myLanes[0].permissions = vclass;
3496  myLanes[0].width = width;
3497  // shift outgoing connections to the left
3498  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
3499  Connection& c = *it;
3500  if (c.fromLane >= 0) {
3501  c.fromLane += 1;
3502  }
3503  }
3504  // shift incoming connections to the left
3505  const EdgeVector& incoming = myFrom->getIncomingEdges();
3506  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
3507  (*it)->shiftToLanesToEdge(this, 1);
3508  }
3510  myTo->shiftTLConnectionLaneIndex(this, 1);
3512 }
3513 
3514 
3515 void
3516 NBEdge::restoreRestrictedLane(SUMOVehicleClass vclass, std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
3517  // check that previously lane was transformed
3518  if (myLanes[0].permissions != vclass) {
3519  WRITE_WARNING("Edge '" + getID() + "' don't have a dedicated lane for " + toString(vclass) + "s. Cannot be restored");
3520  return;
3521  }
3522  // restore old values
3523  myGeom = oldGeometry;
3524  myLanes = oldLanes;
3525  myConnections = oldConnections;
3526  // shift incoming connections to the right
3527  const EdgeVector& incoming = myFrom->getIncomingEdges();
3528  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
3529  (*it)->shiftToLanesToEdge(this, 0);
3530  }
3531  // Shift TL conections
3533  myTo->shiftTLConnectionLaneIndex(this, 0);
3535 }
3536 
3537 
3538 void
3541  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
3542  if ((*it).toEdge == to && (*it).toLane >= 0) {
3543  (*it).toLane += laneOff;
3544  }
3545  }
3546 }
3547 
3548 
3549 void
3552  const int i = (node == myTo ? -1 : 0);
3553  const int i2 = (node == myTo ? 0 : -1);
3554  const double dist = myGeom[i].distanceTo2D(node->getPosition());
3555  const double neededOffset = (getTotalWidth() + getNumLanes() * SUMO_const_laneOffset) / 2;
3556  const double dist2 = MIN2(myGeom.distance2D(other->getGeometry()[i2]),
3557  other->getGeometry().distance2D(myGeom[i]));
3558  const double neededOffset2 = neededOffset + (other->getTotalWidth() + other->getNumLanes() * SUMO_const_laneOffset) / 2;
3559  if (dist < neededOffset && dist2 < neededOffset2) {
3560  PositionVector tmp = myGeom;
3561  // @note this doesn't work well for vissim networks
3562  //tmp.move2side(MIN2(neededOffset - dist, neededOffset2 - dist2));
3563  try {
3564  tmp.move2side(neededOffset - dist);
3565  myGeom[i] = tmp[i];
3566  } catch (InvalidArgument&) {
3567  WRITE_WARNING("Could not avoid overlapping shape at node '" + node->getID() + "' for edge '" + getID() + "'");
3568  }
3569  }
3570  }
3571 }
3572 
3573 
3574 double
3576  double result = getLoadedLength();
3577  if (OptionsCont::getOptions().getBool("no-internal-links") && !hasLoadedLength()) {
3578  // use length to junction center even if a modified geometry was given
3580  geom.push_back_noDoublePos(getToNode()->getCenter());
3581  geom.push_front_noDoublePos(getFromNode()->getCenter());
3582  result = geom.length();
3583  }
3584  return MAX2(result, POSITION_EPS);
3585 }
3586 
3587 void
3588 NBEdge::setOrigID(const std::string origID) {
3589  if (origID != "") {
3590  for (int i = 0; i < (int)myLanes.size(); i++) {
3591  myLanes[i].setParameter(SUMO_PARAM_ORIGID, origID);
3592  }
3593  } else {
3594  // do not record empty origID parameter
3595  for (int i = 0; i < (int)myLanes.size(); i++) {
3596  myLanes[i].unsetParameter(SUMO_PARAM_ORIGID);
3597  }
3598  }
3599 }
3600 
3601 
3602 const EdgeVector&
3604  // @todo cache successors instead of recomputing them every time
3605  mySuccessors.clear();
3606  //std::cout << "getSuccessors edge=" << getID() << " svc=" << toString(vClass) << " cons=" << myConnections.size() << "\n";
3607  for (const Connection& con : myConnections) {
3608  if (con.fromLane >= 0 && con.toLane >= 0 && con.toEdge != nullptr &&
3609  (getPermissions(con.fromLane)
3610  & con.toEdge->getPermissions(con.toLane) & vClass) != 0
3611  && find(mySuccessors.begin(), mySuccessors.end(), con.toEdge) == mySuccessors.end()) {
3612  mySuccessors.push_back(con.toEdge);
3613  //std::cout << " succ=" << con.toEdge->getID() << "\n";
3614  }
3615  }
3616  return mySuccessors;
3617 }
3618 
3619 
3620 const NBConstEdgePairVector&
3622  // @todo cache successors instead of recomputing them every time
3623  myViaSuccessors.clear();
3624  for (const Connection& con : myConnections) {
3625  std::pair<const NBEdge*, const NBEdge*> pair(con.toEdge, nullptr);
3626  if (con.fromLane >= 0 && con.toLane >= 0 && con.toEdge != nullptr &&
3627  (getPermissions(con.fromLane)
3628  & con.toEdge->getPermissions(con.toLane) & vClass) != 0
3629  && find(myViaSuccessors.begin(), myViaSuccessors.end(), pair) == myViaSuccessors.end()) {
3630  myViaSuccessors.push_back(pair);
3631  }
3632  }
3633  return myViaSuccessors;
3634 }
3635 
3636 
3637 void
3638 NBEdge::debugPrintConnections(bool outgoing, bool incoming) const {
3639  if (outgoing) {
3640  for (const Connection& c : myConnections) {
3641  std::cout << " " << getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
3642  }
3643  }
3644  if (incoming) {
3645  for (NBEdge* inc : myFrom->getIncomingEdges()) {
3646  for (Connection& c : inc->myConnections) {
3647  if (c.toEdge == this) {
3648  std::cout << " " << inc->getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
3649  }
3650  }
3651  }
3652  }
3653 }
3654 
3655 
3656 int
3657 NBEdge::getLaneIndexFromLaneID(const std::string laneID) {
3658  return StringUtils::toInt(laneID.substr(laneID.rfind("_") + 1));
3659 }
3660 
3661 /****************************************************************************/
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:2737
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge&#39;s lanes&#39; lateral offset is computed.
Definition: NBEdge.h:704
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:32
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point...
std::string id
id of Connection
Definition: NBEdge.h:215
void moveConnectionToRight(int lane)
Definition: NBEdge.cpp:1466
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1348
bool bothLeftIntersect(const NBNode &n, const PositionVector &shape, LinkDirection dir, NBEdge *otherFrom, const NBEdge::Connection &otherCon, int numPoints, double width2) const
determine conflict between opposite left turns
Definition: NBEdge.cpp:1758
bool expandableBy(NBEdge *possContinuation, std::string &reason) const
Check if Node is expandable.
Definition: NBEdge.cpp:2871
void init(int noLanes, bool tryIgnoreNodePositions, const std::string &origID)
Initialization routines common to all constructors.
Definition: NBEdge.cpp:425
The link is a partial left direction.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:108
void appendTurnaround(bool noTLSControlled, bool onlyDeadends, bool checkPermissions)
Add a connection to the previously computed turnaround, if wished.
Definition: NBEdge.cpp:2640
static const bool UNSPECIFIED_CONNECTION_UNCONTROLLED
TLS-controlled despite its node controlled not specified.
Definition: NBEdge.h:285
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1513
double vmax
maximum velocity
Definition: NBEdge.h:221
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:488
double getAngleAtNodeToCenter(const NBNode *const node) const
Returns the angle of from the node shape center to where the edge meets the node shape.
Definition: NBEdge.cpp:1813
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:2748
double length2D() const
Returns the length.
void divideOnEdges(const EdgeVector *outgoing)
divides the lanes on the outgoing edges
Definition: NBEdge.cpp:2264
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:160
int getFirstAllowedLaneIndex(int direction) const
return the first lane that permits at least 1 vClass or the last lane if search direction of there is...
Definition: NBEdge.cpp:3390
int toLane
The lane the connections yields in.
Definition: NBEdge.h:188
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
Definition: NBNode.cpp:1676
void debugPrintConnections(bool outgoing=true, bool incoming=false) const
debugging helper to print all connections
Definition: NBEdge.cpp:3638
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
static const double UNSPECIFIED_LOADED_LENGTH
no length override given
Definition: NBEdge.h:273
is a pedestrian
std::vector< TLSDisabledConnection > myTLSDisabledConnections
vector with the disabled connections
Definition: NBEdge.h:1532
const std::map< int, double > & getStopOffsets() const
Returns the stopOffset to the end of the edge.
Definition: NBEdge.h:562
~NBEdge()
Destructor.
Definition: NBEdge.cpp:496
void append(const PositionVector &v, double sameThreshold=2.0)
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0) const
return orthogonal through p (extending this vector if necessary)
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1496
double z() const
Returns the z-position.
Definition: Position.h:67
void sortOutgoingConnectionsByAngle()
sorts the outgoing connections by their angle relative to their junction
Definition: NBEdge.cpp:1253
std::string viaID
if Connection have a via, ID of it
Definition: NBEdge.h:227
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) ...
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:185
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1226
void mirrorX()
mirror coordinates along the x-axis
Definition: NBEdge.cpp:514
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
static PositionVector startShapeAt(const PositionVector &laneShape, const NBNode *startNode, PositionVector nodeShape)
Definition: NBEdge.cpp:801
static NBEdge DummyEdge
Dummy edge to use when a reference must be supplied in the no-arguments constructor (FOX technicality...
Definition: NBEdge.h:255
NBNode * myTo
Definition: NBEdge.h:1454
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
Definition: NBEdge.h:270
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3222
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1042
The relationships between edges are computed/loaded.
Definition: NBEdge.h:88
double getLaneSpeed(int lane) const
get lane speed
Definition: NBEdge.cpp:1837
void computeEdgeShape(double smoothElevationThreshold=-1)
Recomputeds the lane shapes to terminate at the node shape For every lane the intersection with the f...
Definition: NBEdge.cpp:760
bool hasPermissions() const
whether at least one lane has restrictions
Definition: NBEdge.cpp:1967
bool isConnectedTo(const NBEdge *e) const
Returns the information whethe a connection to the given edge has been added (or computed) ...
Definition: NBEdge.cpp:1164
void reduceGeometry(const double minDist)
Removes points with a distance lesser than the given.
Definition: NBEdge.cpp:922
bool hasSignalisedConnectionTo(const NBEdge *const e) const
Check if edge has signalised connections.
Definition: NBEdge.cpp:3002
std::vector< std::pair< const NBEdge *, const NBEdge * > > NBConstEdgePairVector
Definition: NBCont.h:43
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:60
double myLaneWidth
This width of this edge&#39;s lanes.
Definition: NBEdge.h:1508
std::map< int, double > myStopOffsets
A vClass specific stop offset - assumed of length 0 (unspecified) or 1. For the latter case the int i...
Definition: NBEdge.h:1505
double myEndOffset
This edges&#39;s offset to the intersection begin (will be applied to all lanes)
Definition: NBEdge.h:1499
void addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices)
add lane
Definition: NBEdge.cpp:3042
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3272
Holds (- relative to the edge it is build from -!!!) the list of main directions a vehicle that drive...
Definition: NBEdge.h:1344
PositionVector computeInternalLaneShape(NBEdge *fromE, const NBEdge::Connection &con, int numPoints, NBNode *recordError=0) const
Compute the shape for an internal lane.
Definition: NBNode.cpp:660
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.h:577
Some static methods for string processing.
Definition: StringUtils.h:40
static const double ANGLE_LOOKAHEAD
the distance at which to take the default angle
Definition: NBEdge.h:279
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1781
void moveConnectionToLeft(int lane)
Definition: NBEdge.cpp:1451
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.cpp:2291
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:427
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1460
const std::string & getTypeID() const
get ID of type
Definition: NBEdge.h:1004
vehicle is a bicycle
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.
const double SUMO_const_laneWidth
Definition: StdDefs.h:51
bool empty() const
returns the information whether no following street has a higher priority
Definition: NBEdge.cpp:230
void addIncomingEdge(NBEdge *edge)
adds an incoming edge
Definition: NBNode.cpp:427
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
The representation of a single edge during network building.
Definition: NBEdge.h:65
void reinitNodes(NBNode *from, NBNode *to)
Resets nodes but keeps all other values the same (used when joining)
Definition: NBEdge.cpp:399
void clearControllingTLInformation()
clears tlID for all connections
Definition: NBEdge.cpp:2813
vehicle is a small delivery vehicle
void setNodeBorder(const NBNode *node, const Position &p, const Position &p2, bool rectangularCut)
Set Node border.
Definition: NBEdge.cpp:610
Lane2LaneInfoType
Modes of setting connections between lanes.
Definition: NBEdge.h:103
std::vector< int > * prepareEdgePriorities(const EdgeVector *outgoing)
recomputes the edge priorities and manipulates them for a distribution of lanes on edges which is mor...
Definition: NBEdge.cpp:2540
Lane(NBEdge *e, const std::string &_origID)
constructor
Definition: NBEdge.cpp:128
const double SUMO_const_laneWidthAndOffset
Definition: StdDefs.h:55
The link is a 180 degree turn.
bool hasLaneSpecificSpeed() const
whether lanes differ in speed
Definition: NBEdge.cpp:1992
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:276
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:668
std::vector< Direction > myDirs
list of the main direction within the following junction relative to the edge
Definition: NBEdge.h:1350
void markAsInLane2LaneState()
mark edge as in lane to state lane
Definition: NBEdge.cpp:3128
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:261
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1281
double getMaxLaneOffset()
get max lane offset
Definition: NBEdge.cpp:2731
TLS Disabled Connections.
Definition: NBEdge.h:1525
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:254
Lanes to lanes - relationships are computed; should be recheked.
Definition: NBEdge.h:92
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
T MAX2(T a, T b)
Definition: StdDefs.h:76
bool hasLoadedLength() const
Returns whether a length was set explicitly.
Definition: NBEdge.h:507
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3013
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:3303
PositionVector shape
The crossing&#39;s shape.
Definition: NBNode.h:133
int myFromJunctionPriority
The priority normalised for the node the edge is outgoing of.
Definition: NBEdge.h:1487
void setLoadedLength(double val)
set loaded lenght
Definition: NBEdge.cpp:3346
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:71
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:589
void computeLaneShapes()
compute lane shapes
Definition: NBEdge.cpp:1843
bool mayDefinitelyPass
Information about being definitely free to drive (on-ramps)
Definition: NBEdge.h:197
PositionVector reverse() const
reverse position vector
double endOffset
This lane&#39;s offset to the intersection begin.
Definition: NBEdge.h:133
PositionVector myGeom
The geometry for the edge.
Definition: NBEdge.h:1493
double visibility
custom foe visiblity for connection
Definition: NBEdge.h:206
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
void remapConnections(const EdgeVector &incoming)
Remaps the connection in a way that allows the removal of it.
Definition: NBEdge.cpp:1265
const double SUMO_const_laneOffset
Definition: StdDefs.h:52
#define RAD2DEG(x)
Definition: GeomHelper.h:39
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const std::string & getID() const
Returns the id.
Definition: Named.h:78
void insert_noDoublePos(const std::vector< Position >::iterator &at, const Position &p)
insert in front a non double position
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVCAll
all VClasses are allowed
std::vector< int > getConnectionLanes(NBEdge *currentOutgoing) const
Returns the list of lanes that may be used to reach the given edge.
Definition: NBEdge.cpp:1239
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
PositionVector myFromBorder
intersection borders (because the node shape might be invalid)
Definition: NBEdge.h:1545
void restoreBikelane(std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore an previously added BikeLane
Definition: NBEdge.cpp:3476
bool isRailDeadEnd() const
whether this edge is a railway edge that does not continue
Definition: NBEdge.cpp:679
bool setStopOffsets(int lane, std::map< int, double > offsets, bool overwrite=false)
set lane and vehicle class specific stopOffset (negative lane implies set for all lanes) ...
Definition: NBEdge.cpp:3238
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:3458
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:437
bool hasElevation() const
return whether two positions differ in z-coordinate
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge&#39;s geometry
Definition: NBEdge.cpp:559
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:86
bool hasLaneSpecificStopOffsets() const
whether lanes differ in stopOffsets
Definition: NBEdge.cpp:2025
bool includes(Direction d) const
returns the information whether the street in the given direction has a higher priority ...
Definition: NBEdge.cpp:236
double getShapeStartAngle() const
Returns the angle at the start of the edge.
Definition: NBEdge.cpp:1951
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:258
The link is a (hard) left direction.
void assignInternalLaneLength(std::vector< Connection >::iterator i, int numLanes, double lengthSum)
assign length to all lanes of an internal edge
Definition: NBEdge.cpp:1720
PositionVector customShape
custom shape for connection
Definition: NBEdge.h:212
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:241
The connection was computed and validated.
Definition: NBEdge.h:109
bool hasDefaultGeometryEndpoints() const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:541
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
void shortenGeometryAtNode(const NBNode *node, double reduction)
linearly extend the geometry at the given node
Definition: NBEdge.cpp:596
void setLaneShape(int lane, const PositionVector &shape)
sets a custom lane shape
Definition: NBEdge.cpp:3295
void setAcceleration(int lane, bool accelRamp)
marks one lane as acceleration lane
Definition: NBEdge.cpp:3287
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane, bool lefthand=false)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBNode.cpp:1554
static double legacyDegree(const double angle, const bool positive=false)
Definition: GeomHelper.cpp:203
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:255
PositionVector cutAtIntersection(const PositionVector &old) const
cut shape at the intersection shapes
Definition: NBEdge.cpp:694
The edge has been loaded, nothing is computed yet.
Definition: NBEdge.h:86
NBNode * tryGetNodeAtPosition(double pos, double tolerance=5.0) const
Returns the node at the given edges length (using an epsilon)
Definition: NBEdge.cpp:2697
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:3373
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
int myToJunctionPriority
The priority normalised for the node the edge is incoming in.
Definition: NBEdge.h:1490
The link is a straight direction.
PositionVector shape
shape of Connection
Definition: NBEdge.h:218
static const double UNSPECIFIED_SPEED
unspecified lane speed
Definition: NBEdge.h:264
void restoreSidewalk(std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore an previously added sidewalk
Definition: NBEdge.cpp:3464
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:998
bool keepClear
whether the junction must be kept clear when using this connection
Definition: NBEdge.h:200
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:3482
std::vector< Connection > getConnectionsFromLane(int lane) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1117
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:116
bool addEdge2EdgeConnection(NBEdge *dest)
Adds a connection to another edge.
Definition: NBEdge.cpp:974
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void incLaneNo(int by)
increment lane
Definition: NBEdge.cpp:3085
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:303
bool myAmMacroscopicConnector
Information whether this edge is a (macroscopic) connector.
Definition: NBEdge.h:1522
void push_front_noDoublePos(const Position &p)
insert in front a non double position
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
bool computeLanes2Edges()
computes the edge, step2: computation of which lanes approach the edges)
Definition: NBEdge.cpp:2111
NBEdge * myTurnDestination
The turn destination edge (if a connection exists)
Definition: NBEdge.h:1481
double myStartAngle
The angles of the edge.
Definition: NBEdge.h:1461
bool hasLaneSpecificWidth() const
whether lanes differ in width
Definition: NBEdge.cpp:2003
double speed
custom speed for connection
Definition: NBEdge.h:209
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
Definition: NBEdge.h:96
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
bool hasLaneSpecificEndOffset() const
whether lanes differ in offset
Definition: NBEdge.cpp:2014
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:152
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:201
bool hasDefaultGeometryEndpointAtNode(const NBNode *node) const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:548
void decLaneNo(int by)
decrement lane
Definition: NBEdge.cpp:3116
std::string tlID
The id of the traffic light that controls this connection.
Definition: NBEdge.h:191
#define DEBUGCOND2(LANE)
double beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position ...
std::string getLaneID(int lane) const
get Lane ID (Secure)
Definition: NBEdge.cpp:3022
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:420
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:182
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
NBEdge()
constructor for dummy edge
Definition: NBEdge.cpp:345
int operator()(const Connection &c1, const Connection &c2) const
comparing operation
Definition: NBEdge.cpp:245
A list of positions.
bool addLane2LaneConnections(int fromLane, NBEdge *dest, int toLane, int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp:1025
void setOrigID(const std::string origID)
set origID for all lanes
Definition: NBEdge.cpp:3588
const PositionVector getInnerGeometry() const
Returns the geometry of the edge without the endpoints.
Definition: NBEdge.cpp:529
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition: NBEdge.cpp:2711
static int computePrioritySum(const std::vector< int > &priorities)
computes the sum of the given list&#39;s entries (sic!)
Definition: NBEdge.cpp:2630
static bool connections_sorter(const Connection &c1, const Connection &c2)
connections_sorter sort by fromLane, toEdge and toLane
Definition: NBEdge.cpp:3361
void resetNodeBorder(const NBNode *node)
Definition: NBEdge.cpp:657
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition: NBEdge.h:267
bool needsLaneSpecificOutput() const
whether at least one lane has values differing from the edges values
Definition: NBEdge.cpp:2071
void deleteLane(int index, bool recompute, bool shiftIndices)
delete lane
Definition: NBEdge.cpp:3096
bool hasConnectionTo(NBEdge *destEdge, int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1158
NBEdge * myPossibleTurnDestination
The edge that would be the turn destination if there was one.
Definition: NBEdge.h:1484
bool hasDefaultGeometry() const
Returns whether the geometry consists only of the node positions.
Definition: NBEdge.cpp:535
static int getLaneIndexFromLaneID(const std::string laneID)
Definition: NBEdge.cpp:3657
int myPriority
The priority of the edge.
Definition: NBEdge.h:1467
static double firstIntersection(const PositionVector &v1, const PositionVector &v2, double width2)
compute the first intersection point between the given lane geometries considering their rspective wi...
Definition: NBEdge.cpp:1732
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2882
NBConstEdgePairVector myViaSuccessors
Definition: NBEdge.h:1557
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:61
T MIN2(T a, T b)
Definition: StdDefs.h:70
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
The link is a (hard) right direction.
Connection(int fromLane_, NBEdge *toEdge_, int toLane_)
Constructor.
Definition: NBEdge.cpp:91
std::string getSidewalkID()
get the lane id for the canonical sidewalk lane
Definition: NBEdge.cpp:3442
EdgeBuildingStep myStep
The building step.
Definition: NBEdge.h:1448
#define POSITION_EPS
Definition: config.h:172
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:523
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:543
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1801
std::vector< double > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
Class to sort edges by their angle.
Definition: NBEdge.h:1736
void buildInnerEdges(const NBNode &n, int noInternalNoSplits, int &linkIndex, int &splitIndex)
Definition: NBEdge.cpp:1479
double myTotalAngle
Definition: NBEdge.h:1463
PositionVector getCWBoundaryLine(const NBNode &n) const
get the outer boundary of this edge when going clock-wise around the given node
Definition: NBEdge.cpp:2831
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:555
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter...
#define DEG2RAD(x)
Definition: GeomHelper.h:38
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:52
std::vector< Connection > myConnections
List of connections to following edges.
Definition: NBEdge.h:1475
std::string getLaneIDInsecure(int lane) const
get Lane ID (Insecure)
Definition: NBEdge.cpp:3028
void execute(const int lane, const int virtEdge)
executes a bresenham - step
Definition: NBEdge.cpp:147
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
The connection was given by the user.
Definition: NBEdge.h:107
The link is a partial right direction.
double speed
The speed allowed on this lane.
Definition: NBEdge.h:124
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:3404
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3331
bool lanesWereAssigned() const
Check if lanes were assigned.
Definition: NBEdge.cpp:2725
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:3575
void move2side(double amount)
move position vector to side using certain ammount
vehicle is a passenger car (a "normal" car)
bool myAmInnerEdge
Information whether this is a junction-inner edge.
Definition: NBEdge.h:1519
int myIndex
the index of the edge in the list of all edges. Set by NBEdgeCont and requires re-set whenever the li...
Definition: NBEdge.h:1551
int tlLinkIndex
The index of this connection within the controlling traffic light.
Definition: NBEdge.h:194
bool hasLaneSpecificPermissions() const
whether lanes differ in allowed vehicle classes
Definition: NBEdge.cpp:1978
Base class for objects which have an id.
Definition: Named.h:58
double myEndAngle
Definition: NBEdge.h:1462
bool recheckLanes()
recheck whether all lanes within the edge are all right and optimises the connections once again ...
Definition: NBEdge.cpp:2135
bool hasLaneParams() const
whether one of the lanes has parameters set
Definition: NBEdge.cpp:2061
void reinit(NBNode *from, NBNode *to, const std::string &type, double speed, int nolanes, int priority, PositionVector geom, double width, double endOffset, const std::string &streetName, LaneSpreadFunction spread=LANESPREAD_RIGHT, bool tryIgnoreNodePositions=false)
Resets initial values.
Definition: NBEdge.cpp:351
double mySpeed
The maximal speed.
Definition: NBEdge.h:1470
static std::string convertUmlaute(std::string str)
Converts german "Umlaute" to their latin-version.
Definition: StringUtils.cpp:86
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream&#39;s direction.
Definition: NBNode.cpp:1764
static bool isValidNetID(const std::string &value)
whether the given string is a valid id for a network element
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1979
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:514
int getToLane() const
returns the to-lane
#define DEBUGCOND(PEDID)
NBEdge * getTo() const
returns the to-edge (end of the connection)
int internalLaneIndex
The lane index of this internal lane within the internal edge.
Definition: NBEdge.h:239
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:622
void extendGeometryAtNode(const NBNode *node, double maxExtent)
linearly extend the geometry at the given node
Definition: NBEdge.cpp:573
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
Connection getConnection(int fromLane, const NBEdge *to, int toLane) const
Returns the specified connection This method goes through "myConnections" and returns the specified o...
Definition: NBEdge.cpp:1129
vehicle is a bus
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:530
void setTurningDestination(NBEdge *e, bool onlyPossible=false)
Sets the turing destination at the given edge.
Definition: NBEdge.cpp:1828
static const int BACKWARD
Definition: NBNode.h:202
std::string myID
The name of the object.
Definition: Named.h:130
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
double width
This crossing&#39;s width.
Definition: NBNode.h:137
double length() const
Returns the length.
void addStraightConnections(const EdgeVector *outgoing, const std::vector< int > &availableLanes, const std::vector< int > *priorities)
add some straight connections
Definition: NBEdge.cpp:2458
void disableConnection4TLS(int fromLane, NBEdge *toEdge, int toLane)
disable connections for TLS
Definition: NBEdge.cpp:2821
PositionVector viaShape
shape of via
Definition: NBEdge.h:230
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset, int threshold=-1)
patches loaded signal plans by modifying lane indices above threshold by the given offset ...
Definition: NBNode.cpp:386
bool hasAccelLane() const
whether one of the lanes is an acceleration lane
Definition: NBEdge.cpp:2039
EdgeVector mySuccessors
Definition: NBEdge.h:1554
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:855
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:250
PositionVector myToBorder
Definition: NBEdge.h:1546
#define M_PI
Definition: odrSpiral.cpp:40
double getCrossingAngle(NBNode *node)
return the angle for computing pedestrian crossings at the given node
Definition: NBEdge.cpp:3417
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node) ...
Definition: NBNode.h:308
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
Definition: NBNode.cpp:1666
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:3198
static const int UNSPECIFIED_INTERNAL_LANE_INDEX
internal lane computation not yet done
Definition: NBEdge.h:282
void setPreferredVehicleClass(SVCPermissions permissions, int lane=-1)
set preferred Vehicle Class
Definition: NBEdge.cpp:3317
const PositionVector & getNodeBorder(const NBNode *node)
Definition: NBEdge.cpp:646
double mySignalOffset
the offset of a traffic light signal from the end of this edge (-1 for None)
Definition: NBEdge.h:1541
The edge has been loaded and connections shall not be added.
Definition: NBEdge.h:84
bool hasCustomLaneShape() const
whether one of the lanes has a custom shape
Definition: NBEdge.cpp:2050
std::vector< Connection > myConnectionsToDelete
List of connections marked for delayed removal.
Definition: NBEdge.h:1478
double contPos
custom position for internal junction on this connection
Definition: NBEdge.h:203
void shiftLaneIndex(NBEdge *edge, int offset, int threshold=-1)
patches lane indices refering to the given edge and above the threshold by the given offset ...
std::vector< std::string > foeIncomingLanes
FOE Incomings lanes.
Definition: NBEdge.h:236
bool uncontrolled
check if Connection is uncontrolled
Definition: NBEdge.h:242
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:1791
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:267
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
double angleAt2D(int pos) const
get angle in certain position of position vector
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:3470
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:79
const EdgeVector * getConnectedSorted()
Returns the list of outgoing edges without the turnaround sorted in clockwise direction.
Definition: NBEdge.cpp:1177
void restoreRestrictedLane(SUMOVehicleClass vclass, std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore a restricted lane
Definition: NBEdge.cpp:3516
void sortOutgoingConnectionsByIndex()
sorts the outgoing connections by their from-lane-index and their to-lane-index
Definition: NBEdge.cpp:1259
bool needsCont(const NBEdge *fromE, const NBEdge *otherFromE, const NBEdge::Connection &c, const NBEdge::Connection &otherC) const
whether an internal junction should be built at from and respect other
Definition: NBNode.cpp:791
const std::string SUMO_PARAM_ORIGID
std::string myType
The type of the edge.
Definition: NBEdge.h:1451
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge&#39;s lateral offset shal...
void append(NBEdge *continuation)
append another edge
Definition: NBEdge.cpp:2967
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2684
The connection was computed.
Definition: NBEdge.h:105
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:60
const Position & getPosition() const
Definition: NBNode.h:242
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:131
int getFromLane() const
returns the from-lane
Represents a single node (junction) during network building.
Definition: NBNode.h:68
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
MainDirections(const EdgeVector &outgoing, NBEdge *parent, NBNode *to, int indexOfStraightest)
constructor
Definition: NBEdge.cpp:178
void dismissVehicleClassInformation()
dimiss vehicle class information
Definition: NBEdge.cpp:3352
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
Definition: NBEdge.h:94
A definition of a pedestrian crossing.
Definition: NBNode.h:125
const NBConstEdgePairVector & getViaSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges for the given vClass.
Definition: NBEdge.cpp:3621
void replaceInConnections(NBEdge *which, NBEdge *by, int laneOff)
replace in current connections of edge
Definition: NBEdge.cpp:1360
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1214
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:234
static void compute(BresenhamCallBack *callBack, const int val1, const int val2)
Definition: Bresenham.cpp:34
Direction
enum of possible directions
Definition: NBEdge.h:1347
const EdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges for the given vClass.
Definition: NBEdge.cpp:3603
void preferVehicleClass(int lane, SUMOVehicleClass vclass)
prefer certain vehicle class
Definition: NBEdge.cpp:3161
void checkGeometry(const double maxAngle, const double minRadius, bool fix)
Check the angles of successive geometry segments.
Definition: NBEdge.cpp:928
#define NUMERICAL_EPS
Definition: config.h:148
void push_back_noDoublePos(const Position &p)
insert in back a non double position
bool isLeftMover(const NBEdge *const from, const NBEdge *const to) const
Computes whether the given connection is a left mover across the junction.
Definition: NBNode.cpp:1647
void allowVehicleClass(int lane, SUMOVehicleClass vclass)
set allowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:3135
int getTLIndex() const
returns the index within the controlling tls or InvalidTLIndex if this link is unontrolled ...
Definition: NBConnection.h:94
void insertConnection(NBEdge::Connection connection)
insert a previously created NBEdge::connection
Definition: NBEdge.cpp:1111
void addGeometryPoint(int index, const Position &p)
Adds a further geometry point.
Definition: NBEdge.cpp:867
void shiftToLanesToEdge(NBEdge *to, int laneOff)
modifify the toLane for all connections to the given edge
Definition: NBEdge.cpp:3539
void computeAngle()
computes the angle of this edge and stores it in myAngle
Definition: NBEdge.cpp:1899
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:434
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:60
bool computeEdge2Edges(bool noLeftMovers)
computes the edge (step1: computation of approached edges)
Definition: NBEdge.cpp:2086
std::string getInternalLaneID() const
get ID of internal lane
Definition: NBEdge.cpp:80
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:2851
static T maxValue(const std::vector< T > &v)
Definition: VectorHelper.h:91
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:167
bool haveVia
check if Connection have a Via
Definition: NBEdge.h:224
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn&#39;t set.
Definition: NBEdge.h:497
void add(double xoff, double yoff, double zoff)
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:861
double myLength
The length of the edge.
Definition: NBEdge.h:1457
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:242
void divideSelectedLanesOnEdges(const EdgeVector *outgoing, const std::vector< int > &availableLanes, const std::vector< int > *priorities)
divide selected lanes on edges
Definition: NBEdge.cpp:2344
PositionVector computeLaneShape(int lane, double offset) const
Computes the shape for the given lane.
Definition: NBEdge.cpp:1887
double getShapeEndAngle() const
Returns the angle at the end of the edge.
Definition: NBEdge.cpp:1959
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
double myLoadedLength
An optional length to use (-1 if not valid)
Definition: NBEdge.h:1516
void closePolygon()
ensures that the last position equals the first
Lanes to edges - relationships are computed/loaded.
Definition: NBEdge.h:90
std::string myStreetName
The street name (or whatever arbitrary string you wish to attach)
Definition: NBEdge.h:1535
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1454
bool canMoveConnection(const Connection &con, int newFromLane) const
whether the connection can originate on newFromLane
Definition: NBEdge.cpp:1442
Connection & getConnectionRef(int fromLane, const NBEdge *to, int toLane)
Returns reference to the specified connection This method goes through "myConnections" and returns th...
Definition: NBEdge.cpp:1143
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
Definition: NBEdge.cpp:3034
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:441
std::vector< int > foeInternalLinks
FOE Internal links.
Definition: NBEdge.h:233
~MainDirections()
destructor
Definition: NBEdge.cpp:226
static bool isTrafficLight(SumoXMLNodeType type)
return whether the given type is a traffic light
Definition: NBNode.cpp:3102
void shiftPositionAtNode(NBNode *node, NBEdge *opposite)
shift geometry at the given node to avoid overlap
Definition: NBEdge.cpp:3550
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
void disallowVehicleClass(int lane, SUMOVehicleClass vclass)
set disallowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:3148
void copyConnectionsFrom(NBEdge *src)
copy connections from antoher edge
Definition: NBEdge.cpp:1435
A class that being a bresenham-callback assigns the incoming lanes to the edges.
Definition: NBEdge.h:1304
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:3174
void reshiftPosition(double xoff, double yoff)
Applies an offset to the edge.
Definition: NBEdge.cpp:501
const std::map< NBEdge *, std::vector< int > > & getBuiltConnections() const
get built connections
Definition: NBEdge.h:1324
void setz(double z)
set position z
Definition: Position.h:82
NBEdge::Lane getFirstNonPedestrianLane(int direction) const
get first non-pedestrian lane
Definition: NBEdge.cpp:3433
bool splitGeometry(NBEdgeCont &ec, NBNodeCont &nc)
Splits this edge at geometry points.
Definition: NBEdge.cpp:877