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