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 /****************************************************************************/
NBEdge::Lane getFirstNonPedestrianLane(int direction) const
get first non-pedestrian lane
Definition: NBEdge.cpp:3127
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:32
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
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 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.
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1429
bool includes(Direction d) const
returns the information whether the street in the given direction has a higher priority ...
Definition: NBEdge.cpp:231
double vmax
maximun velocity
Definition: NBEdge.h:222
PositionVector cutAtIntersection(const PositionVector &old) const
cut shape at the intersection shapes
Definition: NBEdge.cpp:630
double z() const
Returns the z-position.
Definition: Position.h:72
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:249
const std::string & getTypeID() const
get ID of type
Definition: NBEdge.h:982
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:2514
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 toLane
The lane the connections yields in.
Definition: NBEdge.h:189
std::string foeIncomingLanes
FOE Incomings lanes.
Definition: NBEdge.h:237
static const double UNSPECIFIED_LOADED_LENGTH
no length override given
Definition: NBEdge.h:269
is a pedestrian
int getTLIndex() const
returns the index within the controlling tls or InvalidTLIndex if this link is unontrolled ...
Definition: NBConnection.h:99
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)
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1418
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 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
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:186
bool hasDefaultGeometry() const
Returns whether the geometry consists only of the node positions.
Definition: NBEdge.cpp:508
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset)
patches loaded signal plans by modifying lane indices
Definition: NBNode.cpp:370
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
bool hasAccelLane() const
whether one of the lanes is an acceleration lane
Definition: NBEdge.cpp:1828
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 getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1611
void reduceGeometry(const double minDist)
Removes points with a distance lesser than the given.
Definition: NBEdge.cpp:845
bool expandableBy(NBEdge *possContinuation, std::string &reason) const
Check if Node is expandable.
Definition: NBEdge.cpp:2637
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point...
double myLaneWidth
This width of this edge&#39;s lanes.
Definition: NBEdge.h:1424
bool empty() const
returns the information whether no following street has a higher priority
Definition: NBEdge.cpp:225
std::vector< Connection > getConnectionsFromLane(int lane) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1037
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
Definition: NBEdge.cpp:2795
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn&#39;t set.
Definition: NBEdge.h:489
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
bool hasLaneSpecificEndOffset() const
whether lanes differ in offset
Definition: NBEdge.cpp:1817
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
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:297
Holds (- relative to the edge it is build from -!!!) the list of main directions a vehicle that drive...
Definition: NBEdge.h:1264
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:2935
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
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:569
void moveConnectionToLeft(int lane)
Definition: NBEdge.cpp:1366
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1281
vehicle is a bicycle
const double SUMO_const_laneWidth
Definition: StdDefs.h:49
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 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
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
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
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:2503
bool hasDefaultGeometryEndpoints() const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:514
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.
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
int getFromLane() const
returns the from-lane
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:272
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
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:86
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1146
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
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) ...
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
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.h:557
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
TLS Disabled Connections.
Definition: NBEdge.h:1441
Lanes to lanes - relationships are computed; should be recheked.
Definition: NBEdge.h:97
T MAX2(T a, T b)
Definition: StdDefs.h:73
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
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:547
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:506
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
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 getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
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
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 getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
PositionVector myGeom
The geometry for the edge.
Definition: NBEdge.h:1415
double visibility
custom foe visiblity for connection
Definition: NBEdge.h:207
const std::map< std::string, std::string > & getMap() const
Returns the inner key/value map.
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
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0) const
return orthogonal through p (extending this vector if necessary)
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
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
void shiftLaneIndex(NBEdge *edge, int offset)
patches lane indices refering to the given edge
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
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
The connection was computed and validated.
Definition: NBEdge.h:114
#define DEBUGCOND
Definition: NBEdge.cpp:59
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
PositionVector reverse() const
reverse position vector
The edge has been loaded, nothing is computed yet.
Definition: NBEdge.h:91
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
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1134
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
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:254
bool hasPermissions() const
whether at least one lane has restrictions
Definition: NBEdge.cpp:1770
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:121
const std::string & getID() const
Returns the id.
Definition: Named.h:65
void addLane(int index, bool recompute=true)
add lane
Definition: NBEdge.cpp:2803
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
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 myAmMacroscopicConnector
Information whether this edge is a (macroscopic) connector.
Definition: NBEdge.h:1438
double getShapeEndAngle() const
Returns the angle at the end of the edge.
Definition: NBEdge.cpp:1762
const PositionVector getInnerGeometry() const
Returns the geometry of the edge without the endpoints.
Definition: NBEdge.cpp:502
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.
const Position & getPosition() const
Definition: NBNode.h:241
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
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
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
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
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:522
int operator()(const Connection &c1, const Connection &c2) const
comparing operation
Definition: NBEdge.cpp:240
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
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
bool hasLaneSpecificSpeed() const
whether lanes differ in speed
Definition: NBEdge.cpp:1795
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:419
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
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
std::string getInternalLaneID() const
get ID of internal lane
Definition: NBEdge.cpp:80
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
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
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition: NBEdge.cpp:2477
bool hasLaneSpecificPermissions() const
whether lanes differ in allowed vehicle classes
Definition: NBEdge.cpp:1781
bool lanesWereAssigned() const
Check if lanes were assigned.
Definition: NBEdge.cpp:2491
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
const std::map< NBEdge *, std::vector< int > > & getBuiltConnections() const
get built connections
Definition: NBEdge.h:1244
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:266
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2596
NBEdge * myPossibleTurnDestination
The edge that would be the turn destination if there was one.
Definition: NBEdge.h:1406
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 computeLaneShape(int lane, double offset) const
Computes the shape for the given lane.
Definition: NBEdge.cpp:1697
bool hasLoadedLength() const
Returns whether a length was set explicitly.
Definition: NBEdge.h:499
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:412
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2450
double length() const
Returns the length.
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
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:3067
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:67
bool needsLaneSpecificOutput() const
whether at least one lane has values differing from the edges values
Definition: NBEdge.cpp:1860
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
bool canMoveConnection(const Connection &con, int newFromLane) const
whether the connection can originate on newFromLane
Definition: NBEdge.cpp:1357
#define POSITION_EPS
Definition: config.h:175
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
std::string getLaneIDInsecure(int lane) const
get Lane ID (Insecure)
Definition: NBEdge.cpp:2789
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
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
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
#define DEG2RAD(x)
Definition: GeomHelper.h:44
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
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
void execute(const int lane, const int virtEdge)
executes a bresenham - step
Definition: NBEdge.cpp:142
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
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1726
The link is a partial right direction.
double speed
The speed allowed on this lane.
Definition: NBEdge.h:129
void move2side(double amount)
move position vector to side using certain ammount
vehicle is a passenger car (a "normal" car)
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:239
bool myAmInnerEdge
Information whether this is a junction-inner edge.
Definition: NBEdge.h:1435
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
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
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
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1591
PositionVector startShapeAt(const PositionVector &laneShape, const NBNode *startNode, PositionVector nodeShape) const
Definition: NBEdge.cpp:712
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
int internalLaneIndex
The lane index of this internal lane within the internal edge.
Definition: NBEdge.h:240
void extendGeometryAtNode(const NBNode *node, double maxExtent)
linearly extend the geometry at the given node
Definition: NBEdge.cpp:546
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3025
vehicle is a bus
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
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
double getLaneSpeed(int lane) const
get lane speed
Definition: NBEdge.cpp:1647
bool hasLaneParams() const
whether one of the lanes has parameters set
Definition: NBEdge.cpp:1850
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
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:433
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:480
double width
This crossing&#39;s width.
Definition: NBNode.h:143
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
double length2D() 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
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
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:40
static const int UNSPECIFIED_INTERNAL_LANE_INDEX
internal lane computation not yet done
Definition: NBEdge.h:277
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
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:602
The edge has been loaded and connections shall not be added.
Definition: NBEdge.h:89
double getFinalLength() const
get length that will be assigned to the lanes in the final network
Definition: NBEdge.cpp:3269
int getToLane() const
returns the to-lane
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
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
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
NBEdge * getTo() const
returns the to-edge (end of the connection)
The connection was computed.
Definition: NBEdge.h:110
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge&#39;s lanes&#39; lateral offset is computed.
Definition: NBEdge.h:684
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:137
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
bool hasSignalisedConnectionTo(const NBEdge *const e) const
Check if edge has signalised connections.
Definition: NBEdge.cpp:2763
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
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
bool hasLaneSpecificWidth() const
whether lanes differ in width
Definition: NBEdge.cpp:1806
bool hasCustomLaneShape() const
whether one of the lanes has a custom shape
Definition: NBEdge.cpp:1839
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
double getShapeStartAngle() const
Returns the angle at the start of the edge.
Definition: NBEdge.cpp:1754
Direction
enum of possible directions
Definition: NBEdge.h:1267
std::pair< PositionVector, PositionVector > splitAt(double where) const
Returns the two lists made when this list vector is splitted at the given point.
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
std::string getLaneID(int lane) const
get Lane ID (Secure)
Definition: NBEdge.cpp:2783
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
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 * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:108
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
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
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
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
void add(double xoff, double yoff, double zoff)
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
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
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.cpp:2038
#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
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:3098
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
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:535
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1376
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:2774
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
std::vector< int > foeInternalLinks
FOE Internal links.
Definition: NBEdge.h:234
~MainDirections()
destructor
Definition: NBEdge.cpp:221
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:778
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
double angleAt2D(int pos) const
get angle in certain position of position vector
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
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
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
double beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position ...
void reshiftPosition(double xoff, double yoff)
Applies an offset to the edge.
Definition: NBEdge.cpp:474
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
void setz(double z)
set position z
Definition: Position.h:87
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:426
bool splitGeometry(NBEdgeCont &ec, NBNodeCont &nc)
Splits this edge at geometry points.
Definition: NBEdge.cpp:800