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