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