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