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