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.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
23 // Methods for the representation of a single edge
24 /****************************************************************************/
25 #include <config.h>
26 
27 #include <vector>
28 #include <string>
29 #include <algorithm>
30 #include <cmath>
31 #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 "NBOwnTLDef.h"
47 #include "NBTypeCont.h"
48 #include "NBEdge.h"
49 
50 //#define ADDITIONAL_WARNINGS
51 //#define DEBUG_CONNECTION_GUESSING
52 //#define DEBUG_ANGLES
53 //#define DEBUG_NODE_BORDER
54 //#define DEBUG_REPLACECONNECTION
55 //#define DEBUG_JUNCTIONPRIO
56 //#define DEBUG_TURNSIGNS
57 //#define DEBUG_CUT_LANES
58 #define DEBUGID ""
59 #define DEBUGCOND (getID() == DEBUGID)
60 //#define DEBUGCOND (StringUtils::startsWith(getID(), DEBUGID))
61 //#define DEBUGCOND (getID() == "22762377#1" || getID() == "146511467")
62 #define DEBUGCOND2(obj) ((obj != 0 && (obj)->getID() == DEBUGID))
63 //#define DEBUGCOND (true)
64 
65 // ===========================================================================
66 // static members
67 // ===========================================================================
68 const double NBEdge::UNSPECIFIED_WIDTH = -1;
69 const double NBEdge::UNSPECIFIED_OFFSET = 0;
70 const double NBEdge::UNSPECIFIED_SPEED = -1;
71 const double NBEdge::UNSPECIFIED_FRICTION = 1.;
72 const double NBEdge::UNSPECIFIED_CONTPOS = -1;
74 
75 const double NBEdge::UNSPECIFIED_SIGNAL_OFFSET = -1;
76 const double NBEdge::UNSPECIFIED_LOADED_LENGTH = -1;
77 const double NBEdge::ANGLE_LOOKAHEAD = 10.0;
80 
82 
84 
85 ConstRouterEdgePairVector NBEdge::Connection::myViaSuccessors = ConstRouterEdgePairVector({ std::pair<NBRouterEdge*, NBRouterEdge*>(nullptr, nullptr) });
86 
87 // ===========================================================================
88 // method definitions
89 // ===========================================================================
90 std::string
92  return id + "_" + toString(internalLaneIndex);
93 }
94 
95 
96 std::string
98  return (Named::getIDSecure(parent) + "_" + toString(fromLane) + "->" + Named::getIDSecure(toEdge) + "_" + toString(toLane)
99  + (permissions == SVC_UNSPECIFIED ? "" : " (" + getVehicleClassNames(permissions) + ")"));
100 }
101 
102 
103 NBEdge::Connection::Connection(int fromLane_, NBEdge* toEdge_, int toLane_, const bool mayDefinitelyPass_) :
104  fromLane(fromLane_),
105  toEdge(toEdge_),
106  toLane(toLane_),
107  mayDefinitelyPass(mayDefinitelyPass_),
108  customLength(myDefaultConnectionLength),
109  id(toEdge_ == nullptr ? "" : toEdge->getFromNode()->getID()) {
110 }
111 
112 
113 NBEdge::Lane::Lane(NBEdge* e, const std::string& origID_) :
114  speed(e->getSpeed()),
115  friction(e->getFriction()),
116  permissions(SVCAll),
117  preferred(0),
118  changeLeft(SVCAll),
119  changeRight(SVCAll),
120  endOffset(e->getEndOffset()),
121  laneStopOffset(e->getEdgeStopOffset()),
122  width(e->getLaneWidth()),
123  accelRamp(false),
124  connectionsDone(false) {
125  if (origID_ != "") {
127  }
128 }
129 
130 
131 /* -------------------------------------------------------------------------
132  * NBEdge::ToEdgeConnectionsAdder-methods
133  * ----------------------------------------------------------------------- */
134 void
135 NBEdge::ToEdgeConnectionsAdder::execute(const int lane, const int virtEdge) {
136  // check
137  assert((int)myTransitions.size() > virtEdge);
138  // get the approached edge
139  NBEdge* succEdge = myTransitions[virtEdge];
140  std::vector<int> lanes;
141 
142  // check whether the currently regarded, approached edge has already
143  // a connection starting at the edge which is currently being build
144  std::map<NBEdge*, std::vector<int> >::iterator i = myConnections.find(succEdge);
145  if (i != myConnections.end()) {
146  // if there were already lanes assigned, get them
147  lanes = (*i).second;
148  }
149 
150  // check whether the current lane was already used to connect the currently
151  // regarded approached edge
152  std::vector<int>::iterator j = std::find(lanes.begin(), lanes.end(), lane);
153  if (j == lanes.end()) {
154  // if not, add it to the list
155  lanes.push_back(lane);
156  }
157  // set information about connecting lanes
158  myConnections[succEdge] = lanes;
159 }
160 
161 
162 
163 /* -------------------------------------------------------------------------
164  * NBEdge::MainDirections-methods
165  * ----------------------------------------------------------------------- */
166 NBEdge::MainDirections::MainDirections(const EdgeVector& outgoing, NBEdge* parent, NBNode* to, const std::vector<int>& availableLanes) : myStraightest(-1) {
168  const NBEdge* straight = nullptr;
169  for (const NBEdge* const out : outgoing) {
170  const SVCPermissions outPerms = out->getPermissions();
171  for (const int l : availableLanes) {
172  if ((parent->myLanes[l].permissions & outPerms) != 0) {
173  if (straight == nullptr || sorter(out, straight)) {
174  straight = out;
175  }
176  break;
177  }
178  }
179  }
180  if (straight == nullptr) {
181  return;
182  }
183  myStraightest = (int)std::distance(outgoing.begin(), std::find(outgoing.begin(), outgoing.end(), straight));
184 
185  // check whether the right turn has a higher priority
186  assert(outgoing.size() > 0);
187  const LinkDirection straightestDir = to->getDirection(parent, straight);
188 #ifdef DEBUG_CONNECTION_GUESSING
189  if (DEBUGCOND2(parent)) {
190  std::cout << " MainDirections edge=" << parent->getID() << " straightest=" << straight->getID() << " dir=" << toString(straightestDir) << "\n";
191  }
192 #endif
193  if (NBNode::isTrafficLight(to->getType()) &&
194  (straightestDir == LinkDirection::STRAIGHT || straightestDir == LinkDirection::PARTLEFT || straightestDir == LinkDirection::PARTRIGHT)) {
196  return;
197  }
198  if (outgoing[0]->getJunctionPriority(to) == 1) {
200  }
201  // check whether the left turn has a higher priority
202  if (outgoing.back()->getJunctionPriority(to) == 1) {
203  // ok, the left turn belongs to the higher priorised edges on the junction
204  // let's check, whether it has also a higher priority (lane number/speed)
205  // than the current
206  if (outgoing.back()->getPriority() > straight->getPriority() ||
207  outgoing.back()->getNumLanes() > straight->getNumLanes()) {
209  }
210  }
211  // check whether the forward direction has a higher priority
212  // check whether it has a higher priority and is going straight
213  if (straight->getJunctionPriority(to) == 1 && to->getDirection(parent, straight) == LinkDirection::STRAIGHT) {
215  }
216 }
217 
218 
220 
221 
222 bool
224  return myDirs.empty();
225 }
226 
227 
228 bool
230  return std::find(myDirs.begin(), myDirs.end(), d) != myDirs.end();
231 }
232 
233 
234 /* -------------------------------------------------------------------------
235  * NBEdge::connections_relative_edgelane_sorter-methods
236  * ----------------------------------------------------------------------- */
237 int
239  if (c1.toEdge != c2.toEdge) {
241  }
242  return c1.toLane < c2.toLane;
243 }
244 
245 
246 /* -------------------------------------------------------------------------
247  * NBEdge-methods
248  * ----------------------------------------------------------------------- */
249 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
250  std::string type, double speed, double friction, int nolanes,
251  int priority, double laneWidth, double endOffset,
252  LaneSpreadFunction spread, const std::string& streetName) :
253  Named(StringUtils::convertUmlaute(id)),
254  myStep(EdgeBuildingStep::INIT),
255  myType(StringUtils::convertUmlaute(type)),
256  myFrom(from), myTo(to),
258  myPriority(priority), mySpeed(speed), myFriction(friction),
259  myDistance(0),
260  myTurnDestination(nullptr),
261  myPossibleTurnDestination(nullptr),
263  myLaneSpreadFunction(spread), myEndOffset(endOffset),
264  myLaneWidth(laneWidth),
266  myAmInTLS(false), myAmMacroscopicConnector(false),
267  myStreetName(streetName),
269  mySignalNode(nullptr),
270  myIsOffRamp(false),
271  myIsBidi(false),
272  myIndex(-1) {
273  init(nolanes, false, "");
274 }
275 
276 
277 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
278  std::string type, double speed, double friction, int nolanes,
279  int priority, double laneWidth, double endOffset,
280  PositionVector geom,
281  LaneSpreadFunction spread,
282  const std::string& streetName,
283  const std::string& origID,
284  bool tryIgnoreNodePositions) :
285  Named(StringUtils::convertUmlaute(id)),
286  myStep(EdgeBuildingStep::INIT),
287  myType(StringUtils::convertUmlaute(type)),
288  myFrom(from), myTo(to),
289  myStartAngle(0), myEndAngle(0), myTotalAngle(0),
290  myPriority(priority), mySpeed(speed), myFriction(friction),
291  myDistance(0),
292  myTurnDestination(nullptr),
293  myPossibleTurnDestination(nullptr),
294  myFromJunctionPriority(-1), myToJunctionPriority(-1),
295  myGeom(geom), myLaneSpreadFunction(spread), myEndOffset(endOffset),
296  myLaneWidth(laneWidth),
297  myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
298  myAmInTLS(false), myAmMacroscopicConnector(false),
299  myStreetName(streetName),
300  mySignalPosition(Position::INVALID),
301  mySignalNode(nullptr),
302  myIsOffRamp(false),
303  myIsBidi(false),
304  myIndex(-1) {
305  init(nolanes, tryIgnoreNodePositions, origID);
306 }
307 
308 
309 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to, const NBEdge* tpl, const PositionVector& geom, int numLanes) :
310  Named(StringUtils::convertUmlaute(id)),
311  myStep(EdgeBuildingStep::INIT),
312  myType(tpl->getTypeID()),
313  myFrom(from), myTo(to),
314  myStartAngle(0), myEndAngle(0), myTotalAngle(0),
315  myPriority(tpl->getPriority()), mySpeed(tpl->getSpeed()),
316  myFriction(tpl->getFriction()),
317  myDistance(0),
318  myTurnDestination(nullptr),
319  myPossibleTurnDestination(nullptr),
320  myFromJunctionPriority(-1), myToJunctionPriority(-1),
321  myGeom(geom),
322  myLaneSpreadFunction(tpl->getLaneSpreadFunction()),
323  myEndOffset(tpl->getEndOffset()),
324  myEdgeStopOffset(tpl->getEdgeStopOffset()),
325  myLaneWidth(tpl->getLaneWidth()),
326  myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
327  myAmInTLS(false),
328  myAmMacroscopicConnector(false),
329  myStreetName(tpl->getStreetName()),
330  mySignalPosition(to == tpl->myTo ? tpl->mySignalPosition : Position::INVALID),
331  mySignalNode(to == tpl->myTo ? tpl->mySignalNode : nullptr),
332  myIsOffRamp(false),
333  myIsBidi(false),
334  myIndex(-1) {
335  init(numLanes > 0 ? numLanes : tpl->getNumLanes(), myGeom.size() > 0, "");
336  for (int i = 0; i < getNumLanes(); i++) {
337  const int tplIndex = MIN2(i, tpl->getNumLanes() - 1);
338  setSpeed(i, tpl->getLaneSpeed(tplIndex));
339  setFriction(i, tpl->getLaneFriction(tplIndex));
340  setPermissions(tpl->getPermissions(tplIndex), i);
341  setLaneWidth(i, tpl->myLanes[tplIndex].width);
342  setLaneType(i, tpl->myLanes[tplIndex].type);
343  myLanes[i].updateParameters(tpl->myLanes[tplIndex].getParametersMap());
344  if (to == tpl->myTo) {
345  setEndOffset(i, tpl->myLanes[tplIndex].endOffset);
346  setEdgeStopOffset(i, tpl->myLanes[tplIndex].laneStopOffset);
347  }
348  }
349  if (tpl->myLoadedLength > 0 && to == tpl->getFromNode() && from == tpl->getToNode() && geom == tpl->getGeometry().reverse()) {
351  }
353 }
354 
355 
357  Named("DUMMY"),
358  myStep(EdgeBuildingStep::INIT),
359  myFrom(nullptr), myTo(nullptr),
360  myStartAngle(0), myEndAngle(0), myTotalAngle(0),
361  myPriority(0), mySpeed(0), myFriction(UNSPECIFIED_FRICTION),
362  myDistance(0),
363  myTurnDestination(nullptr),
364  myPossibleTurnDestination(nullptr),
365  myFromJunctionPriority(-1), myToJunctionPriority(-1),
366  myLaneSpreadFunction(LaneSpreadFunction::RIGHT),
367  myEndOffset(0),
368  myEdgeStopOffset(StopOffset()),
369  myLaneWidth(0),
370  myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
371  myAmInTLS(false),
372  myAmMacroscopicConnector(false),
373  mySignalPosition(Position::INVALID),
374  mySignalNode(nullptr) {
375 }
376 
377 
378 void
379 NBEdge::reinit(NBNode* from, NBNode* to, const std::string& type,
380  double speed, double friction, int nolanes, int priority,
381  PositionVector geom, double laneWidth, double endOffset,
382  const std::string& streetName,
383  LaneSpreadFunction spread,
384  bool tryIgnoreNodePositions) {
385  if (myFrom != from) {
386  myFrom->removeEdge(this, false);
387  }
388  if (myTo != to) {
389  myTo->removeEdge(this, false);
390  }
392  myFrom = from;
393  myTo = to;
394  myPriority = priority;
395  //?myTurnDestination(0),
396  //?myFromJunctionPriority(-1), myToJunctionPriority(-1),
397  myGeom = geom;
398  myLaneSpreadFunction = spread;
400  myStreetName = streetName;
401  //?, myAmTurningWithAngle(0), myAmTurningOf(0),
402  //?myAmInTLS(false), myAmMacroscopicConnector(false)
403 
404  // preserve lane-specific settings (geometry must be recomputed)
405  // if new lanes are added they copy the values from the leftmost lane (if specified)
406  const std::vector<Lane> oldLanes = myLanes;
407  init(nolanes, tryIgnoreNodePositions, oldLanes.empty() ? "" : oldLanes[0].getParameter(SUMO_PARAM_ORIGID));
408  for (int i = 0; i < (int)nolanes; ++i) {
409  PositionVector newShape = myLanes[i].shape;
410  myLanes[i] = oldLanes[MIN2(i, (int)oldLanes.size() - 1)];
411  myLanes[i].shape = newShape;
412  }
413  // however, if the new edge defaults are explicityly given, they override the old settings
414  if (endOffset != UNSPECIFIED_OFFSET) {
415  setEndOffset(-1, endOffset);
416  }
417  if (laneWidth != UNSPECIFIED_WIDTH) {
418  setLaneWidth(-1, laneWidth);
419  }
420  if (speed != UNSPECIFIED_SPEED) {
421  setSpeed(-1, speed);
422  }
423  if (friction != UNSPECIFIED_FRICTION) {
424  setFriction(-1, friction);
425  }
426 }
427 
428 
429 void
431  // connections may still be valid
432  if (from == nullptr || to == nullptr) {
433  throw ProcessError(TLF("At least one of edge's '%' nodes is not known.", myID));
434  }
435  if (myFrom != from) {
436  myFrom->removeEdge(this, false);
437  }
438  if (myTo != to) {
439  myTo->removeEdge(this, false);
440  }
441  // remove first from both nodes and then add to the new nodes
442  // (otherwise reversing does not work)
443  if (myFrom != from) {
444  myFrom = from;
445  myFrom->addOutgoingEdge(this);
446  }
447  if (myTo != to) {
448  myTo = to;
449  myTo->addIncomingEdge(this);
450  }
451  computeAngle();
452 }
453 
454 
455 void
456 NBEdge::init(int noLanes, bool tryIgnoreNodePositions, const std::string& origID) {
457  if (noLanes == 0) {
458  throw ProcessError(TLF("Edge '%' needs at least one lane.", myID));
459  }
460  if (myFrom == nullptr || myTo == nullptr) {
461  throw ProcessError(TLF("At least one of edge's '%' nodes is not known.", myID));
462  }
464  throw ProcessError(TLF("Invalid edge id '%'.", myID));
465  }
466  // revisit geometry
467  // should have at least two points at the end...
468  // and in dome cases, the node positions must be added
469  // attempt symmetrical removal for forward and backward direction
470  // (very important for bidiRail)
471  if (myFrom->getID() < myTo->getID()) {
472  PositionVector reverse = myGeom.reverse();
473  reverse.removeDoublePoints(POSITION_EPS, true);
474  myGeom = reverse.reverse();
475  } else {
476  myGeom.removeDoublePoints(POSITION_EPS, true);
477  }
478 
479  if (!tryIgnoreNodePositions || myGeom.size() < 2) {
480  if (myGeom.size() == 0) {
481  myGeom.push_back(myFrom->getPosition());
482  myGeom.push_back(myTo->getPosition());
483  } else {
486  }
487  }
488  if (myGeom.size() < 2) {
489  myGeom.clear();
490  myGeom.push_back(myFrom->getPosition());
491  myGeom.push_back(myTo->getPosition());
492  }
493  if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
494  WRITE_WARNINGF(TL("Edge's '%' from- and to-node are at the same position."), myID);
495  int patchIndex = myFrom->getID() < myTo->getID() ? 1 : 0;
496  myGeom[patchIndex].add(Position(POSITION_EPS, POSITION_EPS));
497  }
498  //
499  myFrom->addOutgoingEdge(this);
500  myTo->addIncomingEdge(this);
501  // prepare container
502  assert(myGeom.size() >= 2);
503  myLength = myGeom.length();
504  if ((int)myLanes.size() > noLanes) {
505  // remove connections starting at the removed lanes
506  for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
507  removeFromConnections(nullptr, lane, -1);
508  }
509  // remove connections targeting the removed lanes
510  const EdgeVector& incoming = myFrom->getIncomingEdges();
511  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
512  for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
513  (*i)->removeFromConnections(this, -1, lane);
514  }
515  }
516  }
517  myLanes.clear();
518  for (int i = 0; i < noLanes; i++) {
519  myLanes.push_back(Lane(this, origID));
520  }
522  computeAngle();
523 
524 #ifdef DEBUG_CONNECTION_GUESSING
525  if (DEBUGCOND) {
526  std::cout << "init edge=" << getID() << "\n";
527  for (Connection& c : myConnections) {
528  std::cout << " conn " << c.getDescription(this) << "\n";
529  }
530  for (Connection& c : myConnectionsToDelete) {
531  std::cout << " connToDelete " << c.getDescription(this) << "\n";
532  }
533  }
534 #endif
535 }
536 
537 
539 
540 
541 // ----------- Applying offset
542 void
543 NBEdge::reshiftPosition(double xoff, double yoff) {
544  myGeom.add(xoff, yoff, 0);
545  for (Lane& lane : myLanes) {
546  lane.customShape.add(xoff, yoff, 0);
547  }
548  computeLaneShapes(); // old shapes are dubious if computed with large coordinates
549  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
550  (*i).customShape.add(xoff, yoff, 0);
551  }
553  mySignalPosition.add(xoff, yoff);
554  }
555  myFromBorder.add(xoff, yoff, 0);
556  myToBorder.add(xoff, yoff, 0);
558  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
559 }
560 
561 
562 void
564  myGeom.mirrorX();
565  for (int i = 0; i < (int)myLanes.size(); i++) {
566  myLanes[i].shape.mirrorX();
567  myLanes[i].customShape.mirrorX();
568  }
569  for (Connection& c : myConnections) {
570  c.shape.mirrorX();
571  c.viaShape.mirrorX();
572  c.customShape.mirrorX();
573  }
576  }
577  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
578 }
579 
580 
581 // ----------- Edge geometry access and computation
582 const PositionVector
584  return myGeom.getSubpartByIndex(1, (int)myGeom.size() - 2);
585 }
586 
587 
588 bool
590  return myGeom.size() == 2 && hasDefaultGeometryEndpoints();
591 }
592 
593 
594 bool
596  return myGeom.front().almostSame(myFrom->getPosition(), 0.01) &&
597  myGeom.back().almostSame(myTo->getPosition(), 0.01);
598 }
599 
600 
601 bool
603  // do not extend past the node position
604  if (node == myFrom) {
605  return myGeom.front() == node->getPosition();
606  } else {
607  assert(node == myTo);
608  return myGeom.back() == node->getPosition();
609  }
610 }
611 
612 Position
613 NBEdge::getEndpointAtNode(const NBNode* node) const {
614  return node == myFrom ? myGeom.front() : myGeom.back();
615 }
616 
617 void
618 NBEdge::setGeometry(const PositionVector& s, bool inner) {
619  Position begin = myGeom.front(); // may differ from node position
620  Position end = myGeom.back(); // may differ from node position
621  myGeom = s;
622  if (inner) {
623  myGeom.insert(myGeom.begin(), begin);
624  myGeom.push_back(end);
625  }
626  // ensure non-zero length (see ::init)
627  if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
628  WRITE_WARNINGF(TL("Edge's '%' from- and to-node are at the same position."), myID);
629  int patchIndex = myFrom->getID() < myTo->getID() ? 1 : 0;
630  myGeom[patchIndex].add(Position(POSITION_EPS, POSITION_EPS));
631  }
633  computeAngle();
634  myLength = myGeom.length();
635 }
636 
637 
638 void
639 NBEdge::extendGeometryAtNode(const NBNode* node, double maxExtent) {
640  //std::cout << "extendGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " extent=" << maxExtent << " geom=" << myGeom;
641  if (node == myFrom) {
642  myGeom.extrapolate(maxExtent, true);
643  double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
644  //std::cout << " geom2=" << myGeom << " offset=" << offset;
645  if (offset != GeomHelper::INVALID_OFFSET) {
646  myGeom = myGeom.getSubpart2D(MIN2(offset, myGeom.length2D() - 2 * POSITION_EPS), myGeom.length2D());
647  }
648  } else {
649  assert(node == myTo);
650  myGeom.extrapolate(maxExtent, false, true);
651  double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
652  //std::cout << " geom2=" << myGeom << " offset=" << offset;
653  if (offset != GeomHelper::INVALID_OFFSET) {
654  myGeom = myGeom.getSubpart2D(0, MAX2(offset, 2 * POSITION_EPS));
655  }
656  }
657  //std::cout << " geom3=" << myGeom << "\n";
658 }
659 
660 
661 void
662 NBEdge::shortenGeometryAtNode(const NBNode* node, double reduction) {
663  //std::cout << "shortenGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " reduction=" << reduction << " geom=" << myGeom;
664  reduction = MIN2(reduction, myGeom.length2D() - 2 * POSITION_EPS);
665  if (node == myFrom) {
666  myGeom = myGeom.getSubpart2D(reduction, myGeom.length2D());
667  } else {
668  myGeom = myGeom.getSubpart2D(0, myGeom.length2D() - reduction);
669  }
671  //std::cout << " geom2=" << myGeom << "\n";
672 }
673 
674 
675 void
676 NBEdge::setNodeBorder(const NBNode* node, const Position& p, const Position& p2, bool rectangularCut) {
677  PositionVector border;
678  if (rectangularCut) {
679  const double extend = 100;
680  border = myGeom.getOrthogonal(p, extend, node == myTo);
681  } else {
682  border.push_back(p);
683  border.push_back(p2);
684  }
685  if (border.size() == 2) {
686  border.extrapolate2D(getTotalWidth());
687  if (node == myFrom) {
688  myFromBorder = border;
689  } else {
690  assert(node == myTo);
691  myToBorder = border;
692  }
693  }
694 #ifdef DEBUG_NODE_BORDER
696  if (DEBUGCOND) std::cout << "setNodeBorder edge=" << getID() << " node=" << node->getID()
697  << " rect=" << rectangularCut
698  << " p=" << p << " p2=" << p2
699  << " border=" << border
700  << " myGeom=" << myGeom
701  << "\n";
702 
703 #endif
704 }
705 
706 
707 const PositionVector&
708 NBEdge::getNodeBorder(const NBNode* node) const {
709  if (node == myFrom) {
710  return myFromBorder;
711  } else {
712  assert(node == myTo);
713  return myToBorder;
714  }
715 }
716 
717 
718 void
720  if (node == myFrom) {
721  myFromBorder.clear();
722  } else {
723  assert(node == myTo);
724  myToBorder.clear();
725  }
726 }
727 
728 
729 bool
730 NBEdge::isBidiRail(bool ignoreSpread) const {
731  return (isRailway(getPermissions())
732  && (ignoreSpread || myLaneSpreadFunction == LaneSpreadFunction::CENTER)
733  && myPossibleTurnDestination != nullptr
738 }
739 
740 
741 bool
742 NBEdge::isBidiEdge(bool checkPotential) const {
743  return myPossibleTurnDestination != nullptr
745  && (myIsBidi || myPossibleTurnDestination->myIsBidi || checkPotential)
748  // geometry check a) full overlap geometry
751  || (checkPotential && getGeometry().size() == 2 && myPossibleTurnDestination->getGeometry().size() == 2)))
752  // b) TWLT (Two-Way-Left-Turn-lane)
753  || (myLanes.back().shape.reverse().almostSame(myPossibleTurnDestination->myLanes.back().shape, POSITION_EPS))
754  );
755 
756 }
757 
758 
759 bool
761  if (!isRailway(getPermissions())) {
762  return false;
763  }
764  for (NBEdge* out : myTo->getOutgoingEdges()) {
765  if (isRailway(out->getPermissions()) &&
766  out != getTurnDestination(true)) {
767  return true;
768  }
769  }
770  return true;
771 }
772 
773 
776  PositionVector shape = old;
777  shape = startShapeAt(shape, myFrom, myFromBorder);
778 #ifdef DEBUG_CUT_LANES
779  if (DEBUGCOND) {
780  std::cout << getID() << " cutFrom=" << shape << "\n";
781  }
782 #endif
783  if (shape.size() < 2) {
784  // only keep the last snippet
785  const double oldLength = old.length();
786  shape = old.getSubpart(oldLength - 2 * POSITION_EPS, oldLength);
787 #ifdef DEBUG_CUT_LANES
788  if (DEBUGCOND) {
789  std::cout << getID() << " cutFromFallback=" << shape << "\n";
790  }
791 #endif
792  }
793  shape = startShapeAt(shape.reverse(), myTo, myToBorder).reverse();
794 #ifdef DEBUG_CUT_LANES
795  if (DEBUGCOND) {
796  std::cout << getID() << " cutTo=" << shape << "\n";
797  }
798 #endif
799  // sanity checks
800  if (shape.length() < POSITION_EPS) {
801  if (old.length() < 2 * POSITION_EPS) {
802  shape = old;
803  } else {
804  const double midpoint = old.length() / 2;
805  // EPS*2 because otherwhise shape has only a single point
806  shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
807  assert(shape.size() >= 2);
808  assert(shape.length() > 0);
809 #ifdef DEBUG_CUT_LANES
810  if (DEBUGCOND) {
811  std::cout << getID() << " fallBackShort=" << shape << "\n";
812  }
813 #endif
814  }
815  } else {
816  // @note If the node shapes are overlapping we may get a shape which goes in the wrong direction
817  // in this case the result shape should shortened
818  if (DEG2RAD(135) < fabs(GeomHelper::angleDiff(shape.beginEndAngle(), old.beginEndAngle()))) {
819  // eliminate intermediate points
820  PositionVector tmp;
821  tmp.push_back(shape[0]);
822  tmp.push_back(shape[-1]);
823  shape = tmp;
824  if (tmp.length() < POSITION_EPS) {
825  // fall back to original shape
826  if (old.length() < 2 * POSITION_EPS) {
827  shape = old;
828  } else {
829  const double midpoint = old.length() / 2;
830  // EPS*2 because otherwhise shape has only a single point
831  shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
832  assert(shape.size() >= 2);
833  assert(shape.length() > 0);
834  }
835 #ifdef DEBUG_CUT_LANES
836  if (DEBUGCOND) {
837  std::cout << getID() << " fallBackReversed=" << shape << "\n";
838  }
839 #endif
840  } else {
841  const double midpoint = shape.length() / 2;
842  // cut to size and reverse
843  shape = shape.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
844  if (shape.length() < POSITION_EPS) {
845  assert(false);
846  // the shape has a sharp turn near the midpoint
847  }
848  shape = shape.reverse();
849 #ifdef DEBUG_CUT_LANES
850  if (DEBUGCOND) {
851  std::cout << getID() << " fallBackReversed2=" << shape << " mid=" << midpoint << "\n";
852  }
853 #endif
854  }
855  // make short edge flat (length <= 2 * POSITION_EPS)
856  const double z = (shape[0].z() + shape[1].z()) / 2;
857  shape[0].setz(z);
858  shape[1].setz(z);
859  }
860  }
861  return shape;
862 }
863 
864 
865 void
866 NBEdge::computeEdgeShape(double smoothElevationThreshold) {
867  if (smoothElevationThreshold > 0 && myGeom.hasElevation()) {
869  // cutting and patching z-coordinate may cause steep grades which should be smoothed
870  if (!myFrom->geometryLike()) {
871  cut[0].setz(myFrom->getPosition().z());
872  const double d = cut[0].distanceTo2D(cut[1]);
873  const double dZ = fabs(cut[0].z() - cut[1].z());
874  if (dZ / smoothElevationThreshold > d) {
875  cut = cut.smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold));
876  }
877  }
878  if (!myTo->geometryLike()) {
879  cut[-1].setz(myTo->getPosition().z());
880  const double d = cut[-1].distanceTo2D(cut[-2]);
881  const double dZ = fabs(cut[-1].z() - cut[-2].z());
882  if (dZ / smoothElevationThreshold > d) {
883  cut = cut.reverse().smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold)).reverse();
884  }
885  }
886  cut[0] = myGeom[0];
887  cut[-1] = myGeom[-1];
888  if (cut != myGeom) {
889  myGeom = cut;
891  }
892  }
893  for (int i = 0; i < (int)myLanes.size(); i++) {
894  myLanes[i].shape = cutAtIntersection(myLanes[i].shape);
895  }
896  // recompute edge's length as the average of lane lengths
897  double avgLength = 0;
898  for (int i = 0; i < (int)myLanes.size(); i++) {
899  avgLength += myLanes[i].shape.length();
900  }
901  myLength = avgLength / (double) myLanes.size();
902  computeAngle(); // update angles using the finalized node and lane shapes
903 }
904 
905 
907 NBEdge::startShapeAt(const PositionVector& laneShape, const NBNode* startNode, PositionVector nodeShape) {
908  if (nodeShape.size() == 0) {
909  nodeShape = startNode->getShape();
910  nodeShape.closePolygon();
911  }
912  PositionVector lb = laneShape;
913  lb.extrapolate2D(100.0);
914  if (nodeShape.intersects(laneShape)) {
915  // shape intersects directly
916  std::vector<double> pbv = laneShape.intersectsAtLengths2D(nodeShape);
917  assert(pbv.size() > 0);
918  // ensure that the subpart has at least two points
919  double pb = MIN2(laneShape.length2D() - POSITION_EPS - NUMERICAL_EPS, VectorHelper<double>::maxValue(pbv));
920  if (pb < 0) {
921  return laneShape;
922  }
923  PositionVector ns = laneShape.getSubpart2D(pb, laneShape.length2D());
924  //PositionVector ns = pb < (laneShape.length() - POSITION_EPS) ? laneShape.getSubpart2D(pb, laneShape.length()) : laneShape;
925  const double delta = ns[0].z() - laneShape[0].z();
926  //std::cout << "a) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << ns[0].z() << " delta=" << delta << "\n";
927  if (fabs(delta) > 2 * POSITION_EPS && (!startNode->geometryLike() || pb < 1)) {
928  // make "real" intersections and small intersections flat
929  //std::cout << "a) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << ns[0].z() << " delta=" << delta << "\n";
930  ns[0].setz(startNode->getPosition().z());
931  }
932  assert(ns.size() >= 2);
933  return ns;
934  } else if (nodeShape.intersects(lb)) {
935  // extension of first segment intersects
936  std::vector<double> pbv = lb.intersectsAtLengths2D(nodeShape);
937  assert(pbv.size() > 0);
938  double pb = VectorHelper<double>::maxValue(pbv);
939  assert(pb >= 0);
940  PositionVector result = laneShape.getSubpartByIndex(1, (int)laneShape.size() - 1);
941  Position np = lb.positionAtOffset2D(pb);
942  const double delta = np.z() - laneShape[0].z();
943  //std::cout << "b) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << np.z() << " delta=" << delta << "\n";
944  if (fabs(delta) > 2 * POSITION_EPS && !startNode->geometryLike()) {
945  // avoid z-overshoot when extrapolating
946  //std::cout << "b) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << np.z() << " delta=" << delta << "\n";
947  np.setz(startNode->getPosition().z());
948  }
949  result.push_front_noDoublePos(np);
950  return result;
951  //if (result.size() >= 2) {
952  // return result;
953  //} else {
954  // WRITE_WARNING(error + " (resulting shape is too short)");
955  // return laneShape;
956  //}
957  } else {
958  // could not find proper intersection. Probably the edge is very short
959  // and lies within nodeShape
960  // @todo enable warning WRITE_WARNING(error + " (laneShape lies within nodeShape)");
961  return laneShape;
962  }
963 }
964 
965 
966 const PositionVector&
967 NBEdge::getLaneShape(int i) const {
968  return myLanes[i].shape;
969 }
970 
971 
972 void
974  myLaneSpreadFunction = spread;
975 }
976 
977 
980  return myLaneSpreadFunction;
981 }
982 
983 
984 void
985 NBEdge::addGeometryPoint(int index, const Position& p) {
986  if (index >= 0) {
987  myGeom.insert(myGeom.begin() + index, p);
988  } else {
989  myGeom.insert(myGeom.end() + index, p);
990  }
991 }
992 
993 
994 void
995 NBEdge::reduceGeometry(const double minDist) {
996  // attempt symmetrical removal for forward and backward direction
997  // (very important for bidiRail)
998  if (myFrom->getID() < myTo->getID()) {
999  PositionVector reverse = myGeom.reverse();
1000  reverse.removeDoublePoints(minDist, true, 0, 0, true);
1001  myGeom = reverse.reverse();
1002  for (Lane& lane : myLanes) {
1003  reverse = lane.customShape.reverse();
1004  reverse.removeDoublePoints(minDist, true, 0, 0, true);
1005  lane.customShape = reverse.reverse();
1006  }
1007  } else {
1008  myGeom.removeDoublePoints(minDist, true, 0, 0, true);
1009  for (Lane& lane : myLanes) {
1010  lane.customShape.removeDoublePoints(minDist, true, 0, 0, true);
1011  }
1012  }
1013 }
1014 
1015 
1016 void
1017 NBEdge::checkGeometry(const double maxAngle, const double minRadius, bool fix, bool silent) {
1018  if (myGeom.size() < 3) {
1019  return;
1020  }
1021  //std::cout << "checking geometry of " << getID() << " geometry = " << toString(myGeom) << "\n";
1022  std::vector<double> angles; // absolute segment angles
1023  //std::cout << " absolute angles:";
1024  for (int i = 0; i < (int)myGeom.size() - 1; ++i) {
1025  angles.push_back(myGeom.angleAt2D(i));
1026  //std::cout << " " << angles.back();
1027  }
1028  //std::cout << "\n relative angles: ";
1029  for (int i = 0; i < (int)angles.size() - 1; ++i) {
1030  const double relAngle = fabs(GeomHelper::angleDiff(angles[i], angles[i + 1]));
1031  //std::cout << relAngle << " ";
1032  if (maxAngle > 0 && relAngle > maxAngle && !silent) {
1033  WRITE_WARNINGF(TL("Found angle of % degrees at edge '%', segment %."), RAD2DEG(relAngle), getID(), i);
1034  }
1035  if (relAngle < DEG2RAD(1)) {
1036  continue;
1037  }
1038  if (i == 0 || i == (int)angles.size() - 2) {
1039  const bool start = i == 0;
1040  const double dist = (start ? myGeom[0].distanceTo2D(myGeom[1]) : myGeom[-2].distanceTo2D(myGeom[-1]));
1041  const double r = tan(0.5 * (M_PI - relAngle)) * dist;
1042  //std::cout << (start ? " start" : " end") << " length=" << dist << " radius=" << r << " ";
1043  if (minRadius > 0 && r < minRadius) {
1044  if (fix) {
1045  WRITE_MESSAGEF(TL("Removing sharp turn with radius % at the % of edge '%'."),
1046  toString(r), start ? TL("start") : TL("end"), getID());
1047  myGeom.erase(myGeom.begin() + (start ? 1 : i + 1));
1048  checkGeometry(maxAngle, minRadius, fix, silent);
1049  return;
1050  } else if (!silent) {
1051  WRITE_WARNINGF(TL("Found sharp turn with radius % at the % of edge '%'."),
1052  toString(r), start ? TL("start") : TL("end"), getID());
1053  }
1054  }
1055  }
1056  }
1057  //std::cout << "\n";
1058 }
1059 
1060 
1061 // ----------- Setting and getting connections
1062 bool
1063 NBEdge::addEdge2EdgeConnection(NBEdge* dest, bool overrideRemoval, SVCPermissions permissions) {
1065  return true;
1066  }
1067  // check whether the node was merged and now a connection between
1068  // not matching edges is tried to be added
1069  // This happens f.e. within the ptv VISSIM-example "Beijing"
1070  if (dest != nullptr && myTo != dest->myFrom) {
1071  return false;
1072  }
1073  if (dest == nullptr) {
1075  myConnections.push_back(Connection(-1, dest, -1));
1076  } else if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(dest)) == myConnections.end()) {
1077  myConnections.push_back(Connection(-1, dest, -1));
1078  myConnections.back().permissions = permissions;
1079  }
1080  if (overrideRemoval) {
1081  // override earlier delete decision
1082  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end();) {
1083  if (it->toEdge == dest) {
1084  it = myConnectionsToDelete.erase(it);
1085  } else {
1086  it++;
1087  }
1088  }
1089  }
1092  }
1093  return true;
1094 }
1095 
1096 
1097 bool
1099  int toLane, Lane2LaneInfoType type,
1100  bool mayUseSameDestination,
1101  bool mayDefinitelyPass,
1102  KeepClear keepClear,
1103  double contPos,
1104  double visibility,
1105  double speed,
1106  double friction,
1107  double length,
1108  const PositionVector& customShape,
1109  bool uncontrolled,
1110  SVCPermissions permissions,
1111  bool indirectLeft,
1112  const std::string& edgeType,
1113  SVCPermissions changeLeft,
1114  SVCPermissions changeRight,
1115  bool postProcess) {
1117  return true;
1118  }
1119  // check whether the node was merged and now a connection between
1120  // not matching edges is tried to be added
1121  // This happens f.e. within the ptv VISSIM-example "Beijing"
1122  if (myTo != dest->myFrom) {
1123  return false;
1124  }
1125  if (!addEdge2EdgeConnection(dest)) {
1126  return false;
1127  }
1128  return setConnection(from, dest, toLane, type, mayUseSameDestination, mayDefinitelyPass, keepClear, contPos, visibility, speed, friction, length,
1129  customShape, uncontrolled, permissions, indirectLeft, edgeType, changeLeft, changeRight, postProcess);
1130 }
1131 
1132 
1133 bool
1135  NBEdge* dest, int toLane,
1136  int no, Lane2LaneInfoType type,
1137  bool invalidatePrevious,
1138  bool mayDefinitelyPass) {
1139  if (invalidatePrevious) {
1140  invalidateConnections(true);
1141  }
1142  bool ok = true;
1143  for (int i = 0; i < no && ok; i++) {
1144  ok &= addLane2LaneConnection(fromLane + i, dest, toLane + i, type, false, mayDefinitelyPass);
1145  }
1146  return ok;
1147 }
1148 
1149 
1150 bool
1151 NBEdge::setConnection(int lane, NBEdge* destEdge,
1152  int destLane, Lane2LaneInfoType type,
1153  bool mayUseSameDestination,
1154  bool mayDefinitelyPass,
1155  KeepClear keepClear,
1156  double contPos,
1157  double visibility,
1158  double speed,
1159  double friction,
1160  double length,
1161  const PositionVector& customShape,
1162  bool uncontrolled,
1163  SVCPermissions permissions,
1164  bool indirectLeft,
1165  const std::string& edgeType,
1166  SVCPermissions changeLeft,
1167  SVCPermissions changeRight,
1168  bool postProcess) {
1170  return false;
1171  }
1172  // some kind of a misbehaviour which may occure when the junction's outgoing
1173  // edge priorities were not properly computed, what may happen due to
1174  // an incomplete or not proper input
1175  // what happens is that under some circumstances a single lane may set to
1176  // be approached more than once by the one of our lanes.
1177  // This must not be!
1178  // we test whether it is the case and do nothing if so - the connection
1179  // will be refused
1180  //
1181  if (!mayUseSameDestination && hasConnectionTo(destEdge, destLane)) {
1182  return false;
1183  }
1184  if (find_if(myConnections.begin(), myConnections.end(), connections_finder(lane, destEdge, destLane)) != myConnections.end()) {
1185  return true;
1186  }
1187  if ((int)myLanes.size() <= lane || destEdge->getNumLanes() <= (int)destLane) {
1188  // problem might be corrigible in post-processing
1189  WRITE_WARNINGF(TL("Could not set connection from '%' to '%'."), getLaneID(lane), destEdge->getLaneID(destLane));
1190  return false;
1191  }
1192  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1193  if ((*i).toEdge == destEdge && ((*i).fromLane == -1 || (*i).toLane == -1)) {
1194  if (permissions == SVC_UNSPECIFIED) {
1195  // @note: in case we were to add multiple connections from the
1196  // same lane the second one wouldn't get the special permissions!
1197  permissions = (*i).permissions;
1198  }
1199  i = myConnections.erase(i);
1200  } else {
1201  ++i;
1202  }
1203  }
1204  myConnections.push_back(Connection(lane, destEdge, destLane));
1205  if (mayDefinitelyPass) {
1206  myConnections.back().mayDefinitelyPass = true;
1207  }
1208  myConnections.back().keepClear = keepClear;
1209  myConnections.back().contPos = contPos;
1210  myConnections.back().visibility = visibility;
1211  myConnections.back().permissions = permissions;
1212  myConnections.back().indirectLeft = indirectLeft;
1213  myConnections.back().edgeType = edgeType;
1214  myConnections.back().changeLeft = changeLeft;
1215  myConnections.back().changeRight = changeRight;
1216  myConnections.back().speed = speed;
1217  myConnections.back().friction = friction;
1218  myConnections.back().customLength = length;
1219  myConnections.back().customShape = customShape;
1220  myConnections.back().uncontrolled = uncontrolled;
1221  if (type == Lane2LaneInfoType::USER) {
1223  } else {
1224  // check whether we have to take another look at it later
1225  if (type == Lane2LaneInfoType::COMPUTED) {
1226  // yes, the connection was set using an algorithm which requires a recheck
1228  } else {
1229  // ok, let's only not recheck it if we did no add something that has to be rechecked
1232  }
1233  }
1234  }
1235  if (postProcess) {
1236  // override earlier delete decision
1237  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end();) {
1238  if ((it->fromLane < 0 || it->fromLane == lane)
1239  && (it->toEdge == nullptr || it->toEdge == destEdge)
1240  && (it->toLane < 0 || it->toLane == destLane)) {
1241  it = myConnectionsToDelete.erase(it);
1242  } else {
1243  it++;
1244  }
1245  }
1246  }
1247  return true;
1248 }
1249 
1250 
1251 std::vector<NBEdge::Connection>
1252 NBEdge::getConnectionsFromLane(int lane, const NBEdge* to, int toLane) const {
1253  std::vector<NBEdge::Connection> ret;
1254  for (const Connection& c : myConnections) {
1255  if ((lane < 0 || c.fromLane == lane)
1256  && (to == nullptr || to == c.toEdge)
1257  && (toLane < 0 || toLane == c.toLane)) {
1258  ret.push_back(c);
1259  }
1260  }
1261  return ret;
1262 }
1263 
1264 
1265 const NBEdge::Connection&
1266 NBEdge::getConnection(int fromLane, const NBEdge* to, int toLane) const {
1267  for (const Connection& c : myConnections) {
1268  if (c.fromLane == fromLane && c.toEdge == to && c.toLane == toLane) {
1269  return c;
1270  }
1271  }
1272  throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1273  + " to " + to->getID() + "_" + toString(toLane) + " not found");
1274 }
1275 
1276 
1278 NBEdge::getConnectionRef(int fromLane, const NBEdge* to, int toLane) {
1279  for (Connection& c : myConnections) {
1280  if (c.fromLane == fromLane && c.toEdge == to && c.toLane == toLane) {
1281  return c;
1282  }
1283  }
1284  throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1285  + " to " + to->getID() + "_" + toString(toLane) + " not found");
1286 }
1287 
1288 
1289 bool
1290 NBEdge::hasConnectionTo(const NBEdge* destEdge, int destLane, int fromLane) const {
1291  return destEdge != nullptr && find_if(myConnections.begin(), myConnections.end(), connections_toedgelane_finder(destEdge, destLane, fromLane)) != myConnections.end();
1292 }
1293 
1294 
1295 bool
1296 NBEdge::isConnectedTo(const NBEdge* e, const bool ignoreTurnaround) const {
1297  if (!ignoreTurnaround && (e == myTurnDestination)) {
1298  return true;
1299  }
1300  return
1301  find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(e))
1302  !=
1303  myConnections.end();
1304 
1305 }
1306 
1307 
1308 const EdgeVector*
1310  // check whether connections exist and if not, use edges from the node
1311  EdgeVector outgoing;
1312  if (myConnections.size() == 0) {
1313  outgoing = myTo->getOutgoingEdges();
1314  } else {
1315  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1316  if (find(outgoing.begin(), outgoing.end(), (*i).toEdge) == outgoing.end()) {
1317  outgoing.push_back((*i).toEdge);
1318  }
1319  }
1320  }
1321  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
1322  if (it->fromLane < 0 && it->toLane < 0) {
1323  // found an edge that shall not be connected
1324  EdgeVector::iterator forbidden = std::find(outgoing.begin(), outgoing.end(), it->toEdge);
1325  if (forbidden != outgoing.end()) {
1326  outgoing.erase(forbidden);
1327  }
1328  }
1329  }
1330  // allocate the sorted container
1331  int size = (int) outgoing.size();
1332  EdgeVector* edges = new EdgeVector();
1333  edges->reserve(size);
1334  for (EdgeVector::const_iterator i = outgoing.begin(); i != outgoing.end(); i++) {
1335  NBEdge* outedge = *i;
1336  if (outedge != nullptr && outedge != myTurnDestination) {
1337  edges->push_back(outedge);
1338  }
1339  }
1340  std::sort(edges->begin(), edges->end(), NBContHelper::relative_outgoing_edge_sorter(this));
1341  return edges;
1342 }
1343 
1344 
1345 EdgeVector
1347  EdgeVector ret;
1348  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1349  if (find(ret.begin(), ret.end(), (*i).toEdge) == ret.end()) {
1350  ret.push_back((*i).toEdge);
1351  }
1352  }
1353  return ret;
1354 }
1355 
1356 
1357 EdgeVector
1359  EdgeVector ret;
1360  const EdgeVector& candidates = myFrom->getIncomingEdges();
1361  for (EdgeVector::const_iterator i = candidates.begin(); i != candidates.end(); i++) {
1362  if ((*i)->isConnectedTo(this)) {
1363  ret.push_back(*i);
1364  }
1365  }
1366  return ret;
1367 }
1368 
1369 
1370 std::vector<int>
1371 NBEdge::getConnectionLanes(NBEdge* currentOutgoing, bool withBikes) const {
1372  std::vector<int> ret;
1373  if (currentOutgoing != myTurnDestination) {
1374  for (const Connection& c : myConnections) {
1375  if (c.toEdge == currentOutgoing && (withBikes || getPermissions(c.fromLane) != SVC_BICYCLE)) {
1376  ret.push_back(c.fromLane);
1377  }
1378  }
1379  }
1380  return ret;
1381 }
1382 
1383 
1384 void
1387 }
1388 
1389 
1390 void
1392  sort(myConnections.begin(), myConnections.end(), connections_sorter);
1393 }
1394 
1395 
1396 void
1398  EdgeVector connected = getConnectedEdges();
1399  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
1400  NBEdge* inc = *i;
1401  // We have to do this
1403  // add all connections
1404  for (EdgeVector::iterator j = connected.begin(); j != connected.end(); j++) {
1405  inc->addEdge2EdgeConnection(*j);
1406  }
1407  inc->removeFromConnections(this);
1408  }
1409 }
1410 
1411 
1412 void
1413 NBEdge::removeFromConnections(NBEdge* toEdge, int fromLane, int toLane, bool tryLater, const bool adaptToLaneRemoval,
1414  const bool keepPossibleTurns) {
1415  // remove from "myConnections"
1416  const int fromLaneRemoved = adaptToLaneRemoval && fromLane >= 0 ? fromLane : -1;
1417  const int toLaneRemoved = adaptToLaneRemoval && toLane >= 0 ? toLane : -1;
1418  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1419  Connection& c = *i;
1420  if ((toEdge == nullptr || c.toEdge == toEdge)
1421  && (fromLane < 0 || c.fromLane == fromLane)
1422  && (toLane < 0 || c.toLane == toLane)) {
1423  if (myTo->isTLControlled()) {
1424  std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1425  for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1426  (*it)->removeConnection(NBConnection(this, c.fromLane, c.toEdge, c.toLane));
1427  }
1428  }
1429  i = myConnections.erase(i);
1430  tryLater = false;
1431  } else {
1432  if (fromLaneRemoved >= 0 && c.fromLane > fromLaneRemoved) {
1433  if (myTo->isTLControlled()) {
1434  std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1435  for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1436  for (NBConnectionVector::iterator tlcon = (*it)->getControlledLinks().begin(); tlcon != (*it)->getControlledLinks().end(); ++tlcon) {
1437  NBConnection& tc = *tlcon;
1438  if (tc.getTo() == c.toEdge && tc.getFromLane() == c.fromLane && tc.getToLane() == c.toLane) {
1439  tc.shiftLaneIndex(this, -1);
1440  }
1441  }
1442  }
1443  }
1444  //std::cout << getID() << " removeFromConnections fromLane=" << fromLane << " to=" << Named::getIDSecure(toEdge) << " toLane=" << toLane << " reduceFromLane=" << c.fromLane << " (to=" << c.toLane << ")\n";
1445  c.fromLane--;
1446  }
1447  if (toLaneRemoved >= 0 && c.toLane > toLaneRemoved && (toEdge == nullptr || c.toEdge == toEdge)) {
1448  //std::cout << getID() << " removeFromConnections fromLane=" << fromLane << " to=" << Named::getIDSecure(toEdge) << " toLane=" << toLane << " reduceToLane=" << c.toLane << " (from=" << c.fromLane << ")\n";
1449  c.toLane--;
1450  }
1451  ++i;
1452  }
1453  }
1454  // check whether it was the turn destination
1455  if (myTurnDestination == toEdge && fromLane < 0) {
1456  myTurnDestination = nullptr;
1457  }
1458  if (myPossibleTurnDestination == toEdge && fromLane < 0 && !keepPossibleTurns) {
1459  myPossibleTurnDestination = nullptr;
1460  }
1461  if (tryLater) {
1462  myConnectionsToDelete.push_back(Connection(fromLane, toEdge, toLane));
1463 #ifdef DEBUG_CONNECTION_GUESSING
1464  if (DEBUGCOND) {
1465  std::cout << "removeFromConnections " << getID() << "_" << fromLane << "->" << toEdge->getID() << "_" << toLane << "\n";
1466  for (Connection& c : myConnections) {
1467  std::cout << " conn " << c.getDescription(this) << "\n";
1468  }
1469  for (Connection& c : myConnectionsToDelete) {
1470  std::cout << " connToDelete " << c.getDescription(this) << "\n";
1471  }
1472  }
1473 #endif
1474  }
1475 }
1476 
1477 
1478 bool
1480  // iterate over connections
1481  for (auto i = myConnections.begin(); i != myConnections.end(); i++) {
1482  if ((i->toEdge == connectionToRemove.toEdge) && (i->fromLane == connectionToRemove.fromLane) && (i->toLane == connectionToRemove.toLane)) {
1483  // remove connection
1484  myConnections.erase(i);
1485  return true;
1486  }
1487  }
1488  // assert(false);
1489  return false;
1490 }
1491 
1492 
1493 void
1494 NBEdge::invalidateConnections(bool reallowSetting) {
1495  myTurnDestination = nullptr;
1496  myConnections.clear();
1497  if (reallowSetting) {
1499  } else {
1501  }
1502 }
1503 
1504 
1505 void
1506 NBEdge::replaceInConnections(NBEdge* which, NBEdge* by, int laneOff) {
1507  // replace in "_connectedEdges"
1508  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1509  if ((*i).toEdge == which) {
1510  (*i).toEdge = by;
1511  (*i).toLane += laneOff;
1512  }
1513  }
1514  // check whether it was the turn destination
1515  if (myTurnDestination == which) {
1516  myTurnDestination = by;
1517  }
1518 }
1519 
1520 void
1521 NBEdge::replaceInConnections(NBEdge* which, const std::vector<NBEdge::Connection>& origConns) {
1522  std::map<int, int> laneMap;
1523  int minLane = -1;
1524  int maxLane = -1;
1525  // get lanes used to approach the edge to remap
1526  bool wasConnected = false;
1527  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1528  if ((*i).toEdge != which) {
1529  continue;
1530  }
1531  wasConnected = true;
1532  if ((*i).fromLane != -1) {
1533  int fromLane = (*i).fromLane;
1534  laneMap[(*i).toLane] = fromLane;
1535  if (minLane == -1 || minLane > fromLane) {
1536  minLane = fromLane;
1537  }
1538  if (maxLane == -1 || maxLane < fromLane) {
1539  maxLane = fromLane;
1540  }
1541  }
1542  }
1543  if (!wasConnected) {
1544  return;
1545  }
1546  // add new connections
1547  std::vector<NBEdge::Connection> conns = origConns;
1548  EdgeVector origTargets = getSuccessors();
1549  for (std::vector<NBEdge::Connection>::iterator i = conns.begin(); i != conns.end(); ++i) {
1550  if ((*i).toEdge == which || (*i).toEdge == this
1551  // if we already have connections to the target edge, do not add new ones as they are probably from a circular replacement
1552  || std::find(origTargets.begin(), origTargets.end(), (*i).toEdge) != origTargets.end()) {
1553 #ifdef DEBUG_REPLACECONNECTION
1554  if (DEBUGCOND) {
1555  std::cout << " replaceInConnections edge=" << getID() << " which=" << which->getID()
1556  << " origTargets=" << toString(origTargets) << " newTarget=" << i->toEdge->getID() << " skipped\n";
1557  }
1558 #endif
1559  continue;
1560  }
1561  if (which->getStep() == EdgeBuildingStep::EDGE2EDGES) {
1562  // do not set lane-level connections
1563  replaceInConnections(which, (*i).toEdge, 0);
1564  continue;
1565  }
1566  int fromLane = (*i).fromLane;
1567  int toUse = -1;
1568  if (laneMap.find(fromLane) == laneMap.end()) {
1569  if (fromLane >= 0 && fromLane <= minLane) {
1570  toUse = minLane;
1571  // patch laneMap to avoid crossed-over connections
1572  for (auto& item : laneMap) {
1573  if (item.first < fromLane) {
1574  item.second = MIN2(item.second, minLane);
1575  }
1576  }
1577  }
1578  if (fromLane >= 0 && fromLane >= maxLane) {
1579  toUse = maxLane;
1580  // patch laneMap to avoid crossed-over connections
1581  for (auto& item : laneMap) {
1582  if (item.first > fromLane) {
1583  item.second = MAX2(item.second, maxLane);
1584  }
1585  }
1586  }
1587  } else {
1588  toUse = laneMap[fromLane];
1589  }
1590  if (toUse == -1) {
1591  toUse = 0;
1592  }
1593 #ifdef DEBUG_REPLACECONNECTION
1594  if (DEBUGCOND) {
1595  std::cout << " replaceInConnections edge=" << getID() << " which=" << which->getID() << " origTargets=" << toString(origTargets)
1596  << " origFrom=" << fromLane << " laneMap=" << joinToString(laneMap, ":", ",") << " minLane=" << minLane << " maxLane=" << maxLane
1597  << " newTarget=" << i->toEdge->getID() << " fromLane=" << toUse << " toLane=" << i->toLane << "\n";
1598  }
1599 #endif
1600  setConnection(toUse, i->toEdge, i->toLane, Lane2LaneInfoType::COMPUTED, false, i->mayDefinitelyPass, i->keepClear,
1601  i->contPos, i->visibility, i->speed, i->friction, i->customLength, i->customShape, i->uncontrolled);
1602  }
1603  // remove the remapped edge from connections
1604  removeFromConnections(which);
1605 }
1606 
1607 
1608 void
1610  myStep = src->myStep;
1612 }
1613 
1614 
1615 bool
1616 NBEdge::canMoveConnection(const Connection& con, int newFromLane) const {
1617  // only allow using newFromLane if at least 1 vClass is permitted to use
1618  // this connection. If the connection shall be moved to a sidewalk, only create the connection if there is no walking area
1619  const SVCPermissions common = (getPermissions(newFromLane) & con.toEdge->getPermissions(con.toLane));
1620  return (common > 0 && common != SVC_PEDESTRIAN);
1621 }
1622 
1623 
1624 void
1626  int index = 0;
1627  for (int i = 0; i < (int)myConnections.size(); ++i) {
1628  if (myConnections[i].fromLane == (int)(lane) && canMoveConnection(myConnections[i], lane + 1)) {
1629  index = i;
1630  }
1631  }
1632  std::vector<Connection>::iterator i = myConnections.begin() + index;
1633  Connection c = *i;
1634  myConnections.erase(i);
1635  setConnection(lane + 1, c.toEdge, c.toLane, Lane2LaneInfoType::VALIDATED, false);
1636 }
1637 
1638 
1639 void
1641  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1642  if ((*i).fromLane == (int)lane && canMoveConnection(*i, lane - 1)) {
1643  Connection c = *i;
1644  i = myConnections.erase(i);
1645  setConnection(lane - 1, c.toEdge, c.toLane, Lane2LaneInfoType::VALIDATED, false);
1646  return;
1647  }
1648  }
1649 }
1650 
1651 
1652 double
1653 NBEdge::buildInnerEdges(const NBNode& n, int noInternalNoSplits, int& linkIndex, int& splitIndex) {
1654  const OptionsCont& oc = OptionsCont::getOptions();
1655  const int numPoints = oc.getInt("junctions.internal-link-detail");
1656  const bool joinTurns = oc.getBool("junctions.join-turns");
1657  const double limitTurnSpeed = oc.getFloat("junctions.limit-turn-speed");
1658  const double limitTurnSpeedMinAngle = DEG2RAD(oc.getFloat("junctions.limit-turn-speed.min-angle"));
1659  const double limitTurnSpeedMinAngleRail = DEG2RAD(oc.getFloat("junctions.limit-turn-speed.min-angle.railway"));
1660  const double limitTurnSpeedWarnStraight = oc.getFloat("junctions.limit-turn-speed.warn.straight");
1661  const double limitTurnSpeedWarnTurn = oc.getFloat("junctions.limit-turn-speed.warn.turn");
1662  const bool higherSpeed = oc.getBool("junctions.higher-speed");
1663  const double interalJunctionVehicleWidth = oc.getFloat("internal-junctions.vehicle-width");
1664  const bool fromRail = isRailway(getPermissions());
1665  std::string innerID = ":" + n.getID();
1666  NBEdge* toEdge = nullptr;
1667  int edgeIndex = linkIndex;
1668  int internalLaneIndex = 0;
1669  int numLanes = 0; // number of lanes that share the same edge
1670  double lengthSum = 0; // total shape length of all lanes that share the same edge
1671  int avoidedIntersectingLeftOriginLane = std::numeric_limits<int>::max();
1672  bool averageLength = true;
1673  double maxCross = 0.;
1674  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1675  Connection& con = *i;
1676  con.haveVia = false; // reset first since this may be called multiple times
1677  if (con.toEdge == nullptr) {
1678  continue;
1679  }
1680  LinkDirection dir = n.getDirection(this, con.toEdge);
1681  const bool isRightTurn = (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT);
1682  const bool isTurn = (isRightTurn || dir == LinkDirection::LEFT || dir == LinkDirection::PARTLEFT);
1683  // put turning internal lanes on separate edges
1684  if (con.toEdge != toEdge) {
1685  // skip indices to keep some correspondence between edge ids and link indices:
1686  // internalEdgeIndex + internalLaneIndex = linkIndex
1687  edgeIndex = linkIndex;
1688  toEdge = con.toEdge;
1689  internalLaneIndex = 0;
1690  maxCross = MAX2(maxCross, assignInternalLaneLength(i, numLanes, lengthSum, averageLength));
1691  numLanes = 0;
1692  lengthSum = 0;
1693  }
1694  averageLength = !isTurn || joinTurns; // legacy behavior
1695  SVCPermissions conPermissions = getPermissions(con.fromLane) & con.toEdge->getPermissions(con.toLane);
1696  const int conShapeFlag = (conPermissions & ~SVC_PEDESTRIAN) != 0 ? 0 : NBNode::SCURVE_IGNORE;
1697  PositionVector shape = n.computeInternalLaneShape(this, con, numPoints, myTo, conShapeFlag);
1698  std::vector<int> foeInternalLinks;
1699 
1700  if (dir != LinkDirection::STRAIGHT && shape.length() < POSITION_EPS && !(isBidiRail() && getTurnDestination(true) == con.toEdge)) {
1701  WRITE_WARNINGF(TL("Connection '%_%->%_%' is only %m short."), getID(), con.fromLane, con.toEdge->getID(), con.toLane, shape.length());
1702  }
1703 
1704  // crossingPosition, list of foe link indices
1705  std::pair<double, std::vector<int> > crossingPositions(-1, std::vector<int>());
1706  std::set<std::string> tmpFoeIncomingLanes;
1707  if (dir != LinkDirection::STRAIGHT || con.contPos != UNSPECIFIED_CONTPOS) {
1708  int index = 0;
1709  std::vector<PositionVector> otherShapes;
1710  const double width1 = MIN2(interalJunctionVehicleWidth / 2, getLaneWidth(con.fromLane) / 2);
1711  const double width1OppositeLeft = 0; // using width1 changes a lot of curves even though they are rarely responsible for collisions
1712  for (const NBEdge* i2 : n.getIncomingEdges()) {
1713  for (const Connection& k2 : i2->getConnections()) {
1714  if (k2.toEdge == nullptr) {
1715  continue;
1716  }
1717  // vehicles are typically less wide than the lane
1718  // they drive on but but bicycle lanes should be kept clear for their whole width
1719  double width2 = k2.toEdge->getLaneWidth(k2.toLane);
1720  if (k2.toEdge->getPermissions(k2.toLane) != SVC_BICYCLE) {
1721  width2 *= 0.5;
1722  }
1723  const bool foes = n.foes(this, con.toEdge, i2, k2.toEdge);
1724  LinkDirection dir2 = n.getDirection(i2, k2.toEdge);
1725  bool needsCont = !isRailway(conPermissions) && (n.needsCont(this, i2, con, k2) || (con.contPos != UNSPECIFIED_CONTPOS && !con.indirectLeft));
1726  const bool avoidIntersectCandidate = !foes && bothLeftTurns(dir, i2, dir2);
1727  bool oppositeLeftIntersect = avoidIntersectCandidate && haveIntersection(n, shape, i2, k2, numPoints, width1OppositeLeft, width2);
1728  int shapeFlag = 0;
1730  // do not warn if only bicycles, pedestrians or delivery vehicles are involved as this is a typical occurrence
1731  if (con.customShape.size() == 0
1732  && k2.customShape.size() == 0
1733  && (oppositeLeftIntersect || (avoidedIntersectingLeftOriginLane < con.fromLane && avoidIntersectCandidate))
1734  && ((i2->getPermissions(k2.fromLane) & warn) != 0
1735  && (k2.toEdge->getPermissions(k2.toLane) & warn) != 0)) {
1736  // recompute with different curve parameters (unless
1737  // the other connection is "unimportant"
1739  PositionVector origShape = shape;
1740  shape = n.computeInternalLaneShape(this, con, numPoints, myTo, shapeFlag);
1741  oppositeLeftIntersect = haveIntersection(n, shape, i2, k2, numPoints, width1OppositeLeft, width2, shapeFlag);
1742  if (oppositeLeftIntersect
1743  && (conPermissions & (SVCAll & ~(SVC_BICYCLE | SVC_PEDESTRIAN))) == 0) {
1744  shape = origShape;
1745  } else {
1746  // recompute previously computed crossing positions
1747  if (avoidedIntersectingLeftOriginLane == std::numeric_limits<int>::max()
1748  || avoidedIntersectingLeftOriginLane < con.fromLane) {
1749  for (const PositionVector& otherShape : otherShapes) {
1750  const bool secondIntersection = con.indirectLeft && this == i2 && con.fromLane == k2.fromLane;
1751  const double minDV = firstIntersection(shape, otherShape, width1OppositeLeft, width2,
1752  "Could not compute intersection of conflicting internal lanes at node '" + myTo->getID() + "'", secondIntersection);
1753  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1754  assert(minDV >= 0);
1755  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1756  crossingPositions.first = minDV;
1757  }
1758  }
1759  }
1760  }
1761  // make sure connections further to the left do not get a wider angle
1762  avoidedIntersectingLeftOriginLane = con.fromLane;
1763  }
1764  }
1765  const bool bothPrio = getJunctionPriority(&n) > 0 && i2->getJunctionPriority(&n) > 0;
1766  //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";
1767  // the following special case might get obsolete once we have solved #9745
1768  const bool isBicycleLeftTurn = k2.indirectLeft || (dir2 == LinkDirection::LEFT && (i2->getPermissions(k2.fromLane) & k2.toEdge->getPermissions(k2.toLane)) == SVC_BICYCLE);
1769  // compute the crossing point
1770  if ((needsCont || (bothPrio && oppositeLeftIntersect && !isRailway(conPermissions))) && (!con.indirectLeft || dir2 == LinkDirection::STRAIGHT) && !isBicycleLeftTurn) {
1771  crossingPositions.second.push_back(index);
1772  const PositionVector otherShape = n.computeInternalLaneShape(i2, k2, numPoints, 0, shapeFlag);
1773  otherShapes.push_back(otherShape);
1774  const bool secondIntersection = con.indirectLeft && this == i2 && con.fromLane == k2.fromLane;
1775  const double minDV = firstIntersection(shape, otherShape, width1, width2,
1776  "Could not compute intersection of conflicting internal lanes at node '" + myTo->getID() + "'", secondIntersection);
1777  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1778  assert(minDV >= 0);
1779  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1780  crossingPositions.first = minDV;
1781  }
1782  }
1783  }
1784  const bool rightTurnConflict = NBNode::rightTurnConflict(
1785  this, con.toEdge, con.fromLane, i2, k2.toEdge, k2.fromLane);
1786  const bool indirectTurnConflit = con.indirectLeft && this == i2 && dir2 == LinkDirection::STRAIGHT;
1787  const bool mergeConflict = myTo->mergeConflict(this, con, i2, k2, true);
1788  const bool mergeResponse = myTo->mergeConflict(this, con, i2, k2, false);
1789  const bool bidiConflict = myTo->bidiConflict(this, con, i2, k2, true);
1790  // compute foe internal lanes
1791  if (foes || rightTurnConflict || oppositeLeftIntersect || mergeConflict || indirectTurnConflit || bidiConflict) {
1792  foeInternalLinks.push_back(index);
1793  }
1794  // only warn once per pair of intersecting turns
1795  if (oppositeLeftIntersect && getID() > i2->getID()
1796  && (getPermissions(con.fromLane) & warn) != 0
1797  && (con.toEdge->getPermissions(con.toLane) & warn) != 0
1798  && (i2->getPermissions(k2.fromLane) & warn) != 0
1799  && (k2.toEdge->getPermissions(k2.toLane) & warn) != 0
1800  // do not warn for unregulated nodes
1802  ) {
1803  WRITE_WARNINGF(TL("Intersecting left turns at junction '%' from lane '%' and lane '%' (increase junction radius to avoid this)."),
1804  n.getID(), getLaneID(con.fromLane), i2->getLaneID(k2.fromLane));
1805  }
1806  // compute foe incoming lanes
1807  const bool signalised = hasSignalisedConnectionTo(con.toEdge);
1808  if ((n.forbids(i2, k2.toEdge, this, con.toEdge, signalised) || rightTurnConflict || indirectTurnConflit || mergeResponse)
1809  && (needsCont || dir == LinkDirection::TURN || (!signalised && this != i2 && !con.indirectLeft))) {
1810  tmpFoeIncomingLanes.insert(i2->getID() + "_" + toString(k2.fromLane));
1811  }
1812  if (bothPrio && oppositeLeftIntersect && getID() < i2->getID()) {
1813  //std::cout << " c1=" << con.getDescription(this) << " c2=" << k2.getDescription(i2) << " bothPrio=" << bothPrio << " oppositeLeftIntersect=" << oppositeLeftIntersect << "\n";
1814  // break symmetry using edge id
1815  // only store link index and resolve actual lane id later (might be multi-lane internal edge)
1816  tmpFoeIncomingLanes.insert(":" + toString(index));
1817  }
1818  index++;
1819  }
1820  }
1821  if (dir == LinkDirection::TURN && crossingPositions.first < 0 && crossingPositions.second.size() != 0 && shape.length() > 2. * POSITION_EPS) {
1822  // let turnarounds wait in the middle if no other crossing point was found and it has a sensible length
1823  // (if endOffset is used, the crossing point is in the middle of the part within the junction shape)
1824  crossingPositions.first = (double)(shape.length() + getEndOffset(con.fromLane)) / 2.;
1825  }
1826  // foe pedestrian crossings
1827  std::vector<NBNode::Crossing*> crossings = n.getCrossings();
1828  for (auto c : crossings) {
1829  const NBNode::Crossing& crossing = *c;
1830  for (EdgeVector::const_iterator it_e = crossing.edges.begin(); it_e != crossing.edges.end(); ++it_e) {
1831  const NBEdge* edge = *it_e;
1832  // compute foe internal lanes
1833  if ((this == edge || con.toEdge == edge) && !isRailway(conPermissions)) {
1834  foeInternalLinks.push_back(index);
1835  if (con.toEdge == edge &&
1836  ((isRightTurn && getJunctionPriority(&n) > 0) || (isTurn && con.tlID != ""))) {
1837  // build internal junctions (not for left turns at uncontrolled intersections)
1838  PositionVector crossingShape = crossing.shape;
1839  crossingShape.extrapolate(5.0); // sometimes shapes miss each other by a small margin
1840  const double minDV = firstIntersection(shape, crossingShape, 0, crossing.width / 2);
1841  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) {
1842  assert(minDV >= 0);
1843  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1844  crossingPositions.first = minDV;
1845  }
1846  }
1847  } else if (this == edge && crossing.priority && !myTo->isTLControlled()) {
1848  crossingPositions.first = 0;
1849  }
1850  }
1851  }
1852  index++;
1853  }
1854 
1855  }
1856  if (con.contPos != UNSPECIFIED_CONTPOS) {
1857  // apply custom internal junction position
1858  if (con.contPos <= 0 || con.contPos >= shape.length()) {
1859  // disable internal junction
1860  crossingPositions.first = -1;
1861  } else {
1862  // set custom position
1863  crossingPositions.first = con.contPos;
1864  }
1865  }
1866 
1867  // @todo compute the maximum speed allowed based on angular velocity
1868  // see !!! for an explanation (with a_lat_mean ~0.3)
1869  /*
1870  double vmax = (double) 0.3 * (double) 9.80778 *
1871  getLaneShape(con.fromLane).back().distanceTo(
1872  con.toEdge->getLaneShape(con.toLane).front())
1873  / (double) 2.0 / (double) M_PI;
1874  vmax = MIN2(vmax, ((getSpeed() + con.toEdge->getSpeed()) / (double) 2.0));
1875  */
1876  if (con.speed == UNSPECIFIED_SPEED) {
1877  if (higherSpeed) {
1878  con.vmax = MAX2(myLanes[con.fromLane].speed, con.toEdge->getLanes()[con.toLane].speed);
1879  } else {
1880  con.vmax = (myLanes[con.fromLane].speed + con.toEdge->getLanes()[con.toLane].speed) / (double) 2.0;
1881  }
1882  if (limitTurnSpeed > 0) {
1883  // see [Odhams and Cole, Models of Driver Speed Choice in Curves, 2004]
1884  const double angleRaw = fabs(GeomHelper::angleDiff(
1885  getLaneShape(con.fromLane).angleAt2D(-2),
1886  con.toEdge->getLaneShape(con.toLane).angleAt2D(0)));
1887  const double angle = MAX2(0.0, angleRaw - (fromRail ? limitTurnSpeedMinAngleRail : limitTurnSpeedMinAngle));
1888  const double length = shape.length2D();
1889  // do not trust the radius of tiny junctions
1890  // formula adapted from [Odhams, Andre and Cole, David, Models of Driver Speed Choice in Curves, 2004]
1891  if (angle > 0 && length > 1) {
1892  // permit higher turning speed on wide lanes
1893  const double radius = length / angle + getLaneWidth(con.fromLane) / 4;
1894  const double limit = sqrt(limitTurnSpeed * radius);
1895  const double reduction = con.vmax - limit;
1896  // always treat connctions at roundabout as turns when warning
1897  const bool atRoundabout = getJunctionPriority(myTo) == JunctionPriority::ROUNDABOUT || con.toEdge->getJunctionPriority(myFrom) == JunctionPriority::ROUNDABOUT;
1898  const LinkDirection dir2 = atRoundabout ? LinkDirection::LEFT : dir;
1899  if ((dir2 == LinkDirection::STRAIGHT && reduction > limitTurnSpeedWarnStraight)
1900  || (dir2 != LinkDirection::TURN && reduction > limitTurnSpeedWarnTurn)) {
1901  std::string dirType = std::string(dir == LinkDirection::STRAIGHT ? "straight" : "turning");
1902  if (atRoundabout) {
1903  dirType = "roundabout";
1904  }
1905  WRITE_WARNINGF(TL("Speed of % connection '%' reduced by % due to turning radius of % (length=%, angle=%)."),
1906  dirType, con.getDescription(this), reduction, radius, length, RAD2DEG(angleRaw));
1907  }
1908  con.vmax = MIN2(con.vmax, limit);
1909  // value is saved in <net> attribute. Must be set again when importing from .con.xml
1910  // con.speed = con.vmax;
1911  }
1912  assert(con.vmax > 0);
1913  //if (getID() == "-1017000.0.00") {
1914  // std::cout << con.getDescription(this) << " angleRaw=" << angleRaw << " angle=" << RAD2DEG(angle) << " length=" << length << " radius=" << length / angle
1915  // << " vmaxTurn=" << sqrt(limitTurnSpeed * length / angle) << " vmax=" << con.vmax << "\n";
1916  //}
1917  } else if (fromRail && dir == LinkDirection::TURN) {
1918  con.vmax = 0.01;
1919  }
1920  } else {
1921  con.vmax = con.speed;
1922  }
1923  if (con.friction == UNSPECIFIED_FRICTION) {
1924  con.friction = (myLanes[con.fromLane].friction + con.toEdge->getLanes()[con.toLane].friction) / 2.;
1925  }
1926  //
1927  assert(shape.size() >= 2);
1928  // get internal splits if any
1929  con.id = innerID + "_" + toString(edgeIndex);
1930  const double shapeLength = shape.length();
1931  double firstLength = shapeLength;
1932  if (crossingPositions.first > 0 && crossingPositions.first < shapeLength) {
1933  std::pair<PositionVector, PositionVector> split = shape.splitAt(crossingPositions.first);
1934  con.shape = split.first;
1935  con.foeIncomingLanes = std::vector<std::string>(tmpFoeIncomingLanes.begin(), tmpFoeIncomingLanes.end());
1936  con.foeInternalLinks = foeInternalLinks; // resolve link indices to lane ids later
1937  con.viaID = innerID + "_" + toString(splitIndex + noInternalNoSplits);
1938  ++splitIndex;
1939  con.viaShape = split.second;
1940  con.haveVia = true;
1941  firstLength = con.shape.length();
1942  } else {
1943  con.shape = shape;
1944  }
1945  con.internalLaneIndex = internalLaneIndex;
1946  ++internalLaneIndex;
1947  ++linkIndex;
1948  ++numLanes;
1950  // split length proportionally
1951  lengthSum += firstLength / shapeLength * con.customLength;
1952  } else {
1953  lengthSum += firstLength;
1954  }
1955  }
1956  return MAX2(maxCross, assignInternalLaneLength(myConnections.end(), numLanes, lengthSum, averageLength));
1957 }
1958 
1959 
1960 double
1961 NBEdge::assignInternalLaneLength(std::vector<Connection>::iterator i, int numLanes, double lengthSum, bool averageLength) {
1962  // assign average length to all lanes of the same internal edge if averageLength is set
1963  // the lengthSum only covers the part up to the first internal junction
1964  // TODO This code assumes that either all connections in question have a via or none
1965  double maxCross = 0.;
1966  assert(i - myConnections.begin() >= numLanes);
1967  for (int prevIndex = 1; prevIndex <= numLanes; prevIndex++) {
1968  //std::cout << " con=" << (*(i - prevIndex)).getDescription(this) << " numLanes=" << numLanes << " avgLength=" << lengthSum / numLanes << "\n";
1969  Connection& c = (*(i - prevIndex));
1970  const double minLength = c.customLength != UNSPECIFIED_LOADED_LENGTH ? pow(10, -gPrecision) : POSITION_EPS;
1971  c.length = MAX2(minLength, averageLength ? lengthSum / numLanes : c.shape.length());
1972  if (c.haveVia) {
1973  c.viaLength = MAX2(minLength, c.viaShape.length());
1974  }
1976  if (c.haveVia) {
1977  // split length proportionally
1978  const double a = c.viaLength / (c.shape.length() + c.viaLength);
1979  c.viaLength = MAX2(minLength, a * c.customLength);
1980  }
1981  if (!averageLength) {
1982  c.length = MAX2(minLength, c.customLength - c.viaLength);
1983  }
1984  }
1985  if (c.haveVia) {
1986  // we need to be able to leave from the internal junction by accelerating from 0
1987  maxCross = MAX2(maxCross, sqrt(2. * c.viaLength)); // t = sqrt(2*s/a) and we assume 'a' is at least 1 (default value for tram in SUMOVTypeParameter)
1988  }
1989  // we need to be able to cross the junction in one go but not if we have an indirect left turn
1990  if (c.indirectLeft) {
1991  maxCross = MAX2(maxCross, MAX2(c.length, c.viaLength) / MAX2(c.vmax, NBOwnTLDef::MIN_SPEED_CROSSING_TIME));
1992  } else {
1993  maxCross = MAX2(maxCross, (c.length + c.viaLength) / MAX2(c.vmax, NBOwnTLDef::MIN_SPEED_CROSSING_TIME));
1994  }
1995  }
1996  return maxCross;
1997 }
1998 
1999 
2000 double
2001 NBEdge::firstIntersection(const PositionVector& v1, const PositionVector& v2, double width1, double width2, const std::string& error, bool secondIntersection) {
2002  double intersect = std::numeric_limits<double>::max();
2003  if (v2.length() < POSITION_EPS) {
2004  return intersect;
2005  }
2006  try {
2007  PositionVector v1Right = v1;
2008  v1Right.move2side(width1);
2009 
2010  PositionVector v1Left = v1;
2011  v1Left.move2side(-width1);
2012 
2013  PositionVector v2Right = v2;
2014  v2Right.move2side(width2);
2015 
2016  PositionVector v2Left = v2;
2017  v2Left.move2side(-width2);
2018 
2019  // intersect all border combinations
2020  bool skip = secondIntersection;
2021  for (double cand : v1Left.intersectsAtLengths2D(v2Right)) {
2022  if (skip) {
2023  skip = false;
2024  continue;
2025  }
2026  intersect = MIN2(intersect, cand);
2027  }
2028  skip = secondIntersection;
2029  for (double cand : v1Left.intersectsAtLengths2D(v2Left)) {
2030  if (skip) {
2031  skip = false;
2032  continue;
2033  }
2034  intersect = MIN2(intersect, cand);
2035  }
2036  skip = secondIntersection;
2037  for (double cand : v1Right.intersectsAtLengths2D(v2Right)) {
2038  if (skip) {
2039  skip = false;
2040  continue;
2041  }
2042  intersect = MIN2(intersect, cand);
2043  }
2044  skip = secondIntersection;
2045  for (double cand : v1Right.intersectsAtLengths2D(v2Left)) {
2046  if (skip) {
2047  skip = false;
2048  continue;
2049  }
2050  intersect = MIN2(intersect, cand);
2051  }
2052  } catch (InvalidArgument&) {
2053  if (error != "") {
2054  WRITE_WARNING(error);
2055  }
2056  }
2057  //std::cout << " v1=" << v1 << " v2Right=" << v2Right << " v2Left=" << v2Left << "\n";
2058  //std::cout << " intersectsRight=" << toString(v1.intersectsAtLengths2D(v2Right)) << "\n";
2059  //std::cout << " intersectsLeft=" << toString(v1.intersectsAtLengths2D(v2Left)) << "\n";
2060  return intersect;
2061 }
2062 
2063 
2064 bool
2065 NBEdge::bothLeftTurns(LinkDirection dir, const NBEdge* otherFrom, LinkDirection dir2) const {
2066  if (otherFrom == this) {
2067  // not an opposite pair
2068  return false;
2069  }
2070  return (dir == LinkDirection::LEFT || dir == LinkDirection::PARTLEFT) && (dir2 == LinkDirection::LEFT || dir2 == LinkDirection::PARTLEFT);
2071 }
2072 
2073 bool
2074 NBEdge::haveIntersection(const NBNode& n, const PositionVector& shape, const NBEdge* otherFrom, const NBEdge::Connection& otherCon, int numPoints,
2075  double width1, double width2, int shapeFlag) const {
2076  const PositionVector otherShape = n.computeInternalLaneShape(otherFrom, otherCon, numPoints, 0, shapeFlag);
2077  const double minDV = firstIntersection(shape, otherShape, width1, width2);
2078  return minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS;
2079 }
2080 
2081 
2082 // -----------
2083 int
2084 NBEdge::getJunctionPriority(const NBNode* const node) const {
2085  if (node == myFrom) {
2086  return myFromJunctionPriority;
2087  } else {
2088  return myToJunctionPriority;
2089  }
2090 }
2091 
2092 
2093 void
2094 NBEdge::setJunctionPriority(const NBNode* const node, int prio) {
2095  if (node == myFrom) {
2096  myFromJunctionPriority = prio;
2097 #ifdef DEBUG_JUNCTIONPRIO
2098  setParameter("fromPrio", toString(prio));
2099 #endif
2100  } else {
2101  myToJunctionPriority = prio;
2102 #ifdef DEBUG_JUNCTIONPRIO
2103  setParameter("toPrio", toString(prio));
2104 #endif
2105  }
2106 }
2107 
2108 
2109 double
2110 NBEdge::getAngleAtNode(const NBNode* const atNode) const {
2111  if (atNode == myFrom) {
2113  }
2114  assert(atNode == myTo);
2116 }
2117 
2118 
2119 double
2120 NBEdge::getAngleAtNodeNormalized(const NBNode* const atNode) const {
2121  double res;
2122  if (atNode == myFrom) {
2123  res = GeomHelper::legacyDegree(myGeom.angleAt2D(0)) - 180;
2124  } else {
2125  assert(atNode == myTo);
2127  }
2128  if (res < 0) {
2129  res += 360;
2130  }
2131  return res;
2132 }
2133 
2134 
2135 double
2136 NBEdge::getAngleAtNodeToCenter(const NBNode* const atNode) const {
2137  if (atNode == myFrom) {
2138  double res = myStartAngle - 180;
2139  if (res < 0) {
2140  res += 360;
2141  }
2142  return res;
2143  } else {
2144  assert(atNode == myTo);
2145  return myEndAngle;
2146  }
2147 }
2148 
2149 
2150 void
2151 NBEdge::setTurningDestination(NBEdge* e, bool onlyPossible) {
2152  if (!onlyPossible) {
2153  myTurnDestination = e;
2154  }
2156 }
2157 
2158 
2159 double
2160 NBEdge::getLaneSpeed(int lane) const {
2161  return myLanes[lane].speed;
2162 }
2163 
2164 
2165 double
2166 NBEdge::getLaneFriction(int lane) const {
2167  return myLanes[lane].friction;
2168 }
2169 
2170 
2171 void
2174 }
2175 
2176 
2177 void
2179  for (Lane& lane : myLanes) {
2180  if (lane.changeLeft != SVCAll) {
2181  lane.changeLeft = ignoring;
2182  }
2183  if (lane.changeRight != SVCAll) {
2184  lane.changeRight = ignoring;
2185  }
2186  }
2187  for (Connection& con : myConnections) {
2188  if (con.changeLeft != SVC_UNSPECIFIED && con.changeLeft != SVCAll) {
2189  con.changeLeft = ignoring;
2190  }
2191  if (con.changeRight != SVC_UNSPECIFIED && con.changeRight != SVCAll) {
2192  con.changeRight = ignoring;
2193  }
2194  }
2195 }
2196 
2197 
2198 void
2200  // vissim needs this
2201  if (myFrom == myTo) {
2202  return;
2203  }
2204  // compute lane offset, first
2205  std::vector<double> offsets(myLanes.size(), 0.);
2206  double offset = 0;
2207  for (int i = (int)myLanes.size() - 2; i >= 0; --i) {
2208  offset += (getLaneWidth(i) + getLaneWidth(i + 1)) / 2.;
2209  offsets[i] = offset;
2210  }
2212  double width = 0;
2213  for (int i = 0; i < (int)myLanes.size(); ++i) {
2214  width += getLaneWidth(i);
2215  }
2216  offset = -width / 2. + getLaneWidth((int)myLanes.size() - 1) / 2.;
2217  } else {
2218  double laneWidth = myLanes.back().width != UNSPECIFIED_WIDTH ? myLanes.back().width : SUMO_const_laneWidth;
2219  offset = laneWidth / 2.;
2220  }
2222  for (NBEdge* e : myTo->getOutgoingEdges()) {
2223  if (e->getToNode() == myFrom && getInnerGeometry().reverse() == e->getInnerGeometry()) {
2224  offset += (e->getTotalWidth() - getTotalWidth()) / 2;
2225  break;
2226  }
2227  }
2228  }
2229 
2230  for (int i = 0; i < (int)myLanes.size(); ++i) {
2231  offsets[i] += offset;
2232  }
2233 
2234  // build the shape of each lane
2235  for (int i = 0; i < (int)myLanes.size(); ++i) {
2236  if (myLanes[i].customShape.size() != 0) {
2237  myLanes[i].shape = myLanes[i].customShape;
2238  continue;
2239  }
2240  try {
2241  myLanes[i].shape = computeLaneShape(i, offsets[i]);
2242  } catch (InvalidArgument& e) {
2243  WRITE_WARNINGF(TL("In lane '%': lane shape could not be determined (%)."), getLaneID(i), e.what());
2244  myLanes[i].shape = myGeom;
2245  }
2246  }
2247 }
2248 
2249 
2251 NBEdge::computeLaneShape(int lane, double offset) const {
2252  PositionVector shape = myGeom;
2253  try {
2254  shape.move2side(offset);
2255  } catch (InvalidArgument& e) {
2256  WRITE_WARNINGF(TL("In lane '%': Could not build shape (%)."), getLaneID(lane), e.what());
2257  }
2258  return shape;
2259 }
2260 
2261 
2262 void
2264  // taking the angle at the first might be unstable, thus we take the angle
2265  // at a certain distance. (To compare two edges, additional geometry
2266  // segments are considered to resolve ambiguities)
2267  const bool hasFromShape = myFrom->getShape().size() > 0;
2268  const bool hasToShape = myTo->getShape().size() > 0;
2269  Position fromCenter = (hasFromShape ? myFrom->getShape().getCentroid() : myFrom->getPosition());
2270  Position toCenter = (hasToShape ? myTo->getShape().getCentroid() : myTo->getPosition());
2271  PositionVector shape = myGeom;
2272  if ((hasFromShape || hasToShape) && getNumLanes() > 0) {
2274  shape = myLanes[getNumLanes() - 1].shape ;
2275  } else {
2276  shape = myLanes[getNumLanes() / 2].shape;
2277  if (getNumLanes() % 2 == 0) {
2278  // there is no center lane. shift to get the center
2279  shape.move2side(getLaneWidth(getNumLanes() / 2) * 0.5);
2280  }
2281  }
2282  }
2283 
2284  // if the junction shape is suspicious we cannot trust the angle to the centroid
2285  const bool suspiciousFromShape = hasFromShape && (myFrom->getShape().distance2D(shape[0]) > 2 * POSITION_EPS
2286  || myFrom->getShape().around(shape[-1])
2287  || !(myFrom->getShape().around(fromCenter)));
2288  const bool suspiciousToShape = hasToShape && (myTo->getShape().distance2D(shape[-1]) > 2 * POSITION_EPS
2289  || myTo->getShape().around(shape[0])
2290  || !(myTo->getShape().around(toCenter)));
2291 
2292  const double angleLookahead = MIN2(shape.length2D() / 2, ANGLE_LOOKAHEAD);
2293  const Position referencePosStart = shape.positionAtOffset2D(angleLookahead);
2294  const Position referencePosEnd = shape.positionAtOffset2D(shape.length2D() - angleLookahead);
2295 
2296  myStartAngle = GeomHelper::legacyDegree(fromCenter.angleTo2D(referencePosStart), true);
2297  const double myStartAngle2 = GeomHelper::legacyDegree(myFrom->getPosition().angleTo2D(referencePosStart), true);
2298  const double myStartAngle3 = getAngleAtNode(myFrom);
2299  myEndAngle = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(toCenter), true);
2300  const double myEndAngle2 = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(myTo->getPosition()), true);
2301  const double myEndAngle3 = getAngleAtNode(myTo);
2302 
2303 #ifdef DEBUG_ANGLES
2304  if (DEBUGCOND) {
2305  if (suspiciousFromShape) {
2306  std::cout << "suspiciousFromShape len=" << shape.length() << " startA=" << myStartAngle << " startA2=" << myStartAngle2 << " startA3=" << myStartAngle3
2307  << " rel=" << NBHelpers::normRelAngle(myStartAngle, myStartAngle2)
2308  << " fromCenter=" << fromCenter
2309  << " fromPos=" << myFrom->getPosition()
2310  << " refStart=" << referencePosStart
2311  << "\n";
2312  }
2313  if (suspiciousToShape) {
2314  std::cout << "suspiciousToShape len=" << shape.length() << " endA=" << myEndAngle << " endA2=" << myEndAngle2 << " endA3=" << myEndAngle3
2315  << " rel=" << NBHelpers::normRelAngle(myEndAngle, myEndAngle2)
2316  << " toCenter=" << toCenter
2317  << " toPos=" << myTo->getPosition()
2318  << " refEnd=" << referencePosEnd
2319  << "\n";
2320  }
2321  }
2322 #endif
2323 
2324  if (suspiciousFromShape && shape.length() > 1) {
2325  myStartAngle = myStartAngle2;
2326  } else if (suspiciousToShape && fabs(NBHelpers::normRelAngle(myStartAngle, myStartAngle3)) > 90
2327  // don't trust footpath angles
2328  && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
2329  myStartAngle = myStartAngle3;
2330  if (myStartAngle < 0) {
2331  myStartAngle += 360;
2332  }
2333  }
2334 
2335  if (suspiciousToShape && shape.length() > 1) {
2336  myEndAngle = myEndAngle2;
2337  } else if (suspiciousToShape && fabs(NBHelpers::normRelAngle(myEndAngle, myEndAngle3)) > 90
2338  // don't trust footpath angles
2339  && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
2340  myEndAngle = myEndAngle3;
2341  if (myEndAngle < 0) {
2342  myEndAngle += 360;
2343  }
2344  }
2345 
2347 #ifdef DEBUG_ANGLES
2348  if (DEBUGCOND) std::cout << "computeAngle edge=" << getID()
2349  << " fromCenter=" << fromCenter << " toCenter=" << toCenter
2350  << " refStart=" << referencePosStart << " refEnd=" << referencePosEnd << " shape=" << shape
2351  << " hasFromShape=" << hasFromShape
2352  << " hasToShape=" << hasToShape
2353  << " numLanes=" << getNumLanes()
2354  << " shapeLane=" << getNumLanes() / 2
2355  << " startA=" << myStartAngle << " endA=" << myEndAngle << " totA=" << myTotalAngle << "\n";
2356 #endif
2357 }
2358 
2359 
2360 double
2362  const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
2363  const Position referencePosStart = myGeom.positionAtOffset2D(angleLookahead);
2364  return GeomHelper::legacyDegree(myGeom.front().angleTo2D(referencePosStart), true);
2365 }
2366 
2367 
2368 double
2370  const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
2371  const Position referencePosEnd = myGeom.positionAtOffset2D(myGeom.length2D() - angleLookahead);
2372  return GeomHelper::legacyDegree(referencePosEnd.angleTo2D(myGeom.back()), true);
2373 }
2374 
2375 
2376 bool
2378  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2379  if ((*i).permissions != SVCAll) {
2380  return true;
2381  }
2382  }
2383  return false;
2384 }
2385 
2386 
2387 bool
2389  std::vector<Lane>::const_iterator i = myLanes.begin();
2390  SVCPermissions firstLanePermissions = i->permissions;
2391  i++;
2392  for (; i != myLanes.end(); ++i) {
2393  if (i->permissions != firstLanePermissions) {
2394  return true;
2395  }
2396  }
2397  return false;
2398 }
2399 
2400 
2401 bool
2403  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2404  if (i->speed != getSpeed()) {
2405  return true;
2406  }
2407  }
2408  return false;
2409 }
2410 
2411 bool
2413  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2414  if (i->friction != myLanes.begin()->friction) {
2415  return true;
2416  }
2417  }
2418  return false;
2419 }
2420 
2421 bool
2423  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2424  if (i->width != myLanes.begin()->width) {
2425  return true;
2426  }
2427  }
2428  return false;
2429 }
2430 
2431 
2432 bool
2434  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2435  if (i->type != myLanes.begin()->type) {
2436  return true;
2437  }
2438  }
2439  return false;
2440 }
2441 
2442 
2443 bool
2445  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2446  if (i->endOffset != myLanes.begin()->endOffset) {
2447  return true;
2448  }
2449  }
2450  return false;
2451 }
2452 
2453 
2454 bool
2456  for (const auto& lane : myLanes) {
2457  if (lane.laneStopOffset.isDefined()) {
2458  if (myEdgeStopOffset.isDefined() || (myEdgeStopOffset != lane.laneStopOffset)) {
2459  return true;
2460  }
2461  }
2462  }
2463  return false;
2464 }
2465 
2466 
2467 bool
2469  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2470  if (i->accelRamp) {
2471  return true;
2472  }
2473  }
2474  return false;
2475 }
2476 
2477 
2478 bool
2480  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2481  if (i->customShape.size() > 0) {
2482  return true;
2483  }
2484  }
2485  return false;
2486 }
2487 
2488 
2489 bool
2491  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2492  if (i->getParametersMap().size() > 0) {
2493  return true;
2494  }
2495  }
2496  return false;
2497 }
2498 
2499 bool
2501  for (const Lane& lane : myLanes) {
2502  if (lane.changeLeft != SVCAll || lane.changeRight != SVCAll) {
2503  return true;
2504  }
2505  }
2506  return false;
2507 }
2508 
2509 bool
2511  return (hasLaneSpecificPermissions()
2514  || hasLaneSpecificType()
2517  || hasAccelLane()
2518  || hasCustomLaneShape()
2519  || hasLaneParams()
2520  || prohibitsChanging()
2521  || (!myLanes.empty() && myLanes.back().oppositeID != ""));
2522 }
2523 
2524 
2525 
2526 bool
2527 NBEdge::computeEdge2Edges(bool noLeftMovers) {
2528 #ifdef DEBUG_CONNECTION_GUESSING
2529  if (DEBUGCOND) {
2530  std::cout << "computeEdge2Edges edge=" << getID() << " step=" << (int)myStep << " noLeftMovers=" << noLeftMovers << "\n";
2531  for (Connection& c : myConnections) {
2532  std::cout << " conn " << c.getDescription(this) << "\n";
2533  }
2534  for (Connection& c : myConnectionsToDelete) {
2535  std::cout << " connToDelete " << c.getDescription(this) << "\n";
2536  }
2537  }
2538 #endif
2539  // return if this relationship has been build in previous steps or
2540  // during the import
2542  return true;
2543  }
2544  const bool fromRail = isRailway(getPermissions());
2545  for (NBEdge* out : myTo->getOutgoingEdges()) {
2546  if (noLeftMovers && myTo->isLeftMover(this, out)) {
2547  continue;
2548  }
2549  // avoid sharp railway turns
2550  if (fromRail && isRailway(out->getPermissions())) {
2551  const double angle = fabs(NBHelpers::normRelAngle(getAngleAtNode(myTo), out->getAngleAtNode(myTo)));
2552  if (angle > 150) {
2553  continue;
2554  } else if (angle > 90) {
2555  // possibly the junction is large enough to achieve a plausible radius:
2556  const PositionVector& fromShape = myLanes.front().shape;
2557  const PositionVector& toShape = out->getLanes().front().shape;
2558  PositionVector shape = myTo->computeSmoothShape(fromShape, toShape, 5, getTurnDestination() == out, 5, 5);
2559  const double radius = shape.length2D() / DEG2RAD(angle);
2560  const double minRadius = (getPermissions() & SVC_TRAM) != 0 ? 20 : 80;
2561  //std::cout << getID() << " to=" << out->getID() << " radius=" << radius << " minRadius=" << minRadius << "\n";
2562  if (radius < minRadius) {
2563  continue;
2564  }
2565  }
2566  }
2567  if (out == myTurnDestination) {
2568  // will be added by appendTurnaround
2569  continue;
2570  }
2571  if ((getPermissions() & out->getPermissions() & ~SVC_PEDESTRIAN) == 0) {
2572  // no common permissions
2573  continue;
2574  }
2575  myConnections.push_back(Connection(-1, out, -1));
2576  }
2578  return true;
2579 }
2580 
2581 
2582 bool
2584 #ifdef DEBUG_CONNECTION_GUESSING
2585  if (DEBUGCOND) {
2586  std::cout << "computeLanes2Edges edge=" << getID() << " step=" << (int)myStep << "\n";
2587  for (Connection& c : myConnections) {
2588  std::cout << " conn " << c.getDescription(this) << "\n";
2589  }
2590  for (Connection& c : myConnectionsToDelete) {
2591  std::cout << " connToDelete " << c.getDescription(this) << "\n";
2592  }
2593  }
2594 #endif
2595  // return if this relationship has been build in previous steps or
2596  // during the import
2598  return true;
2599  }
2601  // get list of possible outgoing edges sorted by direction clockwise
2602  // the edge in the backward direction (turnaround) is not in the list
2603  const EdgeVector* edges = getConnectedSorted();
2604  if (myConnections.size() != 0 && edges->size() == 0) {
2605  // dead end per definition!?
2606  myConnections.clear();
2607  } else {
2608  // divide the lanes on reachable edges
2609  divideOnEdges(edges);
2610  }
2611  delete edges;
2613  return true;
2614 }
2615 
2616 
2617 std::vector<LinkDirection>
2618 NBEdge::decodeTurnSigns(int turnSigns, int shift) {
2619  std::vector<LinkDirection> result;
2620  for (int i = 0; i < 8; i++) {
2621  // see LinkDirection in SUMOXMLDefinitions.h
2622  if ((turnSigns & (1 << (i + shift))) != 0) {
2623  result.push_back((LinkDirection)(1 << i));
2624  }
2625  }
2626  return result;
2627 }
2628 
2629 void
2630 NBEdge::updateTurnPermissions(SVCPermissions& perm, LinkDirection dir, SVCPermissions spec, std::vector<LinkDirection> dirs) {
2631  if (dirs.size() > 0) {
2632  if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) {
2633  perm &= ~spec;
2634  } else {
2635  perm |= spec;
2636  }
2637  }
2638 }
2639 
2640 bool
2642 #ifdef DEBUG_TURNSIGNS
2643  std::cout << "applyTurnSigns edge=" << getID() << "\n";
2644 #endif
2645  // build a map of target edges and lanes
2646  std::vector<const NBEdge*> targets;
2647  std::map<const NBEdge*, std::vector<int> > toLaneMap;
2648  for (const Connection& c : myConnections) {
2649  if (myLanes[c.fromLane].turnSigns != 0) {
2650  if (std::find(targets.begin(), targets.end(), c.toEdge) == targets.end()) {
2651  targets.push_back(c.toEdge);
2652  }
2653  toLaneMap[c.toEdge].push_back(c.toLane);
2654  }
2655  }
2656  // might be unsorted due to bike lane connections
2657  for (auto& item : toLaneMap) {
2658  std::sort(item.second.begin(), item.second.end());
2659  }
2660 
2661  // check number of distinct signed directions and count the number of signs for each direction
2662  std::map<LinkDirection, int> signCons;
2663  int allDirs = 0;
2664  for (const Lane& lane : myLanes) {
2665  allDirs |= lane.turnSigns;
2666  for (LinkDirection dir : decodeTurnSigns(lane.turnSigns)) {
2667  signCons[dir]++;
2668  }
2669  }
2670  allDirs |= allDirs >> TURN_SIGN_SHIFT_BUS;
2671  allDirs |= allDirs >> TURN_SIGN_SHIFT_TAXI;
2672  allDirs |= allDirs >> TURN_SIGN_SHIFT_BICYCLE;
2673 
2674  if ((allDirs & (int)LinkDirection::NODIR) != 0) {
2675  targets.push_back(nullptr); // dead end
2676  }
2677 
2678  SVCPermissions defaultPermissions = SVC_PASSENGER | SVC_DELIVERY;
2679  // build a mapping from sign directions to targets
2680  std::vector<LinkDirection> signedDirs = decodeTurnSigns(allDirs);
2681  std::map<LinkDirection, const NBEdge*> dirMap;
2682 #ifdef DEBUG_TURNSIGNS
2683  std::cout << " numDirs=" << signedDirs.size() << " numTargets=" << targets.size() << "\n";
2684 #endif
2685  if (signedDirs.size() > targets.size()) {
2686  WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed directions but only % targets"), getID(), signedDirs.size(), targets.size());
2687  return false;
2688  } else if (signedDirs.size() < targets.size()) {
2689  // we need to drop some targets (i.e. turn-around)
2690  // use sumo-directions as a guide
2691  std::vector<LinkDirection> sumoDirs;
2692  for (const NBEdge* to : targets) {
2693  sumoDirs.push_back(myTo->getDirection(this, to));
2694  }
2695  // remove targets to the left
2696  bool checkMore = true;
2697  while (signedDirs.size() < targets.size() && checkMore) {
2698  checkMore = false;
2699  //std::cout << getID() << " sumoDirs=" << joinToString(sumoDirs, ",") << " signedDirs=" << joinToString(signedDirs, ",") << "\n";
2700  if (sumoDirs.back() != signedDirs.back()) {
2701  targets.pop_back();
2702  sumoDirs.pop_back();
2703  checkMore = true;
2704  }
2705  }
2706  // remove targets to the right
2707  checkMore = true;
2708  while (signedDirs.size() < targets.size() && checkMore) {
2709  checkMore = false;
2710  if (sumoDirs.front() != signedDirs.front()) {
2711  targets.erase(targets.begin());
2712  sumoDirs.erase(sumoDirs.begin());
2713  checkMore = true;
2714  }
2715  }
2716  // remove targets by permissions
2717  int i = 0;
2718  while (signedDirs.size() < targets.size() && i < (int)targets.size()) {
2719  if (targets[i] != nullptr && (targets[i]->getPermissions() & defaultPermissions) == 0) {
2720  targets.erase(targets.begin() + i);
2721  sumoDirs.erase(sumoDirs.begin() + i);
2722  } else {
2723  i++;
2724  }
2725  }
2726  if (signedDirs.size() != targets.size()) {
2727  WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed directions and % targets (after target pruning)"), getID(), signedDirs.size(), targets.size());
2728  return false;
2729  }
2730  }
2731  // directions and connections are both sorted from right to left
2732  for (int i = 0; i < (int)signedDirs.size(); i++) {
2733  dirMap[signedDirs[i]] = targets[i];
2734  }
2735  // check whether we have enough target lanes for a each signed direction
2736  for (auto item : signCons) {
2737  const LinkDirection dir = item.first;
2738  if (dir == LinkDirection::NODIR) {
2739  continue;
2740  }
2741  const NBEdge* to = dirMap[dir];
2742  int candidates = to->getNumLanesThatAllow(defaultPermissions, false);
2743  if (candidates == 0) {
2744  WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because the target edge '%' has no suitable lanes"), getID(), to->getID());
2745  return false;
2746  }
2747  std::vector<int>& knownTargets = toLaneMap[to];
2748  if ((int)knownTargets.size() < item.second) {
2749  if (candidates < item.second) {
2750  WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed connections with directions '%' but target edge '%' has only % suitable lanes"),
2751  getID(), item.second, toString(dir), to->getID(), candidates);
2752  return false;
2753  }
2754  int i;
2755  int iInc;
2756  int iEnd;
2757  if (dir > LinkDirection::STRAIGHT) {
2758  // set more targets on the left
2759  i = to->getNumLanes() - 1;
2760  iInc = -1;
2761  iEnd = -1;
2762  } else {
2763  // set more targets on the right
2764  i = 0;
2765  iInc = 1;
2766  iEnd = to->getNumLanes();
2767  }
2768  while ((int)knownTargets.size() < item.second && i != iEnd) {
2769  if ((to->getPermissions(i) & defaultPermissions) != 0) {
2770  if (std::find(knownTargets.begin(), knownTargets.end(), i) == knownTargets.end()) {
2771  knownTargets.push_back(i);
2772  }
2773  }
2774  i += iInc;
2775  }
2776  if ((int)knownTargets.size() != item.second) {
2777  WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because not enough target lanes could be determined for direction '%'"), getID(), toString(dir));
2778  return false;
2779  }
2780  std::sort(knownTargets.begin(), knownTargets.end());
2781  }
2782  }
2783  std::map<const NBEdge*, int> toLaneIndex;
2784  for (int i = 0; i < getNumLanes(); i++) {
2785  const int turnSigns = myLanes[i].turnSigns;
2786  // no turnSigns are given for bicycle lanes and sidewalks
2787  if (turnSigns != 0) {
2788  // clear existing connections
2789  for (auto it = myConnections.begin(); it != myConnections.end();) {
2790  if (it->fromLane == i) {
2791  it = myConnections.erase(it);
2792  } else {
2793  it++;
2794  }
2795  }
2796  // add new connections
2797  int allSigns = (turnSigns
2798  | turnSigns >> TURN_SIGN_SHIFT_BUS
2799  | turnSigns >> TURN_SIGN_SHIFT_TAXI
2800  | turnSigns >> TURN_SIGN_SHIFT_BICYCLE);
2801  std::vector<LinkDirection> all = decodeTurnSigns(turnSigns);
2802  std::vector<LinkDirection> bus = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_BUS);
2803  std::vector<LinkDirection> taxi = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_TAXI);
2804  std::vector<LinkDirection> bike = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_BICYCLE);
2805  //std::cout << " allSigns=" << allSigns << " turnSigns=" << turnSigns << " bus=" << bus.size() << "\n";
2806  for (LinkDirection dir : decodeTurnSigns(allSigns)) {
2807  SVCPermissions perm = 0;
2808  updateTurnPermissions(perm, dir, SVCAll, all);
2809  updateTurnPermissions(perm, dir, SVC_BUS, bus);
2810  updateTurnPermissions(perm, dir, SVC_TAXI, taxi);
2811  updateTurnPermissions(perm, dir, SVC_BICYCLE, bike);
2812  if (perm == SVCAll) {
2813  perm = SVC_UNSPECIFIED;
2814  }
2815  //std::cout << " lane=" << i << " dir=" << toString(dir) << " perm=" << getVehicleClassNames(perm) << "\n";
2816  NBEdge* to = const_cast<NBEdge*>(dirMap[dir]);
2817  if (to != nullptr) {
2818  if (toLaneIndex.count(to) == 0) {
2819  // initialize to rightmost feasible lane
2820  SVCPermissions fromP = getPermissions(i);
2821  if ((fromP & SVC_PASSENGER) != 0) {
2822  // if the source permits passenger traffic, the target should too
2823  fromP = SVC_PASSENGER;
2824  }
2825  int toLane = toLaneMap[to][0];
2826  while ((to->getPermissions(toLane) & fromP) == 0 && (toLane + 1 < to->getNumLanes())) {
2827  toLane++;
2828  /*
2829  if (toLane == to->getNumLanes()) {
2830  SOFT_ASSERT(false);
2831  #ifdef DEBUG_TURNSIGNS
2832  std::cout << " could not find passenger lane for target=" << to->getID() << "\n";
2833  #endif
2834  return false;
2835  }
2836  */
2837  }
2838 #ifdef DEBUG_TURNSIGNS
2839  std::cout << " target=" << to->getID() << " initial toLane=" << toLane << "\n";
2840 #endif
2841  toLaneIndex[to] = toLane;
2842  }
2843  setConnection(i, to, toLaneIndex[to], Lane2LaneInfoType::VALIDATED, true,
2848  perm);
2849  if (toLaneIndex[to] < to->getNumLanes() - 1) {
2850  toLaneIndex[to]++;
2851  }
2852  }
2853  }
2854  }
2855  }
2858  return true;
2859 }
2860 
2861 
2862 bool
2864 #ifdef DEBUG_CONNECTION_GUESSING
2865  if (DEBUGCOND) {
2866  std::cout << "recheckLanes (initial) edge=" << getID() << "\n";
2867  for (Connection& c : myConnections) {
2868  std::cout << " conn " << c.getDescription(this) << "\n";
2869  }
2870  for (Connection& c : myConnectionsToDelete) {
2871  std::cout << " connToDelete " << c.getDescription(this) << "\n";
2872  }
2873  }
2874 #endif
2875  // check delayed removals
2876  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
2877  removeFromConnections(it->toEdge, it->fromLane, it->toLane, false, false, true);
2878  }
2879  std::vector<int> connNumbersPerLane(myLanes.size(), 0);
2880  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
2881  if ((*i).toEdge == nullptr || (*i).fromLane < 0 || (*i).toLane < 0) {
2882  i = myConnections.erase(i);
2883  } else {
2884  if ((*i).fromLane >= 0) {
2885  ++connNumbersPerLane[(*i).fromLane];
2886  }
2887  ++i;
2888  }
2889  }
2891 #ifdef DEBUG_TURNSIGNS
2892  if (myLanes.back().turnSigns != 0) {
2893  std::cout << getID() << " hasTurnSigns\n";
2894  if (myTurnSignTarget != myTo->getID()) {
2895  std::cout << " tst=" << myTurnSignTarget << " to=" << myTo->getID() << "\n";
2896  }
2897  }
2898 #endif
2899  if (myLanes.back().turnSigns == 0 || myTurnSignTarget != myTo->getID() || !applyTurnSigns()) {
2900  // check #1:
2901  // If there is a lane with no connections and any neighbour lane has
2902  // more than one connections, try to move one of them.
2903  // This check is only done for edges which connections were assigned
2904  // using the standard algorithm.
2905  for (int i = 0; i < (int)myLanes.size(); i++) {
2906  if (connNumbersPerLane[i] == 0 && !isForbidden(getPermissions(i) & ~SVC_PEDESTRIAN)) {
2907  // dead-end lane found
2908  bool hasDeadEnd = true;
2909  // find lane with two connections or more to the right of the current lane
2910  for (int i2 = i - 1; hasDeadEnd && i2 >= 0; i2--) {
2911  if (getPermissions(i) != getPermissions(i2)) {
2912  break;
2913  }
2914  if (connNumbersPerLane[i2] > 1) {
2915  connNumbersPerLane[i2]--;
2916  for (int i3 = i2; i3 != i; i3++) {
2920  }
2921  hasDeadEnd = false;
2922  }
2923  }
2924  if (hasDeadEnd) {
2925  // find lane with two connections or more to the left of the current lane
2926  for (int i2 = i + 1; hasDeadEnd && i2 < getNumLanes(); i2++) {
2927  if (getPermissions(i) != getPermissions(i2)) {
2928  break;
2929  }
2930  if (connNumbersPerLane[i2] > 1) {
2931  connNumbersPerLane[i2]--;
2932  for (int i3 = i2; i3 != i; i3--) {
2936  }
2937  hasDeadEnd = false;
2938  }
2939  }
2940  }
2941  if (hasDeadEnd && myTo->getOutgoingEdges().size() > 1) {
2942  int passengerLanes = 0;
2943  int passengerTargetLanes = 0;
2944  for (const Lane& lane : myLanes) {
2945  if ((lane.permissions & SVC_PASSENGER) != 0) {
2946  passengerLanes++;
2947  }
2948  }
2949  for (const NBEdge* out : myTo->getOutgoingEdges()) {
2950  if (!isTurningDirectionAt(out)) {
2951  for (const Lane& lane : out->getLanes()) {
2952  if ((lane.permissions & SVC_PASSENGER) != 0) {
2953  passengerTargetLanes++;
2954  }
2955  }
2956  }
2957  }
2958  if (passengerLanes > 0 && passengerLanes <= passengerTargetLanes) {
2959  // no need for dead-ends
2960  if (i > 0) {
2961  // check if a connection to the right has a usable target to the left of its target
2962  std::vector<Connection> rightCons = getConnectionsFromLane(i - 1);
2963  if (rightCons.size() > 0) {
2964  const Connection& rc = rightCons.back();
2965  NBEdge* to = rc.toEdge;
2966  int toLane = rc.toLane + 1;
2967  if (toLane < to->getNumLanes()
2968  && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
2969  && !hasConnectionTo(to, toLane)) {
2971  hasDeadEnd = false;
2974  }
2975  if (hasDeadEnd) {
2976  // check if a connection to the right has a usable target to the right of its target
2977  toLane = rc.toLane - 1;
2978  if (toLane >= 0
2979  && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(rc.toLane)) != 0
2980  && (getPermissions(rc.fromLane) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
2981  && !hasConnectionTo(to, toLane)) {
2982  // shift the right lane connection target right and connect the dead lane to the old target
2983  getConnectionRef(rc.fromLane, to, rc.toLane).toLane = toLane;
2984  setConnection(i, to, toLane + 1, Lane2LaneInfoType::COMPUTED);
2985  hasDeadEnd = false;
2988  }
2989  }
2990  }
2991  }
2992  if (hasDeadEnd && i < getNumLanes() - 1) {
2993  // check if a connection to the left has a usable target to the right of its target
2994  std::vector<Connection> leftCons = getConnectionsFromLane(i + 1);
2995  if (leftCons.size() > 0) {
2996  NBEdge* to = leftCons.front().toEdge;
2997  int toLane = leftCons.front().toLane - 1;
2998  if (toLane >= 0
2999  && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
3000  && !hasConnectionTo(to, toLane)) {
3002  hasDeadEnd = false;
3005  }
3006  }
3007  }
3008 #ifdef ADDITIONAL_WARNINGS
3009  if (hasDeadEnd) {
3010  WRITE_WARNING("Found dead-end lane " + getLaneID(i));
3011  }
3012 #endif
3013  }
3014  }
3015  }
3016  }
3017  // check restrictions
3018  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
3019  Connection& c = *i;
3021  if (common == SVC_PEDESTRIAN || getPermissions(c.fromLane) == SVC_PEDESTRIAN) {
3022  // these are computed in NBNode::buildWalkingAreas
3023  i = myConnections.erase(i);
3024  } else if (common == 0) {
3025  // no common permissions.
3026  // try to find a suitable target lane to the right
3027  const int origToLane = c.toLane;
3028  c.toLane = -1; // ignore this connection when calling hasConnectionTo
3029  int toLane = origToLane;
3030  while (toLane > 0
3031  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
3032  && !hasConnectionTo(c.toEdge, toLane)
3033  ) {
3034  toLane--;
3035  }
3036  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
3037  && !hasConnectionTo(c.toEdge, toLane)) {
3038  c.toLane = toLane;
3039  ++i;
3040  } else {
3041  // try to find a suitable target lane to the left
3042  toLane = origToLane;
3043  while (toLane < (int)c.toEdge->getNumLanes() - 1
3044  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
3045  && !hasConnectionTo(c.toEdge, toLane)
3046  ) {
3047  toLane++;
3048  }
3049  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
3050  && !hasConnectionTo(c.toEdge, toLane)) {
3051  c.toLane = toLane;
3052  ++i;
3053  } else {
3054  // no alternative target found
3055  i = myConnections.erase(i);
3056  }
3057  }
3059  && isTurningDirectionAt(c.toEdge)) {
3060  // do not allow sharp rail turns
3061  i = myConnections.erase(i);
3062  } else {
3063  ++i;
3064  }
3065  }
3066  }
3067  }
3068  // check involuntary dead end at "real" junctions
3069  if (getPermissions() != SVC_PEDESTRIAN) {
3070  if (myConnections.empty() && myTo->getOutgoingEdges().size() > 1 && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
3071  WRITE_WARNINGF(TL("Edge '%' is not connected to outgoing edges at junction '%'."), getID(), myTo->getID());
3072  }
3073  const EdgeVector& incoming = myFrom->getIncomingEdges();
3074  if (incoming.size() > 1) {
3075  for (int i = 0; i < (int)myLanes.size(); i++) {
3076  if (getPermissions(i) != 0 && getPermissions(i) != SVC_PEDESTRIAN) {
3077  bool connected = false;
3078  for (std::vector<NBEdge*>::const_iterator in = incoming.begin(); in != incoming.end(); ++in) {
3079  if ((*in)->hasConnectionTo(this, i)) {
3080  connected = true;
3081  break;
3082  }
3083  }
3084  if (!connected) {
3085  WRITE_WARNINGF(TL("Lane '%' is not connected from any incoming edge at junction '%'."), getLaneID(i), myFrom->getID());
3086  }
3087  }
3088  }
3089  }
3090  }
3091  // avoid deadend due to change prohibitions
3092  if (getNumLanes() > 1 && myConnections.size() > 0) {
3093  for (int i = 0; i < (int)myLanes.size(); i++) {
3094  Lane& lane = myLanes[i];
3095  if ((connNumbersPerLane[i] == 0 || ((lane.accelRamp || (i > 0 && myLanes[i - 1].accelRamp && connNumbersPerLane[i - 1] > 0))
3096  && getSuccessors(SVC_PASSENGER).size() > 1))
3098  const bool forbiddenLeft = lane.changeLeft != SVCAll && lane.changeLeft != SVC_IGNORING && lane.changeLeft != SVC_UNSPECIFIED;
3099  const bool forbiddenRight = lane.changeRight != SVCAll && lane.changeRight != SVC_IGNORING && lane.changeRight != SVC_UNSPECIFIED;
3100  if (forbiddenLeft && (i == 0 || forbiddenRight)) {
3101  lane.changeLeft = SVC_UNSPECIFIED;
3102  WRITE_WARNINGF(TL("Ignoring changeLeft prohibition for '%' to avoid dead-end"), getLaneID(i));
3103  } else if (forbiddenRight && (i == getNumLanes() - 1 || (i > 0 && myLanes[i - 1].accelRamp))) {
3105  WRITE_WARNINGF(TL("Ignoring changeRight prohibition for '%' to avoid dead-end"), getLaneID(i));
3106  }
3107  }
3108  }
3109  }
3110 #ifdef ADDITIONAL_WARNINGS
3111  // check for connections with bad access permissions
3112  for (const Connection& c : myConnections) {
3113  SVCPermissions fromP = getPermissions(c.fromLane);
3114  SVCPermissions toP = c.toEdge->getPermissions(c.toLane);
3115  if ((fromP & SVC_PASSENGER) != 0
3116  && toP == SVC_BICYCLE) {
3117  bool hasAlternative = false;
3118  for (const Connection& c2 : myConnections) {
3119  if (c.fromLane == c2.fromLane && c.toEdge == c2.toEdge
3120  && (c.toEdge->getPermissions(c2.toLane) & SVC_PASSENGER) != 0) {
3121  hasAlternative = true;
3122  }
3123  }
3124  if (!hasAlternative) {
3125  WRITE_WARNING("Road lane ends on bikeLane for connection " + c.getDescription(this));
3126  }
3127  }
3128  }
3129 
3130 #endif
3131 #ifdef DEBUG_CONNECTION_GUESSING
3132  if (DEBUGCOND) {
3133  std::cout << "recheckLanes (final) edge=" << getID() << "\n";
3134  for (Connection& c : myConnections) {
3135  std::cout << " conn " << c.getDescription(this) << "\n";
3136  }
3137  }
3138 #endif
3139  return true;
3140 }
3141 
3142 
3143 void
3145  if (outgoing->size() == 0) {
3146  // we have to do this, because the turnaround may have been added before
3147  myConnections.clear();
3148  return;
3149  }
3150 
3151 #ifdef DEBUG_CONNECTION_GUESSING
3152  if (DEBUGCOND) {
3153  std::cout << " divideOnEdges " << getID() << " outgoing=" << toString(*outgoing) << "\n";
3154  }
3155 #endif
3156 
3157  // build connections for miv lanes
3158  std::vector<int> availableLanes;
3159  for (int i = 0; i < (int)myLanes.size(); ++i) {
3160  if ((getPermissions(i) & SVC_PASSENGER) != 0) {
3161  availableLanes.push_back(i);
3162  }
3163  }
3164  if (availableLanes.size() > 0) {
3165  divideSelectedLanesOnEdges(outgoing, availableLanes);
3166  }
3167  // build connections for miscellaneous further modes (more than bike,peds,bus and without passenger)
3168  availableLanes.clear();
3169  for (int i = 0; i < (int)myLanes.size(); ++i) {
3170  const SVCPermissions perms = getPermissions(i);
3171  if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) == 0 || (perms & SVC_PASSENGER) != 0 || isForbidden(perms)) {
3172  continue;
3173  }
3174  availableLanes.push_back(i);
3175  }
3176  if (availableLanes.size() > 0) {
3177  divideSelectedLanesOnEdges(outgoing, availableLanes);
3178  }
3179  // build connections for busses from lanes that were excluded in the previous step
3180  availableLanes.clear();
3181  for (int i = 0; i < (int)myLanes.size(); ++i) {
3182  const SVCPermissions perms = getPermissions(i);
3183  if ((perms & SVC_BUS) == 0 || (perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) != 0 || (perms & SVC_PASSENGER) != 0) {
3184  continue;
3185  }
3186  availableLanes.push_back(i);
3187  }
3188  if (availableLanes.size() > 0) {
3189  divideSelectedLanesOnEdges(outgoing, availableLanes);
3190  }
3191  // build connections for bicycles (possibly combined with pedestrians)
3192  availableLanes.clear();
3193  for (int i = 0; i < (int)myLanes.size(); ++i) {
3194  const SVCPermissions perms = getPermissions(i);
3195  if (perms != SVC_BICYCLE && perms != (SVC_BICYCLE | SVC_PEDESTRIAN)) {
3196  continue;
3197  }
3198  availableLanes.push_back(i);
3199  }
3200  if (availableLanes.size() > 0) {
3201  divideSelectedLanesOnEdges(outgoing, availableLanes);
3202  }
3203  // clean up unassigned fromLanes
3204  bool explicitTurnaround = false;
3205  SVCPermissions turnaroundPermissions = SVC_UNSPECIFIED;
3206  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
3207  if ((*i).fromLane == -1) {
3208  if ((*i).toEdge == myTurnDestination && myTurnDestination != nullptr) {
3209  explicitTurnaround = true;
3210  turnaroundPermissions = (*i).permissions;
3211  }
3212  if ((*i).permissions != SVC_UNSPECIFIED) {
3213  for (Connection& c : myConnections) {
3214  if (c.toLane == -1 && c.toEdge == (*i).toEdge) {
3215  // carry over loaded edge2edge permissions
3216  c.permissions = (*i).permissions;
3217  }
3218  }
3219  }
3220  i = myConnections.erase(i);
3221  } else {
3222  ++i;
3223  }
3224  }
3225  if (explicitTurnaround) {
3226  myConnections.push_back(Connection((int)myLanes.size() - 1, myTurnDestination, myTurnDestination->getNumLanes() - 1));
3227  myConnections.back().permissions = turnaroundPermissions;
3228  }
3230 }
3231 
3232 
3233 void
3234 NBEdge::divideSelectedLanesOnEdges(const EdgeVector* outgoing, const std::vector<int>& availableLanes) {
3235  const std::vector<int>& priorities = prepareEdgePriorities(outgoing, availableLanes);
3236  if (priorities.empty()) {
3237  return;
3238  }
3239 #ifdef DEBUG_CONNECTION_GUESSING
3240  if (DEBUGCOND) {
3241  std::cout << "divideSelectedLanesOnEdges " << getID() << " out=" << toString(*outgoing) << " prios=" << toString(priorities) << " avail=" << toString(availableLanes) << "\n";
3242  }
3243 #endif
3244  // compute the resulting number of lanes that should be used to reach the following edge
3245  const int numOutgoing = (int)outgoing->size();
3246  std::vector<int> resultingLanesFactor;
3247  resultingLanesFactor.reserve(numOutgoing);
3248  int minResulting = std::numeric_limits<int>::max();
3249  for (int i = 0; i < numOutgoing; i++) {
3250  // res / minResulting will be the number of lanes which are meant to reach the current outgoing edge
3251  const int res = priorities[i] * (int)availableLanes.size();
3252  resultingLanesFactor.push_back(res);
3253  if (minResulting > res && res > 0) {
3254  // prevent minResulting from becoming 0
3255  minResulting = res;
3256  }
3257  }
3258  // compute the number of virtual edges
3259  // a virtual edge is used as a replacement for a real edge from now on
3260  // it shall allow to divide the existing lanes on this structure without
3261  // regarding the structure of outgoing edges
3262  int numVirtual = 0;
3263  // compute the transition from virtual to real edges
3264  EdgeVector transition;
3265  transition.reserve(numOutgoing);
3266  for (int i = 0; i < numOutgoing; i++) {
3267  // tmpNum will be the number of connections from this edge to the next edge
3268  assert(i < (int)resultingLanesFactor.size());
3269  const int tmpNum = (resultingLanesFactor[i] + minResulting - 1) / minResulting; // integer division rounding up
3270  numVirtual += tmpNum;
3271  for (int j = 0; j < tmpNum; j++) {
3272  transition.push_back((*outgoing)[i]);
3273  }
3274  }
3275 #ifdef DEBUG_CONNECTION_GUESSING
3276  if (DEBUGCOND) {
3277  std::cout << " minResulting=" << minResulting << " numVirtual=" << numVirtual << " availLanes=" << toString(availableLanes) << " resLanes=" << toString(resultingLanesFactor) << " transition=" << toString(transition) << "\n";
3278  }
3279 #endif
3280 
3281  // assign lanes to edges
3282  // (conversion from virtual to real edges is done)
3283  ToEdgeConnectionsAdder adder(transition);
3284  Bresenham::compute(&adder, static_cast<int>(availableLanes.size()), numVirtual);
3285  const std::map<NBEdge*, std::vector<int> >& l2eConns = adder.getBuiltConnections();
3286  for (NBEdge* const target : *outgoing) {
3287  assert(l2eConns.find(target) != l2eConns.end());
3288  for (const int j : l2eConns.find(target)->second) {
3289  const int fromIndex = availableLanes[j];
3290  if ((getPermissions(fromIndex) & target->getPermissions()) == 0) {
3291  // exclude connection if fromLane and toEdge have no common permissions
3292  continue;
3293  }
3294  if ((getPermissions(fromIndex) & target->getPermissions()) == SVC_PEDESTRIAN) {
3295  // exclude connection if the only commonly permitted class are pedestrians
3296  // these connections are later built in NBNode::buildWalkingAreas
3297  continue;
3298  }
3299  // avoid building more connections than the edge has viable lanes (earlier
3300  // ones have precedence). This is necessary when running divideSelectedLanesOnEdges more than once.
3301  // @todo To decide which target lanes are still available we need to do a
3302  // preliminary lane-to-lane assignment in regard to permissions (rather than to ordering)
3303  const int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
3304  int targetLanes = target->getNumLanes();
3305  if (target->getPermissions(0) == SVC_PEDESTRIAN) {
3306  --targetLanes;
3307  }
3308  if (numConsToTarget >= targetLanes) {
3309  continue;
3310  }
3311  if (myLanes[fromIndex].connectionsDone) {
3312  // we already have complete information about connections from
3313  // this lane. do not add anything else
3314 #ifdef DEBUG_CONNECTION_GUESSING
3315  if (DEBUGCOND) {
3316  std::cout << " connectionsDone from " << getID() << "_" << fromIndex << ": ";
3317  for (const Connection& c : getConnectionsFromLane(fromIndex)) {
3318  std::cout << c.getDescription(this) << ", ";
3319  }
3320  std::cout << "\n";
3321  }
3322 #endif
3323  continue;
3324  }
3325  myConnections.push_back(Connection(fromIndex, target, -1));
3326 #ifdef DEBUG_CONNECTION_GUESSING
3327  if (DEBUGCOND) {
3328  std::cout << " request connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3329  }
3330 #endif
3331  }
3332  }
3333 
3334  addStraightConnections(outgoing, availableLanes, priorities);
3335 }
3336 
3337 
3338 void
3339 NBEdge::addStraightConnections(const EdgeVector* outgoing, const std::vector<int>& availableLanes, const std::vector<int>& priorities) {
3340  // ensure sufficient straight connections for the (highest-priority) straight target
3341  const int numOutgoing = (int) outgoing->size();
3342  NBEdge* target = nullptr;
3343  NBEdge* rightOfTarget = nullptr;
3344  NBEdge* leftOfTarget = nullptr;
3345  int maxPrio = 0;
3346  for (int i = 0; i < numOutgoing; i++) {
3347  if (maxPrio < priorities[i]) {
3348  const LinkDirection dir = myTo->getDirection(this, (*outgoing)[i]);
3349  if (dir == LinkDirection::STRAIGHT) {
3350  maxPrio = priorities[i];
3351  target = (*outgoing)[i];
3352  rightOfTarget = i == 0 ? outgoing->back() : (*outgoing)[i - 1];
3353  leftOfTarget = i + 1 == numOutgoing ? outgoing->front() : (*outgoing)[i + 1];
3354  }
3355  }
3356  }
3357  if (target == nullptr) {
3358  return;
3359  }
3360  int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
3361  int targetLanes = (int)target->getNumLanes();
3362  if (target->getPermissions(0) == SVC_PEDESTRIAN) {
3363  --targetLanes;
3364  }
3365  const int numDesiredConsToTarget = MIN2(targetLanes, (int)availableLanes.size());
3366 #ifdef DEBUG_CONNECTION_GUESSING
3367  if (DEBUGCOND) {
3368  std::cout << " checking extra lanes for target=" << target->getID() << " cons=" << numConsToTarget << " desired=" << numDesiredConsToTarget << "\n";
3369  }
3370 #endif
3371  std::vector<int>::const_iterator it_avail = availableLanes.begin();
3372  while (numConsToTarget < numDesiredConsToTarget && it_avail != availableLanes.end()) {
3373  const int fromIndex = *it_avail;
3374  if (
3375  // not yet connected
3376  (count_if(myConnections.begin(), myConnections.end(), connections_finder(fromIndex, target, -1)) == 0)
3377  // matching permissions
3378  && ((getPermissions(fromIndex) & target->getPermissions()) != 0)
3379  // more than pedestrians
3380  && ((getPermissions(fromIndex) & target->getPermissions()) != SVC_PEDESTRIAN)
3381  // lane not yet fully defined
3382  && !myLanes[fromIndex].connectionsDone
3383  ) {
3384 #ifdef DEBUG_CONNECTION_GUESSING
3385  if (DEBUGCOND) {
3386  std::cout << " candidate from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3387  }
3388 #endif
3389  // prevent same-edge conflicts
3390  if (
3391  // no outgoing connections to the right from further left
3392  ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
3393  // no outgoing connections to the left from further right
3394  && (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)) {
3395 #ifdef DEBUG_CONNECTION_GUESSING
3396  if (DEBUGCOND) {
3397  std::cout << " request additional connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3398  }
3399 #endif
3400  myConnections.push_back(Connection(fromIndex, target, -1));
3401  numConsToTarget++;
3402  } else {
3403 #ifdef DEBUG_CONNECTION_GUESSING
3404  if (DEBUGCOND) std::cout
3405  << " fail check1="
3406  << ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
3407  << " check2=" << (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)
3408  << " rightOfTarget=" << rightOfTarget->getID()
3409  << " leftOfTarget=" << leftOfTarget->getID()
3410  << "\n";
3411 #endif
3412 
3413  }
3414  }
3415  ++it_avail;
3416  }
3417 }
3418 
3419 
3420 const std::vector<int>
3421 NBEdge::prepareEdgePriorities(const EdgeVector* outgoing, const std::vector<int>& availableLanes) {
3422  std::vector<int> priorities;
3423  MainDirections mainDirections(*outgoing, this, myTo, availableLanes);
3424  const int dist = mainDirections.getStraightest();
3425  if (dist == -1) {
3426  return priorities;
3427  }
3428  // copy the priorities first
3429  priorities.reserve(outgoing->size());
3430  for (const NBEdge* const out : *outgoing) {
3431  int prio = NBNode::isTrafficLight(myTo->getType()) ? 0 : out->getJunctionPriority(myTo);
3432  assert((prio + 1) * 2 > 0);
3433  prio = (prio + 1) * 2;
3434  priorities.push_back(prio);
3435  }
3436  // when the right turning direction has not a higher priority, divide
3437  // the importance by 2 due to the possibility to leave the junction
3438  // faster from this lane
3439 #ifdef DEBUG_CONNECTION_GUESSING
3440  if (DEBUGCOND) std::cout << " prepareEdgePriorities " << getID()
3441  << " outgoing=" << toString(*outgoing)
3442  << " priorities1=" << toString(priorities)
3443  << " dist=" << dist
3444  << "\n";
3445 #endif
3446  if (dist != 0 && !mainDirections.includes(MainDirections::Direction::RIGHTMOST)) {
3447  assert(priorities.size() > 0);
3448  priorities[0] /= 2;
3449 #ifdef DEBUG_CONNECTION_GUESSING
3450  if (DEBUGCOND) {
3451  std::cout << " priorities2=" << toString(priorities) << "\n";
3452  }
3453 #endif
3454  }
3455  // HEURISTIC:
3456  // when no higher priority exists, let the forward direction be
3457  // the main direction
3458  if (mainDirections.empty()) {
3459  assert(dist < (int)priorities.size());
3460  priorities[dist] *= 2;
3461 #ifdef DEBUG_CONNECTION_GUESSING
3462  if (DEBUGCOND) {
3463  std::cout << " priorities3=" << toString(priorities) << "\n";
3464  }
3465 #endif
3466  }
3468  priorities[dist] += 1;
3469  } else {
3470  // try to ensure separation of left turns
3472  priorities[0] /= 4;
3473  priorities[(int)priorities.size() - 1] /= 2;
3474 #ifdef DEBUG_CONNECTION_GUESSING
3475  if (DEBUGCOND) {
3476  std::cout << " priorities6=" << toString(priorities) << "\n";
3477  }
3478 #endif
3479  } else if (mainDirections.includes(MainDirections::Direction::RIGHTMOST)
3480  && outgoing->size() > 2
3481  && availableLanes.size() == 2
3482  && (*outgoing)[dist]->getPriority() == (*outgoing)[0]->getPriority()) {
3483  priorities[0] /= 4;
3484  priorities.back() /= 2;
3485 #ifdef DEBUG_CONNECTION_GUESSING
3486  if (DEBUGCOND) {
3487  std::cout << " priorities7=" << toString(priorities) << "\n";
3488  }
3489 #endif
3490  }
3491  }
3492  if (mainDirections.includes(MainDirections::Direction::FORWARD)) {
3493  if (myLanes.size() > 2) {
3494  priorities[dist] *= 2;
3495 #ifdef DEBUG_CONNECTION_GUESSING
3496  if (DEBUGCOND) {
3497  std::cout << " priorities4=" << toString(priorities) << "\n";
3498  }
3499 #endif
3500  } else {
3501  priorities[dist] *= 3;
3502 #ifdef DEBUG_CONNECTION_GUESSING
3503  if (DEBUGCOND) {
3504  std::cout << " priorities5=" << toString(priorities) << "\n";
3505  }
3506 #endif
3507  }
3508  }
3509  return priorities;
3510 }
3511 
3512 
3513 void
3514 NBEdge::appendTurnaround(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike, bool checkPermissions) {
3515  // do nothing if no turnaround is known
3517  return;
3518  }
3519  // do nothing if the destination node is controlled by a tls and no turnarounds
3520  // shall be appended for such junctions
3521  if (noTLSControlled && myTo->isTLControlled()) {
3522  return;
3523  }
3524  if (noFringe && myTo->getFringeType() == FringeType::OUTER) {
3525  return;
3526  }
3527  bool isDeadEnd = true;
3528  for (const Connection& c : myConnections) {
3529  if ((c.toEdge->getPermissions(c.toLane)
3530  & getPermissions(c.fromLane)
3531  & SVC_PASSENGER) != 0
3532  || (c.toEdge->getPermissions() & getPermissions()) == getPermissions()) {
3533  isDeadEnd = false;
3534  break;
3535  }
3536  }
3537  if (onlyDeadends && !isDeadEnd) {
3538  return;
3539  }
3540  const int fromLane = getFirstAllowedLaneIndex(NBNode::BACKWARD);
3541  if (onlyTurnlane) {
3542  for (const Connection& c : getConnectionsFromLane(fromLane)) {
3543  LinkDirection dir = myTo->getDirection(this, c.toEdge);
3544  if (dir != LinkDirection::LEFT && dir != LinkDirection::PARTLEFT) {
3545  return;
3546  }
3547  }
3548  }
3550  if (checkPermissions) {
3551  if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == 0) {
3552  // exclude connection if fromLane and toEdge have no common permissions
3553  return;
3554  }
3555  if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == SVC_PEDESTRIAN) {
3556  // exclude connection if the only commonly permitted class are pedestrians
3557  // these connections are later built in NBNode::buildWalkingAreas
3558  return;
3559  }
3560  }
3561  // avoid railway turn-arounds
3564  // except at dead-ends on bidi-edges where they model a reversal in train direction
3565  // @todo #4382: once the network fringe is tagged, it also should not receive turn-arounds)
3566  if (isBidiRail() && isRailDeadEnd()) {
3567  // add a slow connection because direction-reversal implies stopping
3569  return;
3570  } else {
3571  return;
3572  }
3573  };
3574  if (noGeometryLike && !isDeadEnd) {
3575  // ignore paths and service entrances if this edge is for passenger traffic
3576  if (myTo->geometryLike() || ((getPermissions() & SVC_PASSENGER) != 0
3577  && !onlyTurnlane
3578  && myTo->geometryLike(
3581  // make sure the turnDestination has other incoming edges
3582  EdgeVector turnIncoming = myTurnDestination->getIncomingEdges();
3583  if (turnIncoming.size() > 1) {
3584  // this edge is always part of incoming
3585  return;
3586  }
3587  }
3588  }
3590 }
3591 
3592 
3593 bool
3594 NBEdge::isTurningDirectionAt(const NBEdge* const edge) const {
3595  // maybe it was already set as the turning direction
3596  if (edge == myTurnDestination) {
3597  return true;
3598  } else if (myTurnDestination != nullptr) {
3599  // otherwise - it's not if a turning direction exists
3600  return false;
3601  }
3602  return edge == myPossibleTurnDestination;
3603 }
3604 
3605 
3606 NBNode*
3607 NBEdge::tryGetNodeAtPosition(double pos, double tolerance) const {
3608  // return the from-node when the position is at the begin of the edge
3609  if (pos < tolerance) {
3610  return myFrom;
3611  }
3612  // return the to-node when the position is at the end of the edge
3613  if (pos > myLength - tolerance) {
3614  return myTo;
3615  }
3616  return nullptr;
3617 }
3618 
3619 
3620 void
3622  int lanes = e->getNumLanes();
3623  for (int i = 0; i < lanes; i++) {
3624  for (const NBEdge::Connection& el : e->getConnectionsFromLane(i)) {
3625  assert(el.tlID == "");
3626  addLane2LaneConnection(i + laneOff, el.toEdge, el.toLane, Lane2LaneInfoType::COMPUTED);
3627  }
3628  }
3629 }
3630 
3631 
3632 bool
3635 }
3636 
3637 
3638 double
3640  return SUMO_const_laneWidth * (double)myLanes.size();
3641 }
3642 
3643 
3644 bool
3645 NBEdge::mayBeTLSControlled(int fromLane, NBEdge* toEdge, int toLane) const {
3646  for (const Connection& c : myConnections) {
3647  if (c.fromLane == fromLane && c.toEdge == toEdge && c.toLane == toLane && c.uncontrolled) {
3648  return false;
3649  }
3650  }
3651  return true;
3652 }
3653 
3654 
3655 bool
3656 NBEdge::setControllingTLInformation(const NBConnection& c, const std::string& tlID) {
3657  const int fromLane = c.getFromLane();
3658  NBEdge* toEdge = c.getTo();
3659  const int toLane = c.getToLane();
3660  const int tlIndex = c.getTLIndex();
3661  const int tlIndex2 = c.getTLIndex2();
3662  // check whether the connection was not set as not to be controled previously
3663  if (!mayBeTLSControlled(fromLane, toEdge, toLane)) {
3664  return false;
3665  }
3666 
3667  assert(fromLane < 0 || fromLane < (int) myLanes.size());
3668  // try to use information about the connections if given
3669  if (fromLane >= 0 && toLane >= 0) {
3670  // find the specified connection
3671  std::vector<Connection>::iterator i =
3672  find_if(myConnections.begin(), myConnections.end(), connections_finder(fromLane, toEdge, toLane));
3673  // ok, we have to test this as on the removal of self-loop edges some connections
3674  // will be reassigned
3675  if (i != myConnections.end()) {
3676  // get the connection
3677  Connection& connection = *i;
3678  // set the information about the tl
3679  connection.tlID = tlID;
3680  connection.tlLinkIndex = tlIndex;
3681  connection.tlLinkIndex2 = tlIndex2;
3682  return true;
3683  }
3684  }
3685  // if the original connection was not found, set the information for all
3686  // connections
3687  int no = 0;
3688  bool hadError = false;
3689  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
3690  if ((*i).toEdge != toEdge) {
3691  continue;
3692  }
3693  if (fromLane >= 0 && fromLane != (*i).fromLane) {
3694  continue;
3695  }
3696  if (toLane >= 0 && toLane != (*i).toLane) {
3697  continue;
3698  }
3699  if ((*i).tlID == "") {
3700  (*i).tlID = tlID;
3701  (*i).tlLinkIndex = tlIndex;
3702  (*i).tlLinkIndex2 = tlIndex2;
3703  no++;
3704  } else {
3705  if ((*i).tlID != tlID && (*i).tlLinkIndex == tlIndex) {
3706  WRITE_WARNINGF(TL("The lane '%' on edge '%' already had a traffic light signal."), i->fromLane, getID());
3707  hadError = true;
3708  }
3709  }
3710  }
3711  if (hadError && no == 0) {
3712  WRITE_WARNINGF(TL("Could not set any signal of the tlLogic '%' (unknown group)."), tlID);
3713  }
3714  return true;
3715 }
3716 
3717 
3718 void
3720  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); it++) {
3721  it->tlID = "";
3722  }
3723 }
3724 
3725 
3728  PositionVector ret;
3729  int lane;
3730  if (myFrom == (&n)) {
3731  // outgoing
3733  ret = myLanes[lane].shape;
3734  } else {
3735  // incoming
3737  ret = myLanes[lane].shape.reverse();
3738  }
3739  ret.move2side(getLaneWidth(lane) / 2.);
3740  return ret;
3741 }
3742 
3743 
3746  PositionVector ret;
3747  int lane;
3748  if (myFrom == (&n)) {
3749  // outgoing
3751  ret = myLanes[lane].shape;
3752  } else {
3753  // incoming
3755  ret = myLanes[lane].shape.reverse();
3756  }
3757  ret.move2side(-getLaneWidth(lane) / 2.);
3758  return ret;
3759 }
3760 
3761 
3762 bool
3763 NBEdge::expandableBy(NBEdge* possContinuation, std::string& reason) const {
3764  // ok, the number of lanes must match
3765  if (myLanes.size() != possContinuation->myLanes.size()) {
3766  reason = "laneNumber";
3767  return false;
3768  }
3769  // do not create self loops
3770  if (myFrom == possContinuation->myTo) {
3771  reason = "loop";
3772  return false;
3773  }
3774  // conserve bidi-rails
3775  if (isBidiRail() != possContinuation->isBidiRail()) {
3776  reason = "bidi-rail";
3777  return false;
3778  }
3779  // also, check whether the connections - if any exit do allow to join
3780  // both edges
3781  // This edge must have a one-to-one connection to the following lanes
3782  switch (myStep) {
3784  break;
3786  break;
3788  // the following edge must be connected
3789  const EdgeVector& conn = getConnectedEdges();
3790  if (find(conn.begin(), conn.end(), possContinuation) == conn.end()) {
3791  reason = "disconnected";
3792  return false;
3793  }
3794  }
3795  break;
3800  // the possible continuation must be connected
3801  if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(possContinuation)) == myConnections.end()) {
3802  reason = "disconnected";
3803  return false;
3804  }
3805  // all lanes must go to the possible continuation
3806  std::vector<int> conns = getConnectionLanes(possContinuation);
3807  const int offset = MAX2(0, getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true));
3808  if (conns.size() < myLanes.size() - offset) {
3809  reason = "some lanes disconnected";
3810  return false;
3811  }
3812  }
3813  break;
3814  default:
3815  break;
3816  }
3817  const double minLength = OptionsCont::getOptions().getFloat("geometry.remove.min-length");
3818  if (minLength > 0 && (possContinuation->getLoadedLength() < minLength || getLoadedLength() < minLength)) {
3819  return true;
3820  }
3821  const double maxJunctionSize = OptionsCont::getOptions().getFloat("geometry.remove.max-junction-size");
3822  if (maxJunctionSize >= 0) {
3823  const double junctionSize = myGeom.back().distanceTo2D(possContinuation->myGeom.front());
3824  if (junctionSize > maxJunctionSize + POSITION_EPS) {
3825  reason = "junction size (" + toString(junctionSize) + ") > max-junction-size (" + toString(maxJunctionSize) + ")";
3826  return false;
3827  }
3828  }
3829  // the priority, too (?)
3830  if (getPriority() != possContinuation->getPriority()) {
3831  reason = "priority";
3832  return false;
3833  }
3834  // the speed allowed
3835  if (mySpeed != possContinuation->mySpeed) {
3836  reason = "speed";
3837  return false;
3838  }
3839  // spreadtype should match or it will look ugly
3840  if (myLaneSpreadFunction != possContinuation->myLaneSpreadFunction) {
3841  reason = "spreadType";
3842  return false;
3843  }
3844  // matching lanes must have identical properties
3845  for (int i = 0; i < (int)myLanes.size(); i++) {
3846  if (myLanes[i].speed != possContinuation->myLanes[i].speed) {
3847  reason = "lane " + toString(i) + " speed";
3848  return false;
3849  } else if (myLanes[i].permissions != possContinuation->myLanes[i].permissions) {
3850  reason = "lane " + toString(i) + " permissions";
3851  return false;
3852  } else if (myLanes[i].changeLeft != possContinuation->myLanes[i].changeLeft || myLanes[i].changeRight != possContinuation->myLanes[i].changeRight) {
3853  reason = "lane " + toString(i) + " change restrictions";
3854  return false;
3855  } else if (myLanes[i].width != possContinuation->myLanes[i].width &&
3856  fabs(myLanes[i].width - possContinuation->myLanes[i].width) > OptionsCont::getOptions().getFloat("geometry.remove.width-tolerance")) {
3857  reason = "lane " + toString(i) + " width";
3858  return false;
3859  }
3860  }
3861  // if given identically osm names
3862  if (!OptionsCont::getOptions().isDefault("output.street-names") && myStreetName != possContinuation->getStreetName()
3863  && ((myStreetName != "" && possContinuation->getStreetName() != "")
3864  // only permit merging a short unnamed road with a longer named road
3865  || (myStreetName != "" && myLength <= possContinuation->getLength())
3866  || (myStreetName == "" && myLength >= possContinuation->getLength()))) {
3867  return false;
3868  }
3869 
3870  return true;
3871 }
3872 
3873 
3874 void
3876  // append geometry
3877  myGeom.append(e->myGeom);
3878  for (int i = 0; i < (int)myLanes.size(); i++) {
3879  myLanes[i].customShape.append(e->myLanes[i].customShape);
3880  if (myLanes[i].hasParameter(SUMO_PARAM_ORIGID) || e->myLanes[i].hasParameter(SUMO_PARAM_ORIGID)
3881  || OptionsCont::getOptions().getBool("output.original-names")) {
3882  const std::string origID = myLanes[i].getParameter(SUMO_PARAM_ORIGID, getID());
3883  const std::string origID2 = e->myLanes[i].getParameter(SUMO_PARAM_ORIGID, e->getID());
3884  if (origID != origID2) {
3885  myLanes[i].setParameter(SUMO_PARAM_ORIGID, origID + " " + origID2);
3886  }
3887  }
3888  myLanes[i].connectionsDone = e->myLanes[i].connectionsDone;
3889  myLanes[i].turnSigns = e->myLanes[i].turnSigns;
3890  }
3891  if (e->getLength() > myLength) {
3892  // possibly some lane attributes differ (when using option geometry.remove.min-length)
3893  // make sure to use the attributes from the longer edge
3894  for (int i = 0; i < (int)myLanes.size(); i++) {
3895  myLanes[i].width = e->myLanes[i].width;
3896  }
3897  // defined name prevails over undefined name of shorter road
3898  if (myStreetName == "") {
3900  }
3901  }
3902  // recompute length
3903  myLength += e->myLength;
3904  if (myLoadedLength > 0 || e->myLoadedLength > 0) {
3906  }
3907  // copy the connections and the building step if given
3908  myStep = e->myStep;
3913  // set the node
3914  myTo = e->myTo;
3916  myToBorder = e->myToBorder;
3918  if (e->mySignalPosition != Position::INVALID) {
3920  }
3921  computeAngle(); // myEndAngle may be different now
3922 }
3923 
3924 
3925 bool
3927  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
3928  if ((*i).toEdge == e && (*i).tlID != "") {
3929  return true;
3930  }
3931  }
3932  return false;
3933 }
3934 
3935 
3936 NBEdge*
3937 NBEdge::getTurnDestination(bool possibleDestination) const {
3938  if (myTurnDestination == nullptr && possibleDestination) {
3940  }
3941  return myTurnDestination;
3942 }
3943 
3944 
3945 std::string
3946 NBEdge::getLaneID(int lane) const {
3947  return myID + "_" + toString(lane);
3948 }
3949 
3950 
3951 bool
3952 NBEdge::isNearEnough2BeJoined2(NBEdge* e, double threshold) const {
3953  std::vector<double> distances = myGeom.distances(e->getGeometry());
3954  assert(distances.size() > 0);
3955  return VectorHelper<double>::maxValue(distances) < threshold;
3956 }
3957 
3958 
3959 void
3960 NBEdge::addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices) {
3961  assert(index <= (int)myLanes.size());
3962  myLanes.insert(myLanes.begin() + index, Lane(this, ""));
3963  // copy attributes
3964  if (myLanes.size() > 1) {
3965  int templateIndex = index > 0 ? index - 1 : index + 1;
3966  myLanes[index].speed = myLanes[templateIndex].speed;
3967  myLanes[index].friction = myLanes[templateIndex].friction;
3968  myLanes[index].permissions = myLanes[templateIndex].permissions;
3969  myLanes[index].preferred = myLanes[templateIndex].preferred;
3970  myLanes[index].endOffset = myLanes[templateIndex].endOffset;
3971  myLanes[index].width = myLanes[templateIndex].width;
3972  myLanes[index].updateParameters(myLanes[templateIndex].getParametersMap());
3973  }
3974  const EdgeVector& incs = myFrom->getIncomingEdges();
3975  if (recomputeShape) {
3977  }
3978  if (recomputeConnections) {
3979  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
3980  (*i)->invalidateConnections(true);
3981  }
3982  invalidateConnections(true);
3983  } else if (shiftIndices) {
3984  // shift outgoing connections above the added lane to the left
3985  for (Connection& c : myConnections) {
3986  if (c.fromLane >= index) {
3987  c.fromLane += 1;
3988  }
3989  }
3990  // shift incoming connections above the added lane to the left
3991  for (NBEdge* inc : myFrom->getIncomingEdges()) {
3992  for (Connection& c : inc->myConnections) {
3993  if (c.toEdge == this && c.toLane >= index) {
3994  c.toLane += 1;
3995  }
3996  }
3997  }
3998  myFrom->shiftTLConnectionLaneIndex(this, +1, index - 1);
3999  myTo->shiftTLConnectionLaneIndex(this, +1, index - 1);
4000  }
4001 }
4002 
4003 void
4005  int newLaneNo = (int)myLanes.size() + by;
4006  while ((int)myLanes.size() < newLaneNo) {
4007  // recompute shapes on last addition
4008  const bool recompute = ((int)myLanes.size() == newLaneNo - 1) && myStep < EdgeBuildingStep::LANES2LANES_USER;
4009  addLane((int)myLanes.size(), recompute, recompute, false);
4010  }
4011 }
4012 
4013 
4014 void
4015 NBEdge::deleteLane(int index, bool recompute, bool shiftIndices) {
4016  assert(index < (int)myLanes.size());
4017  myLanes.erase(myLanes.begin() + index);
4018  if (recompute) {
4020  const EdgeVector& incs = myFrom->getIncomingEdges();
4021  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
4022  (*i)->invalidateConnections(true);
4023  }
4024  invalidateConnections(true);
4025  } else if (shiftIndices) {
4026  removeFromConnections(nullptr, index, -1, false, true);
4027  for (NBEdge* inc : myFrom->getIncomingEdges()) {
4028  inc->removeFromConnections(this, -1, index, false, true);
4029  }
4030  }
4031 }
4032 
4033 
4034 void
4036  int newLaneNo = (int) myLanes.size() - by;
4037  assert(newLaneNo > 0);
4038  while ((int)myLanes.size() > newLaneNo) {
4039  // recompute shapes on last removal
4040  const bool recompute = (int)myLanes.size() == newLaneNo + 1 && myStep < EdgeBuildingStep::LANES2LANES_USER;
4041  deleteLane((int)myLanes.size() - 1, recompute, false);
4042  }
4043 }
4044 
4045 
4046 void
4048  assert(myTo->getOutgoingEdges().size() == 0);
4050 }
4051 
4052 
4053 void
4055  if (lane < 0) { // all lanes are meant...
4056  for (int i = 0; i < (int)myLanes.size(); i++) {
4057  allowVehicleClass(i, vclass);
4058  }
4059  } else {
4060  assert(lane < (int)myLanes.size());
4061  myLanes[lane].permissions |= vclass;
4062  }
4063 }
4064 
4065 
4066 void
4068  if (lane < 0) { // all lanes are meant...
4069  for (int i = 0; i < (int)myLanes.size(); i++) {
4070  disallowVehicleClass((int) i, vclass);
4071  }
4072  } else {
4073  assert(lane < (int)myLanes.size());
4074  myLanes[lane].permissions &= ~vclass;
4075  }
4076 }
4077 
4078 
4079 void
4081  if (lane < 0) { // all lanes are meant...
4082  for (int i = 0; i < (int)myLanes.size(); i++) {
4083  preferVehicleClass(i, vclasses);
4084  }
4085  } else {
4086  assert(lane < (int)myLanes.size());
4087  myLanes[lane].permissions |= vclasses;
4088  myLanes[lane].preferred |= vclasses;
4089  }
4090 }
4091 
4092 
4093 void
4094 NBEdge::setLaneWidth(int lane, double width) {
4095  if (lane < 0) {
4096  // all lanes are meant...
4097  myLaneWidth = width;
4098  for (int i = 0; i < (int)myLanes.size(); i++) {
4099  // ... do it for each lane
4100  setLaneWidth(i, width);
4101  }
4102  return;
4103  }
4104  assert(lane < (int)myLanes.size());
4105  myLanes[lane].width = width;
4106 }
4107 
4108 void
4109 NBEdge::setLaneType(int lane, const std::string& type) {
4110  if (lane < 0) {
4111  for (int i = 0; i < (int)myLanes.size(); i++) {
4112  // ... do it for each lane
4113  setLaneType(i, type);
4114  }
4115  return;
4116  }
4117  assert(lane < (int)myLanes.size());
4118  myLanes[lane].type = type;
4119 }
4120 
4121 
4122 double
4123 NBEdge::getLaneWidth(int lane) const {
4124  return myLanes[lane].width != UNSPECIFIED_WIDTH
4125  ? myLanes[lane].width
4127 }
4128 
4129 double
4131  const NBNode& node,
4132  const NBEdge::Connection& connection,
4133  const NBEdge::Lane& successor,
4134  bool isVia) const {
4135 
4136  if (!isVia && node.isConstantWidthTransition() && getNumLanes() > connection.toEdge->getNumLanes()) {
4137  return getLaneWidth(connection.fromLane);
4138  }
4139 
4140  return (isBikepath(getPermissions(connection.fromLane)) && (
4141  getLaneWidth(connection.fromLane) < successor.width || successor.width == UNSPECIFIED_WIDTH)) ?
4142  myLanes[connection.fromLane].width : successor.width; // getLaneWidth(connection.fromLane) never returns -1 (UNSPECIFIED_WIDTH)
4143 }
4144 
4145 double
4147  double result = 0;
4148  for (int i = 0; i < (int)myLanes.size(); i++) {
4149  result += getLaneWidth(i);
4150  }
4151  return result;
4152 }
4153 
4154 double
4155 NBEdge::getEndOffset(int lane) const {
4156  return myLanes[lane].endOffset != UNSPECIFIED_OFFSET ? myLanes[lane].endOffset : getEndOffset();
4157 }
4158 
4159 
4160 const StopOffset&
4162  return myEdgeStopOffset;
4163 }
4164 
4165 
4166 const StopOffset&
4167 NBEdge::getLaneStopOffset(int lane) const {
4168  if (lane == -1) {
4169  return myEdgeStopOffset;
4170  } else {
4171  return myLanes[lane].laneStopOffset;
4172  }
4173 }
4174 
4175 
4176 void
4177 NBEdge::setEndOffset(int lane, double offset) {
4178  if (lane < 0) {
4179  // all lanes are meant...
4180  myEndOffset = offset;
4181  for (int i = 0; i < (int)myLanes.size(); i++) {
4182  // ... do it for each lane
4183  setEndOffset(i, offset);
4184  }
4185  return;
4186  }
4187  assert(lane < (int)myLanes.size());
4188  myLanes[lane].endOffset = offset;
4189 }
4190 
4191 
4192 bool
4193 NBEdge::setEdgeStopOffset(int lane, const StopOffset& offset, bool overwrite) {
4194  if (lane < 0) {
4195  if (!overwrite && myEdgeStopOffset.isDefined()) {
4196  return false;
4197  }
4198  // all lanes are meant...
4199  if (offset.getOffset() < 0) {
4200  // Edge length unknown at parsing time, thus check here.
4201  WRITE_WARNINGF(TL("Ignoring invalid stopOffset for edge '%' (negative offset)."), getID());
4202  return false;
4203  } else {
4204  myEdgeStopOffset = offset;
4205  }
4206  } else if (lane < (int)myLanes.size()) {
4207  if (!myLanes[lane].laneStopOffset.isDefined() || overwrite) {
4208  if (offset.getOffset() < 0) {
4209  // Edge length unknown at parsing time, thus check here.
4210  WRITE_WARNINGF(TL("Ignoring invalid stopOffset for lane '%' (negative offset)."), getLaneID(lane));
4211  } else {
4212  myLanes[lane].laneStopOffset = offset;
4213  }
4214  }
4215  } else {
4216  WRITE_WARNINGF(TL("Ignoring invalid stopOffset for lane '%' (invalid lane index)."), toString(lane));
4217  }
4218  return true;
4219 }
4220 
4221 
4222 void
4223 NBEdge::setSpeed(int lane, double speed) {
4224  if (lane < 0) {
4225  // all lanes are meant...
4226  mySpeed = speed;
4227  for (int i = 0; i < (int)myLanes.size(); i++) {
4228  // ... do it for each lane
4229  setSpeed(i, speed);
4230  }
4231  return;
4232  }
4233  assert(lane < (int)myLanes.size());
4234  myLanes[lane].speed = speed;
4235 }
4236 
4237 
4238 void
4239 NBEdge::setFriction(int lane, double friction) {
4240  if (lane < 0) {
4241  // all lanes are meant...
4242  myFriction = friction;
4243  for (int i = 0; i < (int)myLanes.size(); i++) {
4244  // ... do it for each lane
4245  setFriction(i, friction);
4246  }
4247  return;
4248  }
4249  assert(lane < (int)myLanes.size());
4250  myLanes[lane].friction = friction;
4251 }
4252 
4253 
4254 void
4255 NBEdge::setAcceleration(int lane, bool accelRamp) {
4256  assert(lane >= 0);
4257  assert(lane < (int)myLanes.size());
4258  myLanes[lane].accelRamp = accelRamp;
4259 }
4260 
4261 
4262 void
4263 NBEdge::setLaneShape(int lane, const PositionVector& shape) {
4264  assert(lane >= 0);
4265  assert(lane < (int)myLanes.size());
4266  myLanes[lane].customShape = shape;
4267 }
4268 
4269 
4270 void
4271 NBEdge::setPermissions(SVCPermissions permissions, int lane) {
4272  if (lane < 0) {
4273  for (int i = 0; i < (int)myLanes.size(); i++) {
4274  // ... do it for each lane
4275  setPermissions(permissions, i);
4276  }
4277  } else {
4278  assert(lane < (int)myLanes.size());
4279  myLanes[lane].permissions = permissions;
4280  }
4281 }
4282 
4283 
4284 void
4286  if (lane < 0) {
4287  for (int i = 0; i < (int)myLanes.size(); i++) {
4288  // ... do it for each lane
4289  setPreferredVehicleClass(permissions, i);
4290  }
4291  } else {
4292  assert(lane < (int)myLanes.size());
4293  myLanes[lane].preferred = permissions;
4294  }
4295 }
4296 
4297 
4298 void
4299 NBEdge::setPermittedChanging(int lane, SVCPermissions changeLeft, SVCPermissions changeRight) {
4300  assert(lane >= 0);
4301  assert(lane < (int)myLanes.size());
4302  myLanes[lane].changeLeft = changeLeft;
4303  myLanes[lane].changeRight = changeRight;
4304 }
4305 
4306 
4308 NBEdge::getPermissions(int lane) const {
4309  if (lane < 0) {
4310  SVCPermissions result = 0;
4311  for (int i = 0; i < (int)myLanes.size(); i++) {
4312  result |= getPermissions(i);
4313  }
4314  return result;
4315  } else {
4316  assert(lane < (int)myLanes.size());
4317  return myLanes[lane].permissions;
4318  }
4319 }
4320 
4321 
4322 void
4324  myLoadedLength = val;
4325 }
4326 
4327 void
4329  myLength = val;
4330 }
4331 
4332 
4333 void
4335  for (std::vector<Lane>::iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
4336  (*i).permissions = SVCAll;
4337  (*i).preferred = 0;
4338  }
4339 }
4340 
4341 
4342 bool
4344  if (c1.fromLane != c2.fromLane) {
4345  return c1.fromLane < c2.fromLane;
4346  }
4347  if (c1.toEdge != c2.toEdge) {
4348  return false; // do not change ordering among toEdges as this is determined by angle in an earlier step
4349  }
4350  return c1.toLane < c2.toLane;
4351 }
4352 
4353 
4354 double
4358  } else {
4360  myLanes.back().shape.back() : myLanes[getNumLanes() / 2].shape.back();
4361  //std::cout << getID() << " signalPos=" << mySignalPosition << " laneEnd=" << laneEnd << " toShape=" << myTo->getShape() << " toBorder=" << myToBorder << "\n";
4362  return mySignalPosition.distanceTo2D(laneEnd);
4363  }
4364 }
4365 
4366 
4367 int
4368 NBEdge::getFirstNonPedestrianLaneIndex(int direction, bool exclusive) const {
4369  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4370  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4371  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4372  for (int i = start; i != end; i += direction) {
4373  // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
4374  // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
4375  if ((exclusive && myLanes[i].permissions != SVC_PEDESTRIAN && myLanes[i].permissions != 0)
4376  || ((myLanes[i].permissions & SVC_PEDESTRIAN) == 0 && myLanes[i].permissions != 0)) {
4377  return i;
4378  }
4379  }
4380  return -1;
4381 }
4382 
4383 int
4384 NBEdge::getFirstNonPedestrianNonBicycleLaneIndex(int direction, bool exclusive) const {
4385  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4386  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4387  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4388  for (int i = start; i != end; i += direction) {
4389  // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
4390  // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
4391  SVCPermissions p = myLanes[i].permissions;
4392  if ((exclusive && p != SVC_PEDESTRIAN && p != SVC_BICYCLE && p != (SVC_PEDESTRIAN | SVC_BICYCLE) && p != 0)
4393  || (p == SVCAll || ((p & (SVC_PEDESTRIAN | SVC_BICYCLE)) == 0 && p != 0))) {
4394  return i;
4395  }
4396  }
4397  return -1;
4398 }
4399 
4400 int
4402  for (int i = 0; i < (int)myLanes.size(); i++) {
4403  if (myLanes[i].permissions == permissions) {
4404  return i;
4405  }
4406  }
4407  return -1;
4408 }
4409 
4410 int
4411 NBEdge::getFirstAllowedLaneIndex(int direction) const {
4412  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4413  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4414  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4415  for (int i = start; i != end; i += direction) {
4416  if (myLanes[i].permissions != 0) {
4417  return i;
4418  }
4419  }
4420  return end - direction;
4421 }
4422 
4423 
4424 std::set<SVCPermissions>
4425 NBEdge::getPermissionVariants(int iStart, int iEnd) const {
4426  std::set<SVCPermissions> result;
4427  if (iStart < 0 || iStart >= getNumLanes() || iEnd > getNumLanes()) {
4428  throw ProcessError("invalid indices iStart " + toString(iStart) + " iEnd " + toString(iEnd) + " for edge with " + toString(getNumLanes()) + " lanes.");
4429  }
4430  for (int i = iStart; i < iEnd; ++i) {
4431  result.insert(getPermissions(i));
4432  }
4433  return result;
4434 }
4435 
4436 int
4437 NBEdge::getNumLanesThatAllow(SVCPermissions permissions, bool allPermissions) const {
4438  int result = 0;
4439  for (const Lane& lane : myLanes) {
4440  if ((allPermissions && (lane.permissions & permissions) == permissions)
4441  || (!allPermissions && (lane.permissions & permissions) != 0)) {
4442  result++;
4443  }
4444  }
4445  return result;
4446 }
4447 
4448 bool
4450  assert(lane >= 0 && lane < getNumLanes());
4451  return myLanes[lane].changeLeft == SVC_UNSPECIFIED ? true : (myLanes[lane].changeLeft & vclass) == vclass;
4452 }
4453 
4454 bool
4456  assert(lane >= 0 && lane < getNumLanes());
4457  return myLanes[lane].changeRight == SVC_UNSPECIFIED ? true : (myLanes[lane].changeRight & vclass) == vclass;
4458 }
4459 
4460 double
4462  double angle = getAngleAtNode(node) + (getFromNode() == node ? 180.0 : 0.0);
4463  if (angle < 0) {
4464  angle += 360.0;
4465  }
4466  if (angle >= 360) {
4467  angle -= 360.0;
4468  }
4469  if (gDebugFlag1) {
4470  std::cout << getID() << " angle=" << getAngleAtNode(node) << " convAngle=" << angle << "\n";
4471  }
4472  return angle;
4473 }
4474 
4475 
4478  int index = getFirstNonPedestrianLaneIndex(direction);
4479  if (index < 0) {
4480  throw ProcessError(TLF("Edge % allows pedestrians on all lanes", getID()));
4481  }
4482  return myLanes[index];
4483 }
4484 
4485 std::string
4487  // see IntermodalEdge::getSidewalk()
4488  for (int i = 0; i < (int)myLanes.size(); i++) {
4489  if (myLanes[i].permissions == SVC_PEDESTRIAN) {
4490  return getLaneID(i);
4491  }
4492  }
4493  for (int i = 0; i < (int)myLanes.size(); i++) {
4494  if ((myLanes[i].permissions & SVC_PEDESTRIAN) != 0) {
4495  return getLaneID(i);
4496  }
4497  }
4498  return getLaneID(0);
4499 }
4500 
4501 void
4502 NBEdge::addSidewalk(double width) {
4504 }
4505 
4506 
4507 void
4508 NBEdge::restoreSidewalk(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4509  restoreRestrictedLane(SVC_PEDESTRIAN, oldLanes, oldGeometry, oldConnections);
4510 }
4511 
4512 
4513 void
4514 NBEdge::addBikeLane(double width) {
4516 }
4517 
4518 
4519 void
4520 NBEdge::restoreBikelane(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4521  restoreRestrictedLane(SVC_BICYCLE, oldLanes, oldGeometry, oldConnections);
4522 }
4523 
4524 bool
4526  for (const Lane& lane : myLanes) {
4527  if (lane.permissions == vclass) {
4528  return true;
4529  }
4530  }
4531  return false;
4532 }
4533 
4534 
4535 void
4537  if (hasRestrictedLane(vclass)) {
4538  WRITE_WARNINGF(TL("Edge '%' already has a dedicated lane for %s. Not adding another one."), getID(), toString(vclass));
4539  return;
4540  }
4542  myGeom.move2side(width / 2);
4543  }
4544  // disallow the designated vclass on all "old" lanes
4545  disallowVehicleClass(-1, vclass);
4546  // don't create a restricted vehicle lane to the right of a sidewalk
4547  const int newIndex = (vclass != SVC_PEDESTRIAN && myLanes[0].permissions == SVC_PEDESTRIAN) ? 1 : 0;
4548  if (newIndex == 0) {
4549  // disallow pedestrians on all "higher" lanes to ensure that sidewalk remains the rightmost lane
4551  }
4552  // add new lane
4553  myLanes.insert(myLanes.begin() + newIndex, Lane(this, myLanes[0].getParameter(SUMO_PARAM_ORIGID)));
4554  myLanes[newIndex].permissions = vclass;
4555  myLanes[newIndex].width = fabs(width);
4556  // shift outgoing connections to the left
4557  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
4558  Connection& c = *it;
4559  if (c.fromLane >= newIndex) {
4560  c.fromLane += 1;
4561  }
4562  }
4563  // shift incoming connections to the left
4564  const EdgeVector& incoming = myFrom->getIncomingEdges();
4565  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
4566  (*it)->shiftToLanesToEdge(this, 1);
4567  }
4569  myTo->shiftTLConnectionLaneIndex(this, 1);
4571 }
4572 
4573 
4574 void
4575 NBEdge::restoreRestrictedLane(SUMOVehicleClass vclass, std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4576  // check that previously lane was transformed
4577  if (myLanes[0].permissions != vclass) {
4578  WRITE_WARNINGF(TL("Edge '%' doesn't have a dedicated lane for %s. Cannot be restored."), getID(), toString(vclass));
4579  return;
4580  }
4581  // restore old values
4582  myGeom = oldGeometry;
4583  myLanes = oldLanes;
4584  myConnections = oldConnections;
4585  // shift incoming connections to the right
4586  const EdgeVector& incoming = myFrom->getIncomingEdges();
4587  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
4588  (*it)->shiftToLanesToEdge(this, 0);
4589  }
4590  // Shift TL conections
4592  myTo->shiftTLConnectionLaneIndex(this, 0);
4594 }
4595 
4596 
4597 void
4600  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
4601  if ((*it).toEdge == to && (*it).toLane >= 0) {
4602  (*it).toLane += laneOff;
4603  }
4604  }
4605 }
4606 
4607 
4608 void
4611  const int i = (node == myTo ? -1 : 0);
4612  const int i2 = (node == myTo ? 0 : -1);
4613  const double dist = myGeom[i].distanceTo2D(node->getPosition());
4614  const double neededOffset = getTotalWidth() / 2;
4615  const double dist2 = MIN2(myGeom.distance2D(other->getGeometry()[i2]),
4616  other->getGeometry().distance2D(myGeom[i]));
4617  const double neededOffset2 = neededOffset + (other->getTotalWidth()) / 2;
4618  if (dist < neededOffset && dist2 < neededOffset2) {
4619  PositionVector tmp = myGeom;
4620  // @note this doesn't work well for vissim networks
4621  //tmp.move2side(MIN2(neededOffset - dist, neededOffset2 - dist2));
4622  try {
4623  tmp.move2side(neededOffset - dist);
4624  myGeom[i] = tmp[i];
4625  } catch (InvalidArgument&) {
4626  WRITE_WARNINGF(TL("Could not avoid overlapping shape at node '%' for edge '%'."), node->getID(), getID());
4627  }
4628  }
4629  }
4630 }
4631 
4632 
4633 Position
4634 NBEdge::geometryPositionAtOffset(double offset) const {
4635  if (myLoadedLength > 0) {
4636  return myGeom.positionAtOffset(offset * myLength / myLoadedLength);
4637  } else {
4638  return myGeom.positionAtOffset(offset);
4639  }
4640 }
4641 
4642 
4643 double
4645  double result = getLoadedLength();
4646  if (OptionsCont::getOptions().getBool("no-internal-links") && !hasLoadedLength()) {
4647  // use length to junction center even if a modified geometry was given
4649  geom.push_back_noDoublePos(getToNode()->getCenter());
4650  geom.push_front_noDoublePos(getFromNode()->getCenter());
4651  result = geom.length();
4652  }
4653  double avgEndOffset = 0;
4654  for (const Lane& lane : myLanes) {
4655  avgEndOffset += lane.endOffset;
4656  }
4657  if (isBidiRail()) {
4658  avgEndOffset += myPossibleTurnDestination->getEndOffset();
4659  }
4660  avgEndOffset /= (double)myLanes.size();
4661  return MAX2(result - avgEndOffset, POSITION_EPS);
4662 }
4663 
4664 
4665 void
4666 NBEdge::setOrigID(const std::string origID, const bool append, const int laneIdx) {
4667  if (laneIdx == -1) {
4668  for (int i = 0; i < (int)myLanes.size(); i++) {
4669  setOrigID(origID, append, i);
4670  }
4671  } else {
4672  if (origID != "") {
4673  if (append) {
4674  std::vector<std::string> oldIDs = StringTokenizer(myLanes[laneIdx].getParameter(SUMO_PARAM_ORIGID)).getVector();
4675  if (std::find(oldIDs.begin(), oldIDs.end(), origID) == oldIDs.end()) {
4676  oldIDs.push_back(origID);
4677  }
4678  myLanes[laneIdx].setParameter(SUMO_PARAM_ORIGID, toString(oldIDs));
4679  } else {
4680  myLanes[laneIdx].setParameter(SUMO_PARAM_ORIGID, origID);
4681  }
4682  } else {
4683  // do not record empty origID parameter
4684  myLanes[laneIdx].unsetParameter(SUMO_PARAM_ORIGID);
4685  }
4686  }
4687 }
4688 
4689 
4690 const EdgeVector&
4692  // @todo cache successors instead of recomputing them every time
4693  mySuccessors.clear();
4694  //std::cout << "getSuccessors edge=" << getID() << " svc=" << toString(vClass) << " cons=" << myConnections.size() << "\n";
4695  for (const Connection& con : myConnections) {
4696  if (con.fromLane >= 0 && con.toLane >= 0 && con.toEdge != nullptr &&
4697  (vClass == SVC_IGNORING || (getPermissions(con.fromLane)
4698  & con.toEdge->getPermissions(con.toLane) & vClass) != 0)
4699  && std::find(mySuccessors.begin(), mySuccessors.end(), con.toEdge) == mySuccessors.end()) {
4700  mySuccessors.push_back(con.toEdge);
4701  //std::cout << " succ=" << con.toEdge->getID() << "\n";
4702  }
4703  }
4704  return mySuccessors;
4705 }
4706 
4707 
4709 NBEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
4710  // @todo cache successors instead of recomputing them every time
4711  myViaSuccessors.clear();
4712  for (const Connection& con : myConnections) {
4713  std::pair<const NBEdge*, const Connection*> pair(con.toEdge, nullptr);
4714  // special case for Persons in Netedit
4715  if (vClass == SVC_PEDESTRIAN) {
4716  myViaSuccessors.push_back(pair); // Pedestrians have complete freedom of movement in all sucessors
4717  } else if ((con.fromLane >= 0) && (con.toLane >= 0) &&
4718  (con.toEdge != nullptr) &&
4719  ((getPermissions(con.fromLane) & con.toEdge->getPermissions(con.toLane) & vClass) == vClass)) {
4720  // ignore duplicates
4721  if (con.getLength() > 0) {
4722  pair.second = &con;
4723  }
4724  myViaSuccessors.push_back(pair);
4725  }
4726  }
4727  return myViaSuccessors;
4728 }
4729 
4730 
4731 void
4732 NBEdge::debugPrintConnections(bool outgoing, bool incoming) const {
4733  if (outgoing) {
4734  for (const Connection& c : myConnections) {
4735  std::cout << " " << getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
4736  }
4737  }
4738  if (incoming) {
4739  for (NBEdge* inc : myFrom->getIncomingEdges()) {
4740  for (Connection& c : inc->myConnections) {
4741  if (c.toEdge == this) {
4742  std::cout << " " << inc->getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
4743  }
4744  }
4745  }
4746  }
4747 }
4748 
4749 
4750 int
4751 NBEdge::getLaneIndexFromLaneID(const std::string laneID) {
4752  return StringUtils::toInt(laneID.substr(laneID.rfind("_") + 1));
4753 }
4754 
4755 bool
4757  bool haveJoined = false;
4758  int i = 0;
4759  while (i < getNumLanes() - 1) {
4760  if ((getPermissions(i) == perms) && (getPermissions(i + 1) == perms)) {
4761  const double newWidth = getLaneWidth(i) + getLaneWidth(i + 1);
4762  const std::string newType = myLanes[i].type + "|" + myLanes[i + 1].type;
4763  deleteLane(i, false, true);
4764  setLaneWidth(i, newWidth);
4765  setLaneType(i, newType);
4766  haveJoined = true;
4767  } else {
4768  i++;
4769  }
4770  }
4771  return haveJoined;
4772 }
4773 
4774 
4775 EdgeVector
4777  EdgeVector result;
4778  for (NBEdge* edge : edges) {
4779  if ((edge->getPermissions() & permissions) != 0) {
4780  result.push_back(edge);
4781  }
4782  }
4783  return result;
4784 }
4785 
4786 NBEdge*
4788  EdgeVector cands = filterByPermissions(myTo->getOutgoingEdges(), permissions);
4789  if (cands.size() == 0) {
4790  return nullptr;
4791  }
4792  sort(cands.begin(), cands.end(), NBContHelper::edge_similar_direction_sorter(this));
4793  NBEdge* best = cands.front();
4794  if (isTurningDirectionAt(best)) {
4795  return nullptr;
4796  } else {
4797  return best;
4798  }
4799 }
4800 
4801 NBEdge*
4803  EdgeVector cands = filterByPermissions(myFrom->getIncomingEdges(), permissions);
4804  if (cands.size() == 0) {
4805  return nullptr;
4806  }
4807  sort(cands.begin(), cands.end(), NBContHelper::edge_similar_direction_sorter(this, false));
4808  NBEdge* best = cands.front();
4809  if (best->isTurningDirectionAt(this)) {
4810  return nullptr;
4811  } else {
4812  return best;
4813  }
4814 }
4815 
4816 
4817 NBEdge*
4818 NBEdge::guessOpposite(bool reguess) {
4819  NBEdge* opposite = nullptr;
4820  if (getNumLanes() > 0) {
4821  NBEdge::Lane& lastLane = myLanes.back();
4822  const double lastWidth = getLaneWidth(getNumLanes() - 1);
4823  if (lastLane.oppositeID == "" || reguess) {
4824  for (NBEdge* cand : getToNode()->getOutgoingEdges()) {
4825  if (cand->getToNode() == getFromNode() && !cand->getLanes().empty()) {
4826  const double lastWidthCand = cand->getLaneWidth(cand->getNumLanes() - 1);
4827  // in sharp corners, the difference may be higher
4828  // factor (sqrt(2) for 90 degree corners
4829  const double threshold = 1.42 * 0.5 * (lastWidth + lastWidthCand) + 0.5;
4830  const double distance = VectorHelper<double>::maxValue(lastLane.shape.distances(cand->getLanes().back().shape));
4831  //std::cout << " distance=" << distance << " threshold=" << threshold << " distances=" << toString(lastLane.shape.distances(cand->getLanes().back().shape)) << "\n";
4832  if (distance < threshold) {
4833  opposite = cand;
4834  }
4835  }
4836  }
4837  if (opposite != nullptr) {
4838  lastLane.oppositeID = opposite->getLaneID(opposite->getNumLanes() - 1);
4839  }
4840  }
4841  }
4842  return opposite;
4843 }
4844 
4845 double
4846 NBEdge::getDistancAt(double pos) const {
4847  // negative values of myDistances indicate descending kilometrage
4848  return fabs(myDistance + pos);
4849 }
4850 
4851 /****************************************************************************/
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define RAD2DEG(x)
Definition: GeomHelper.h:36
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_MESSAGEF(...)
Definition: MsgHandler.h:298
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
std::vector< std::pair< const NBRouterEdge *, const NBRouterEdge * > > ConstRouterEdgePairVector
Definition: NBCont.h:46
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
KeepClear
keepClear status of connections
Definition: NBCont.h:58
@ KEEPCLEAR_UNSPECIFIED
Definition: NBCont.h:61
#define DEBUGCOND
Definition: NBEdge.cpp:59
#define DEBUGCOND2(obj)
Definition: NBEdge.cpp:62
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
const std::string & getVehicleClassNames(SVCPermissions permissions, bool expand)
Returns the ids of the given classes, divided using a ' '.
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
bool isBikepath(SVCPermissions permissions)
Returns whether an edge with the given permission is a bicycle edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
@ RIGHT
At the rightmost side of the lane.
const std::string SUMO_PARAM_ORIGID
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge's lateral offset shal...
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
int gPrecision
the precision for floating point outputs
Definition: StdDefs.cpp:26
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:37
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN2(T a, T b)
Definition: StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static void compute(BresenhamCallBack *callBack, const int val1, const int val2)
Definition: Bresenham.cpp:32
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:50
static double legacyDegree(const double angle, const bool positive=false)
Definition: GeomHelper.cpp:214
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:178
int getFromLane() const
returns the from-lane
int getTLIndex2() const
Definition: NBConnection.h:94
int getTLIndex() const
returns the index within the controlling tls or InvalidTLIndex if this link is unontrolled
Definition: NBConnection.h:91
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
int getToLane() const
returns the to-lane
NBEdge * getTo() const
returns the to-edge (end of the connection)
Holds (- relative to the edge it is build from -!!!) the list of main directions a vehicle that drive...
Definition: NBEdge.h:1602
bool empty() const
returns the information whether no following street has a higher priority
Definition: NBEdge.cpp:223
bool includes(Direction d) const
returns the information whether the street in the given direction has a higher priority
Definition: NBEdge.cpp:229
int getStraightest() const
returns the index of the straightmost among the given outgoing edges
Definition: NBEdge.h:1619
MainDirections(const EdgeVector &outgoing, NBEdge *parent, NBNode *to, const std::vector< int > &availableLanes)
constructor
Definition: NBEdge.cpp:166
std::vector< Direction > myDirs
list of the main direction within the following junction relative to the edge
Definition: NBEdge.h:1634
~MainDirections()
destructor
Definition: NBEdge.cpp:219
int myStraightest
the index of the straightmost among the given outgoing edges
Definition: NBEdge.h:1631
Direction
enum of possible directions
Definition: NBEdge.h:1605
A class that being a bresenham-callback assigns the incoming lanes to the edges.
Definition: NBEdge.h:1562
void execute(const int lane, const int virtEdge)
executes a bresenham - step
Definition: NBEdge.cpp:135
const std::map< NBEdge *, std::vector< int > > & getBuiltConnections() const
get built connections
Definition: NBEdge.h:1582
Class to sort edges by their angle.
Definition: NBEdge.h:1971
int operator()(const Connection &c1, const Connection &c2) const
comparing operation
Definition: NBEdge.cpp:238
The representation of a single edge during network building.
Definition: NBEdge.h:92
void reinit(NBNode *from, NBNode *to, const std::string &type, double speed, double friction, int nolanes, int priority, PositionVector geom, double width, double endOffset, const std::string &streetName, LaneSpreadFunction spread, bool tryIgnoreNodePositions=false)
Resets initial values.
Definition: NBEdge.cpp:379
void addGeometryPoint(int index, const Position &p)
Adds a further geometry point.
Definition: NBEdge.cpp:985
static std::vector< LinkDirection > decodeTurnSigns(int turnSigns, int shift=0)
decode bitset
Definition: NBEdge.cpp:2618
void mirrorX()
mirror coordinates along the x-axis
Definition: NBEdge.cpp:563
void setPreferredVehicleClass(SVCPermissions permissions, int lane=-1)
set preferred Vehicle Class
Definition: NBEdge.cpp:4285
static const int TURN_SIGN_SHIFT_BUS
shift values for decoding turn signs
Definition: NBEdge.h:375
double getLaneSpeed(int lane) const
get lane speed
Definition: NBEdge.cpp:2160
static const int TURN_SIGN_SHIFT_BICYCLE
Definition: NBEdge.h:377
NBEdge * guessOpposite(bool reguess=false)
set oppositeID and return opposite edge if found
Definition: NBEdge.cpp:4818
void setPermittedChanging(int lane, SVCPermissions changeLeft, SVCPermissions changeRight)
set allowed classes for changing to the left and right from the given lane
Definition: NBEdge.cpp:4299
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:589
double myLaneWidth
This width of this edge's lanes.
Definition: NBEdge.h:1793
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4308
std::vector< Connection > myConnectionsToDelete
List of connections marked for delayed removal.
Definition: NBEdge.h:1763
const EdgeVector * getConnectedSorted()
Returns the list of outgoing edges without the turnaround sorted in clockwise direction.
Definition: NBEdge.cpp:1309
double getDistancAt(double pos) const
get distance at the given offset
Definition: NBEdge.cpp:4846
double myEndOffset
This edges's offset to the intersection begin (will be applied to all lanes)
Definition: NBEdge.h:1784
int myToJunctionPriority
The priority normalised for the node the edge is incoming in.
Definition: NBEdge.h:1775
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:4271
StopOffset myEdgeStopOffset
A vClass specific stop offset - assumed of length 0 (unspecified) or 1. For the latter case the int i...
Definition: NBEdge.h:1790
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:598
double getCrossingAngle(NBNode *node)
return the angle for computing pedestrian crossings at the given node
Definition: NBEdge.cpp:4461
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:4514
bool expandableBy(NBEdge *possContinuation, std::string &reason) const
Check if Node is expandable.
Definition: NBEdge.cpp:3763
double getLaneFriction(int lane) const
get lane friction of specified lane
Definition: NBEdge.cpp:2166
const ConstRouterEdgePairVector & getViaSuccessors(SUMOVehicleClass vClass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Returns the following edges for the given vClass.
Definition: NBEdge.cpp:4709
void init(int noLanes, bool tryIgnoreNodePositions, const std::string &origID)
Initialization routines common to all constructors.
Definition: NBEdge.cpp:456
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4223
void reinitNodes(NBNode *from, NBNode *to)
Resets nodes but keeps all other values the same (used when joining)
Definition: NBEdge.cpp:430
double mySpeed
The maximal speed.
Definition: NBEdge.h:1749
bool hasLaneSpecificFriction() const
whether lanes differ in friction
Definition: NBEdge.cpp:2412
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:638
PositionVector getCWBoundaryLine(const NBNode &n) const
get the outer boundary of this edge when going clock-wise around the given node
Definition: NBEdge.cpp:3727
std::vector< Connection > myConnections
List of connections to following edges.
Definition: NBEdge.h:1760
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:1278
NBEdge()
constructor for dummy edge
Definition: NBEdge.cpp:356
void divideOnEdges(const EdgeVector *outgoing)
divides the lanes on the outgoing edges
Definition: NBEdge.cpp:3144
ConstRouterEdgePairVector myViaSuccessors
Definition: NBEdge.h:1838
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:3745
double buildInnerEdges(const NBNode &n, int noInternalNoSplits, int &linkIndex, int &splitIndex)
Definition: NBEdge.cpp:1653
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Definition: NBEdge.h:351
void incLaneNo(int by)
increment lane
Definition: NBEdge.cpp:4004
static EdgeVector filterByPermissions(const EdgeVector &edges, SVCPermissions permissions)
return only those edges that permit at least one of the give permissions
Definition: NBEdge.cpp:4776
const Connection & getConnection(int fromLane, const NBEdge *to, int toLane) const
Returns the specified connection (unmodifiable) This method goes through "myConnections" and returns ...
Definition: NBEdge.cpp:1266
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:665
void addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices)
add lane
Definition: NBEdge.cpp:3960
bool hasLaneSpecificSpeed() const
whether lanes differ in speed
Definition: NBEdge.cpp:2402
void setAverageLengthWithOpposite(double val)
patch average lane length in regard to the opposite edge
Definition: NBEdge.cpp:4328
void disallowVehicleClass(int lane, SUMOVehicleClass vclass)
set disallowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:4067
double getShapeStartAngle() const
Returns the angle at the start of the edge.
Definition: NBEdge.cpp:2361
static const int UNSPECIFIED_INTERNAL_LANE_INDEX
internal lane computation not yet done
Definition: NBEdge.h:369
void appendTurnaround(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike, bool checkPermissions)
Add a connection to the previously computed turnaround, if wished and a turning direction exists (myT...
Definition: NBEdge.cpp:3514
static bool connections_sorter(const Connection &c1, const Connection &c2)
connections_sorter sort by fromLane, toEdge and toLane
Definition: NBEdge.cpp:4343
std::string myType
The type of the edge.
Definition: NBEdge.h:1727
bool hasPermissions() const
whether at least one lane has restrictions
Definition: NBEdge.cpp:2377
double myTotalAngle
Definition: NBEdge.h:1742
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition: NBEdge.cpp:979
bool hasDefaultGeometryEndpoints() const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:595
std::string myTurnSignTarget
node for which turnSign information applies
Definition: NBEdge.h:1733
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:730
static const bool UNSPECIFIED_CONNECTION_UNCONTROLLED
TLS-controlled despite its node controlled not specified.
Definition: NBEdge.h:372
const EdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges for the given vClass.
Definition: NBEdge.cpp:4691
void dismissVehicleClassInformation()
dimiss vehicle class information
Definition: NBEdge.cpp:4334
bool computeEdge2Edges(bool noLeftMovers)
computes the edge (step1: computation of approached edges)
Definition: NBEdge.cpp:2527
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:631
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1781
void moveConnectionToLeft(int lane)
Definition: NBEdge.cpp:1625
void updateChangeRestrictions(SVCPermissions ignoring)
modify all existing restrictions on lane changing
Definition: NBEdge.cpp:2178
void restoreBikelane(std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore an previously added BikeLane
Definition: NBEdge.cpp:4520
Position getEndpointAtNode(const NBNode *node) const
Definition: NBEdge.cpp:613
NBEdge * getStraightContinuation(SVCPermissions permissions) const
return the straightest follower edge for the given permissions or nullptr (never returns turn-arounds...
Definition: NBEdge.cpp:4787
bool hasLoadedLength() const
Returns whether a length was set explicitly.
Definition: NBEdge.h:608
void restoreSidewalk(std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore an previously added sidewalk
Definition: NBEdge.cpp:4508
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false, SVCPermissions permission=SVC_UNSPECIFIED)
Adds a connection to another edge.
Definition: NBEdge.cpp:1063
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, const bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition: NBEdge.cpp:1098
void divideSelectedLanesOnEdges(const EdgeVector *outgoing, const std::vector< int > &availableLanes)
divide selected lanes on edges
Definition: NBEdge.cpp:3234
bool setEdgeStopOffset(int lane, const StopOffset &offset, bool overwrite=false)
set lane and vehicle class specific stopOffset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4193
bool hasLaneSpecificStopOffsets() const
whether lanes differ in stopOffsets
Definition: NBEdge.cpp:2455
void setNodeBorder(const NBNode *node, const Position &p, const Position &p2, bool rectangularCut)
Set Node border.
Definition: NBEdge.cpp:676
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:4368
const std::string & getID() const
Definition: NBEdge.h:1522
EdgeVector mySuccessors
Definition: NBEdge.h:1835
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:726
void shiftToLanesToEdge(NBEdge *to, int laneOff)
modifify the toLane for all connections to the given edge
Definition: NBEdge.cpp:4598
void checkGeometry(const double maxAngle, const double minRadius, bool fix, bool silent)
Check the angles of successive geometry segments.
Definition: NBEdge.cpp:1017
static double myDefaultConnectionLength
Definition: NBEdge.h:1841
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
Definition: NBEdge.cpp:3952
EdgeBuildingStep myStep
The building step.
Definition: NBEdge.h:1724
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:542
void setLaneType(int lane, const std::string &type)
set lane specific type (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4109
bool computeLanes2Edges()
computes the edge, step2: computation of which lanes approach the edges)
Definition: NBEdge.cpp:2583
EdgeBuildingStep
Current state of the edge within the building process.
Definition: NBEdge.h:109
@ INIT_REJECT_CONNECTIONS
The edge has been loaded and connections shall not be added.
@ EDGE2EDGES
The relationships between edges are computed/loaded.
@ LANES2LANES_RECHECK
Lanes to lanes - relationships are computed; should be rechecked.
@ LANES2LANES_DONE
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
@ LANES2EDGES
Lanes to edges - relationships are computed/loaded.
@ LANES2LANES_USER
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
@ INIT
The edge has been loaded, nothing is computed yet.
NBEdge * getStraightPredecessor(SVCPermissions permissions) const
return the straightest predecessor edge for the given permissions or nullptr (never returns turn-arou...
Definition: NBEdge.cpp:4802
void remapConnections(const EdgeVector &incoming)
Remaps the connection in a way that allows the removal of it.
Definition: NBEdge.cpp:1397
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:615
~NBEdge()
Destructor.
Definition: NBEdge.cpp:538
NBNode * myTo
Definition: NBEdge.h:1730
double myEndAngle
Definition: NBEdge.h:1741
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:4411
bool allowsChangingRight(int lane, SUMOVehicleClass vclass) const
Returns whether the given vehicle class may change left from this lane.
Definition: NBEdge.cpp:4455
static const double UNSPECIFIED_LOADED_LENGTH
no length override given
Definition: NBEdge.h:360
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4094
void resetLaneShapes()
reset lane shapes to what they would be before cutting with the junction shapes
Definition: NBEdge.cpp:2172
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3656
bool bothLeftTurns(LinkDirection dir, const NBEdge *otherFrom, LinkDirection dir2) const
determine conflict between opposite left turns
Definition: NBEdge.cpp:2065
void setAcceleration(int lane, bool accelRamp)
marks one lane as acceleration lane
Definition: NBEdge.cpp:4255
const StopOffset & getEdgeStopOffset() const
Returns the stopOffset to the end of the edge.
Definition: NBEdge.cpp:4161
NBNode * tryGetNodeAtPosition(double pos, double tolerance=5.0) const
Returns the node at the given edges length (using an epsilon)
Definition: NBEdge.cpp:3607
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:973
void clearControllingTLInformation()
clears tlID for all connections
Definition: NBEdge.cpp:3719
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3594
void addStraightConnections(const EdgeVector *outgoing, const std::vector< int > &availableLanes, const std::vector< int > &priorities)
add some straight connections
Definition: NBEdge.cpp:3339
bool hasLaneSpecificPermissions() const
whether lanes differ in allowed vehicle classes
Definition: NBEdge.cpp:2388
bool needsLaneSpecificOutput() const
whether at least one lane has values differing from the edges values
Definition: NBEdge.cpp:2510
void computeAngle()
computes the angle of this edge and stores it in myAngle
Definition: NBEdge.cpp:2263
bool isBidiEdge(bool checkPotential=false) const
whether this edge is part of a bidirectional edge pair
Definition: NBEdge.cpp:742
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:363
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:4502
bool hasSignalisedConnectionTo(const NBEdge *const e) const
Check if edge has signalised connections.
Definition: NBEdge.cpp:3926
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1798
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:516
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:779
std::vector< Connection > getConnectionsFromLane(int lane, const NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1252
bool hasAccelLane() const
whether one of the lanes is an acceleration lane
Definition: NBEdge.cpp:2468
bool myIsBidi
whether this edge is part of a non-rail bidi edge pair
Definition: NBEdge.h:1829
static double firstIntersection(const PositionVector &v1, const PositionVector &v2, double width1, double width2, const std::string &error="", bool secondIntersection=false)
compute the first intersection point between the given lane geometries considering their rspective wi...
Definition: NBEdge.cpp:2001
PositionVector myToBorder
Definition: NBEdge.h:1822
void extendGeometryAtNode(const NBNode *node, double maxExtent)
linearly extend the geometry at the given node
Definition: NBEdge.cpp:639
void setFriction(int lane, double friction)
set lane specific friction (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4239
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition: NBEdge.h:354
static const double ANGLE_LOOKAHEAD
the distance at which to take the default angle
Definition: NBEdge.h:366
int getNumLanesThatAllow(SVCPermissions permissions, bool allPermissions=true) const
Definition: NBEdge.cpp:4437
void reduceGeometry(const double minDist)
Removes points with a distance lesser than the given.
Definition: NBEdge.cpp:995
static NBEdge DummyEdge
Dummy edge to use when a reference must be supplied in the no-arguments constructor (FOX technicality...
Definition: NBEdge.h:339
bool joinLanes(SVCPermissions perms)
join adjacent lanes with the given permissions
Definition: NBEdge.cpp:4756
void resetNodeBorder(const NBNode *node)
Definition: NBEdge.cpp:719
void markAsInLane2LaneState()
mark edge as in lane to state lane
Definition: NBEdge.cpp:4047
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:3645
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:4536
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:1413
double myLength
The length of the edge.
Definition: NBEdge.h:1736
NBEdge::Lane getFirstNonPedestrianLane(int direction) const
@brif get first non-pedestrian lane
Definition: NBEdge.cpp:4477
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1494
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:3421
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:1832
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:4146
PositionVector cutAtIntersection(const PositionVector &old) const
cut shape at the intersection shapes
Definition: NBEdge.cpp:775
Position geometryPositionAtOffset(double offset) const
return position taking into account loaded length
Definition: NBEdge.cpp:4634
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
Definition: NBEdge.h:357
bool canMoveConnection(const Connection &con, int newFromLane) const
whether the connection can originate on newFromLane
Definition: NBEdge.cpp:1616
double getInternalLaneWidth(const NBNode &node, const NBEdge::Connection &connection, const NBEdge::Lane &successor, bool isVia) const
Returns the width of the internal lane associated with the connection.
Definition: NBEdge.cpp:4130
void allowVehicleClass(int lane, SUMOVehicleClass vclass)
set allowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:4054
bool isConnectedTo(const NBEdge *e, const bool ignoreTurnaround=false) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition: NBEdge.cpp:1296
double getMaxLaneOffset()
get max lane offset
Definition: NBEdge.cpp:3639
void deleteLane(int index, bool recompute, bool shiftIndices)
delete lane
Definition: NBEdge.cpp:4015
NBEdge * myPossibleTurnDestination
The edge that would be the turn destination if there was one.
Definition: NBEdge.h:1769
const PositionVector & getNodeBorder(const NBNode *node) const
Definition: NBEdge.cpp:708
const NBNode * mySignalNode
Definition: NBEdge.h:1817
bool hasLaneSpecificWidth() const
whether lanes differ in width
Definition: NBEdge.cpp:2422
void moveConnectionToRight(int lane)
Definition: NBEdge.cpp:1640
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:4425
void reshiftPosition(double xoff, double yoff)
Applies an offset to the edge.
Definition: NBEdge.cpp:543
static const int TURN_SIGN_SHIFT_TAXI
Definition: NBEdge.h:376
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition: NBEdge.cpp:3621
std::string getLaneID(int lane) const
get lane ID
Definition: NBEdge.cpp:3946
bool myIsOffRamp
whether this edge is an Off-Ramp or leads to one
Definition: NBEdge.h:1826
static const double UNSPECIFIED_SPEED
unspecified lane speed
Definition: NBEdge.h:348
Lane2LaneInfoType
Modes of setting connections between lanes.
Definition: NBEdge.h:130
@ USER
The connection was given by the user.
@ VALIDATED
The connection was computed and validated.
@ COMPUTED
The connection was computed.
double getFriction() const
Returns the friction on this edge.
Definition: NBEdge.h:622
static PositionVector startShapeAt(const PositionVector &laneShape, const NBNode *startNode, PositionVector nodeShape)
Definition: NBEdge.cpp:907
std::string getSidewalkID()
get the lane id for the canonical sidewalk lane
Definition: NBEdge.cpp:4486
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:1371
void computeLaneShapes()
compute lane shapes
Definition: NBEdge.cpp:2199
const NBEdge * getBidiEdge() const
Definition: NBEdge.h:1508
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:2136
int getSpecialLane(SVCPermissions permissions) const
return index of the first lane that allows the given permissions
Definition: NBEdge.cpp:4401
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1151
bool hasLaneSpecificEndOffset() const
whether lanes differ in offset
Definition: NBEdge.cpp:2444
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:2084
double myDistance
The mileage/kilometrage at the start of this edge in a linear coordination system.
Definition: NBEdge.h:1755
bool myAmMacroscopicConnector
Information whether this edge is a (macroscopic) connector.
Definition: NBEdge.h:1807
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1346
void setLaneShape(int lane, const PositionVector &shape)
sets a custom lane shape
Definition: NBEdge.cpp:4263
double myLoadedLength
An optional length to use (-1 if not valid)
Definition: NBEdge.h:1801
static void updateTurnPermissions(SVCPermissions &perm, LinkDirection dir, SVCPermissions spec, std::vector< LinkDirection > dirs)
Definition: NBEdge.cpp:2630
void sortOutgoingConnectionsByAngle()
sorts the outgoing connections by their angle relative to their junction
Definition: NBEdge.cpp:1385
bool applyTurnSigns()
apply loaded turn sign information
Definition: NBEdge.cpp:2641
bool haveIntersection(const NBNode &n, const PositionVector &shape, const NBEdge *otherFrom, const NBEdge::Connection &otherCon, int numPoints, double width1, double width2, int shapeFlag=0) const
Definition: NBEdge.cpp:2074
void preferVehicleClass(int lane, SVCPermissions vclasses)
prefer certain vehicle classes for the given lane or for all lanes if -1 is given (ensures also permi...
Definition: NBEdge.cpp:4080
double myStartAngle
The angles of the edge.
Definition: NBEdge.h:1740
double getAngleAtNodeNormalized(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node and disregards edge direction.
Definition: NBEdge.cpp:2120
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3937
void shiftPositionAtNode(NBNode *node, NBEdge *opposite)
shift geometry at the given node to avoid overlap
Definition: NBEdge.cpp:4609
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:2110
bool hasLaneSpecificType() const
whether lanes differ in type
Definition: NBEdge.cpp:2433
PositionVector myFromBorder
intersection borders (because the node shape might be invalid)
Definition: NBEdge.h:1821
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.cpp:4355
bool hasDefaultGeometry() const
Returns whether the geometry consists only of the node positions.
Definition: NBEdge.cpp:589
bool myAmInTLS
Information whether this is lies within a joined tls.
Definition: NBEdge.h:1804
void setTurningDestination(NBEdge *e, bool onlyPossible=false)
Sets the turing destination at the given edge.
Definition: NBEdge.cpp:2151
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:602
NBEdge * myTurnDestination
The turn destination edge (if a connection exists)
Definition: NBEdge.h:1766
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:523
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:866
double assignInternalLaneLength(std::vector< Connection >::iterator i, int numLanes, double lengthSum, bool averageLength)
assign length to all lanes of an internal edge
Definition: NBEdge.cpp:1961
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:342
bool hasRestrictedLane(SUMOVehicleClass vclass) const
returns whether any lane already allows the given vclass exclusively
Definition: NBEdge.cpp:4525
void copyConnectionsFrom(NBEdge *src)
copy connections from antoher edge
Definition: NBEdge.cpp:1609
const StopOffset & getLaneStopOffset(int lane) const
Returns the stop offset to the specified lane's end.
Definition: NBEdge.cpp:4167
void debugPrintConnections(bool outgoing=true, bool incoming=false) const
debugging helper to print all connections
Definition: NBEdge.cpp:4732
Position mySignalPosition
the position of a traffic light signal on this edge
Definition: NBEdge.h:1816
void replaceInConnections(NBEdge *which, NBEdge *by, int laneOff)
replace in current connections of edge
Definition: NBEdge.cpp:1506
bool lanesWereAssigned() const
Check if lanes were assigned.
Definition: NBEdge.cpp:3633
void restoreRestrictedLane(SUMOVehicleClass vclass, std::vector< NBEdge::Lane > oldLanes, PositionVector oldGeometry, std::vector< NBEdge::Connection > oldConnections)
restore a restricted lane
Definition: NBEdge.cpp:4575
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:685
bool isRailDeadEnd() const
whether this edge is a railway edge that does not continue
Definition: NBEdge.cpp:760
double myFriction
The current friction.
Definition: NBEdge.h:1752
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4177
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:345
void sortOutgoingConnectionsByIndex()
sorts the outgoing connections by their from-lane-index and their to-lane-index
Definition: NBEdge.cpp:1391
bool recheckLanes()
recheck whether all lanes within the edge are all right and optimises the connections once again
Definition: NBEdge.cpp:2863
int myFromJunctionPriority
The priority normalised for the node the edge is outgoing of.
Definition: NBEdge.h:1772
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:1134
void setOrigID(const std::string origID, const bool append, const int laneIdx=-1)
set origID for all lanes or for a specific lane
Definition: NBEdge.cpp:4666
PositionVector computeLaneShape(int lane, double offset) const
Computes the shape for the given lane.
Definition: NBEdge.cpp:2251
bool allowsChangingLeft(int lane, SUMOVehicleClass vclass) const
Returns whether the given vehicle class may change left from this lane.
Definition: NBEdge.cpp:4449
static int getLaneIndexFromLaneID(const std::string laneID)
Definition: NBEdge.cpp:4751
bool hasConnectionTo(const NBEdge *destEdge, int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1290
bool hasCustomLaneShape() const
whether one of the lanes has a custom shape
Definition: NBEdge.cpp:2479
bool hasLaneParams() const
whether one of the lanes has parameters set
Definition: NBEdge.cpp:2490
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:967
double getShapeEndAngle() const
Returns the angle at the end of the edge.
Definition: NBEdge.cpp:2369
bool prohibitsChanging() const
whether one of the lanes prohibits lane changing
Definition: NBEdge.cpp:2500
void setLoadedLength(double val)
set loaded length
Definition: NBEdge.cpp:4323
PositionVector myGeom
The geometry for the edge.
Definition: NBEdge.h:1778
const PositionVector getInnerGeometry() const
Returns the geometry of the edge without the endpoints.
Definition: NBEdge.cpp:583
void decLaneNo(int by)
decrement lane
Definition: NBEdge.cpp:4035
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1730
void append(NBEdge *continuation)
append another edge
Definition: NBEdge.cpp:3875
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:2094
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:4644
void shortenGeometryAtNode(const NBNode *node, double reduction)
linearly extend the geometry at the given node
Definition: NBEdge.cpp:662
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:618
int myPriority
The priority of the edge.
Definition: NBEdge.h:1746
std::string myStreetName
The street name (or whatever arbitrary string you wish to attach)
Definition: NBEdge.h:1810
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:535
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1358
int getFirstNonPedestrianNonBicycleLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN, SVC_BICYCLE and 0
Definition: NBEdge.cpp:4384
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:58
A definition of a pedestrian crossing.
Definition: NBNode.h:135
PositionVector shape
The crossing's shape.
Definition: NBNode.h:144
bool priority
whether the pedestrians have priority
Definition: NBNode.h:158
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:142
double width
This crossing's width.
Definition: NBNode.h:150
Represents a single node (junction) during network building.
Definition: NBNode.h:66
void addIncomingEdge(NBEdge *edge)
adds an incoming edge
Definition: NBNode.cpp:490
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:2349
static const int AVOID_INTERSECTING_LEFT_TURNS
Definition: NBNode.h:226
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1920
bool needsCont(const NBEdge *fromE, const NBEdge *otherFromE, const NBEdge::Connection &c, const NBEdge::Connection &otherC, bool checkOnlyTLS=false) const
whether an internal junction should be built at from and respect other
Definition: NBNode.cpp:935
FringeType getFringeType() const
Returns fringe type.
Definition: NBNode.h:305
static const int BACKWARD
Definition: NBNode.h:217
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:285
bool isTrafficLight() const
Definition: NBNode.h:822
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBNode.cpp:2034
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:2179
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:273
bool bidiConflict(const NBEdge *from, const NBEdge::Connection &con, const NBEdge *prohibitorFrom, const NBEdge::Connection &prohibitorCon, bool foes) const
whether the foe connections is oncoming on the same lane
Definition: NBNode.cpp:2105
PositionVector computeSmoothShape(const PositionVector &begShape, const PositionVector &endShape, int numPoints, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, NBNode *recordError=0, int shapeFlag=0) const
Compute a smooth curve between the given geometries.
Definition: NBNode.cpp:545
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:2160
bool mergeConflict(const NBEdge *from, const NBEdge::Connection &con, const NBEdge *prohibitorFrom, const NBEdge::Connection &prohibitorCon, bool foes) const
whether multiple connections from the same edge target the same lane
Definition: NBNode.cpp:2096
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:268
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.cpp:2918
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:500
bool isConstantWidthTransition() const
detects whether a given junction splits or merges lanes while keeping constant road width
Definition: NBNode.cpp:878
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
Definition: NBNode.h:336
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:2605
const Position & getPosition() const
Definition: NBNode.h:260
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:216
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:2189
PositionVector computeInternalLaneShape(const 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:793
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:449
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3753
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:331
static const int SCURVE_IGNORE
Definition: NBNode.h:227
static const double MIN_SPEED_CROSSING_TIME
minimum speed for computing time to cross intersection
Definition: NBOwnTLDef.h:152
Base class for objects which have an id.
Definition: Named.h:54
std::string myID
The name of the object.
Definition: Named.h:125
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
void mergeParameters(const Parameterised::Map &mapArg, const std::string separator=" ", bool uniqueValues=true)
Adds or appends all given parameters from the map.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
void updateParameters(const Parameterised::Map &mapArg)
Adds or updates all given parameters from the map.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:317
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:271
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:132
void setz(double z)
set position z
Definition: Position.h:80
double z() const
Returns the z-position.
Definition: Position.h:65
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition: Position.h:281
void sety(double y)
set position y
Definition: Position.h:75
double y() const
Returns the y-position.
Definition: Position.h:60
A list of positions.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position
double length() const
Returns the length.
void push_front_noDoublePos(const Position &p)
insert in front a non double position
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void add(double xoff, double yoff, double zoff)
void closePolygon()
ensures that the last position equals the first
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 ...
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0, double deg=90) const
return orthogonal through p (extending this vector if necessary)
std::pair< PositionVector, PositionVector > splitAt(double where, bool use2D=false) const
Returns the two lists made when this list vector is splitted at the given point.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
bool almostSame(const PositionVector &v2, double maxDiv=POSITION_EPS) const
check if the two vectors have the same length and pairwise similar positions
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
bool hasElevation() const
return whether two positions differ in z-coordinate
static const PositionVector EMPTY
empty Vector
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void push_back_noDoublePos(const Position &p)
insert in back a non double position
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false, int beginOffset=0, int endOffset=0, bool resample=false)
Removes positions if too near.
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
PositionVector reverse() const
reverse position vector
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
static bool isValidNetID(const std::string &value)
whether the given string is a valid id for a network element
stop offset
bool isDefined() const
check if stopOffset was defined
double getOffset() const
get offset
std::vector< std::string > getVector()
return vector of strings
Some static methods for string processing.
Definition: StringUtils.h:40
static std::string convertUmlaute(std::string str)
Converts german "Umlaute" to their latin-version.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static T maxValue(const std::vector< T > &v)
Definition: VectorHelper.h:87
#define M_PI
Definition: odrSpiral.cpp:45
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:201
bool indirectLeft
Whether this connection is an indirect left turn.
Definition: NBEdge.h:261
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:210
std::string viaID
if Connection have a via, ID of it
Definition: NBEdge.h:279
int toLane
The lane the connections yields in.
Definition: NBEdge.h:216
std::vector< int > foeInternalLinks
FOE Internal links.
Definition: NBEdge.h:288
Connection(int fromLane_, NBEdge *toEdge_, int toLane_, const bool mayDefinitelyPass_=false)
Constructor.
Definition: NBEdge.cpp:103
double speed
custom speed for connection
Definition: NBEdge.h:240
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:213
double customLength
custom length for connection
Definition: NBEdge.h:246
double vmax
maximum velocity
Definition: NBEdge.h:273
PositionVector customShape
custom shape for connection
Definition: NBEdge.h:249
PositionVector viaShape
shape of via
Definition: NBEdge.h:282
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:97
double contPos
custom position for internal junction on this connection
Definition: NBEdge.h:234
std::string getInternalLaneID() const
get ID of internal lane
Definition: NBEdge.cpp:91
int internalLaneIndex
The lane index of this internal lane within the internal edge.
Definition: NBEdge.h:294
std::string tlID
The id of the traffic light that controls this connection.
Definition: NBEdge.h:219
int tlLinkIndex2
The index of the internal junction within the controlling traffic light (optional)
Definition: NBEdge.h:225
double length
computed length (average of all internal lane shape lengths that share an internal edge)
Definition: NBEdge.h:306
PositionVector shape
shape of Connection
Definition: NBEdge.h:270
std::string id
id of Connection
Definition: NBEdge.h:267
std::vector< std::string > foeIncomingLanes
FOE Incomings lanes.
Definition: NBEdge.h:291
bool haveVia
check if Connection have a Via
Definition: NBEdge.h:276
int tlLinkIndex
The index of this connection within the controlling traffic light.
Definition: NBEdge.h:222
double friction
Definition: NBEdge.h:243
double viaLength
the length of the via shape (maybe customized)
Definition: NBEdge.h:285
static ConstRouterEdgePairVector myViaSuccessors
Definition: NBEdge.h:310
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:143
double width
This lane's width.
Definition: NBEdge.h:176
std::string oppositeID
An opposite lane ID, if given.
Definition: NBEdge.h:179
SVCPermissions changeRight
List of vehicle types that are allowed to change right from this lane.
Definition: NBEdge.h:166
SVCPermissions changeLeft
List of vehicle types that are allowed to change Left from this lane.
Definition: NBEdge.h:163
Lane(NBEdge *e, const std::string &_origID)
constructor
Definition: NBEdge.cpp:113
bool accelRamp
Whether this lane is an acceleration lane.
Definition: NBEdge.h:182
PositionVector shape
The lane's shape.
Definition: NBEdge.h:148