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