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