SUMO - Simulation of Urban MObility
NBEdge.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // Methods for the representation of a single edge
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
14 // Copyright (C) 2001-2015 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 
26 // ===========================================================================
27 // included modules
28 // ===========================================================================
29 #ifdef _MSC_VER
30 #include <windows_config.h>
31 #else
32 #include <config.h>
33 #endif
34 
35 #include <vector>
36 #include <string>
37 #include <algorithm>
38 #include <cassert>
39 #include "NBEdgeCont.h"
40 #include "NBNode.h"
41 #include "NBNodeCont.h"
42 #include "NBContHelper.h"
43 #include "NBHelpers.h"
44 #include <cmath>
45 #include <iomanip>
46 #include "NBTypeCont.h"
47 #include <utils/geom/GeomHelper.h>
50 #include <utils/common/ToString.h>
52 #include <utils/common/StdDefs.h>
53 #include "NBEdge.h"
56 
57 #ifdef CHECK_MEMORY_LEAKS
58 #include <foreign/nvwa/debug_new.h>
59 #endif // CHECK_MEMORY_LEAKS
60 
61 #define DEBUGID "disabled"
62 
63 // ===========================================================================
64 // static members
65 // ===========================================================================
70 
74 
75 // ===========================================================================
76 // method definitions
77 // ===========================================================================
78 std::string
80  return id + "_" + toString(internalLaneIndex);
81 }
82 
83 /* -------------------------------------------------------------------------
84  * NBEdge::ToEdgeConnectionsAdder-methods
85  * ----------------------------------------------------------------------- */
86 void
87 NBEdge::ToEdgeConnectionsAdder::execute(const unsigned int lane, const unsigned int virtEdge) {
88  // check
89  assert(myTransitions.size() > virtEdge);
90  // get the approached edge
91  NBEdge* succEdge = myTransitions[virtEdge];
92  std::vector<unsigned int> lanes;
93 
94  // check whether the currently regarded, approached edge has already
95  // a connection starting at the edge which is currently being build
96  std::map<NBEdge*, std::vector<unsigned int> >::iterator i = myConnections.find(succEdge);
97  if (i != myConnections.end()) {
98  // if there were already lanes assigned, get them
99  lanes = (*i).second;
100  }
101 
102  // check whether the current lane was already used to connect the currently
103  // regarded approached edge
104  std::vector<unsigned int>::iterator j = find(lanes.begin(), lanes.end(), lane);
105  if (j == lanes.end()) {
106  // if not, add it to the list
107  lanes.push_back(lane);
108  }
109  // set information about connecting lanes
110  myConnections[succEdge] = lanes;
111 }
112 
113 
114 
115 /* -------------------------------------------------------------------------
116  * NBEdge::MainDirections-methods
117  * ----------------------------------------------------------------------- */
119  NBEdge* parent, NBNode* to) {
120  if (outgoing.size() == 0) {
121  return;
122  }
123  // check whether the right turn has a higher priority
124  assert(outgoing.size() > 0);
125  if (outgoing[0]->getJunctionPriority(to) == 1) {
126  myDirs.push_back(MainDirections::DIR_RIGHTMOST);
127  }
128  // check whether the left turn has a higher priority
129  if (outgoing.back()->getJunctionPriority(to) == 1) {
130  // ok, the left turn belongs to the higher priorised edges on the junction
131  // let's check, whether it has also a higher priority (lane number/speed)
132  // than the current
133  EdgeVector tmp(outgoing);
134  sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
135  if (outgoing.back()->getPriority() > tmp[0]->getPriority()) {
136  myDirs.push_back(MainDirections::DIR_LEFTMOST);
137  } else {
138  if (outgoing.back()->getNumLanes() > tmp[0]->getNumLanes()) {
139  myDirs.push_back(MainDirections::DIR_LEFTMOST);
140  }
141  }
142  }
143  // check whether the forward direction has a higher priority
144  // try to get the forward direction
145  EdgeVector tmp(outgoing);
146  sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
147  NBEdge* edge = *(tmp.begin());
148  // check whether it has a higher priority and is going straight
149  if (edge->getJunctionPriority(to) == 1 && to->getDirection(parent, edge) == LINKDIR_STRAIGHT) {
150  myDirs.push_back(MainDirections::DIR_FORWARD);
151  }
152 }
153 
154 
156 
157 
158 bool
160  return myDirs.empty();
161 }
162 
163 
164 bool
166  return find(myDirs.begin(), myDirs.end(), d) != myDirs.end();
167 }
168 
169 
170 /* -------------------------------------------------------------------------
171  * NBEdge::connections_relative_edgelane_sorter-methods
172  * ----------------------------------------------------------------------- */
173 int
175  if (c1.toEdge != c2.toEdge) {
177  }
178  return c1.toLane < c2.toLane;
179 }
180 
181 
182 /* -------------------------------------------------------------------------
183  * NBEdge-methods
184  * ----------------------------------------------------------------------- */
185 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
186  std::string type, SUMOReal speed, unsigned int nolanes,
187  int priority, SUMOReal laneWidth, SUMOReal offset,
188  const std::string& streetName,
189  LaneSpreadFunction spread) :
190  Named(StringUtils::convertUmlaute(id)),
191  myStep(INIT),
192  myType(StringUtils::convertUmlaute(type)),
193  myFrom(from), myTo(to),
195  myPriority(priority), mySpeed(speed),
199  myLaneSpreadFunction(spread), myEndOffset(offset), myLaneWidth(laneWidth),
202  myStreetName(streetName),
204  init(nolanes, false, "");
205 }
206 
207 
208 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
209  std::string type, SUMOReal speed, unsigned int nolanes,
210  int priority, SUMOReal laneWidth, SUMOReal offset,
211  PositionVector geom,
212  const std::string& streetName,
213  const std::string& origID,
214  LaneSpreadFunction spread, bool tryIgnoreNodePositions) :
215  Named(StringUtils::convertUmlaute(id)),
216  myStep(INIT),
217  myType(StringUtils::convertUmlaute(type)),
218  myFrom(from), myTo(to),
220  myPriority(priority), mySpeed(speed),
224  myGeom(geom), myLaneSpreadFunction(spread), myEndOffset(offset), myLaneWidth(laneWidth),
227  myStreetName(streetName),
229  init(nolanes, tryIgnoreNodePositions, origID);
230 }
231 
232 
233 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to, NBEdge* tpl, const PositionVector& geom, int numLanes) :
234  Named(StringUtils::convertUmlaute(id)),
235  myStep(INIT),
236  myType(tpl->getTypeID()),
237  myFrom(from), myTo(to),
239  myPriority(tpl->getPriority()), mySpeed(tpl->getSpeed()),
243  myGeom(geom),
245  myEndOffset(tpl->getEndOffset()),
246  myLaneWidth(tpl->getLaneWidth()),
248  myAmInnerEdge(false),
250  myStreetName(tpl->getStreetName()),
252  init(numLanes > 0 ? numLanes : tpl->getNumLanes(), myGeom.size() > 0, "");
253  for (unsigned int i = 0; i < getNumLanes(); i++) {
254  const unsigned int tplIndex = MIN2(i, tpl->getNumLanes() - 1);
255  setSpeed(i, tpl->getLaneSpeed(tplIndex));
256  setPermissions(tpl->getPermissions(tplIndex), i);
257  setLaneWidth(i, tpl->myLanes[tplIndex].width);
258  if (to == tpl->myTo) {
259  setEndOffset(i, tpl->myLanes[tplIndex].endOffset);
260  }
261  }
262 }
263 
264 
265 void
266 NBEdge::reinit(NBNode* from, NBNode* to, const std::string& type,
267  SUMOReal speed, unsigned int nolanes, int priority,
268  PositionVector geom, SUMOReal laneWidth, SUMOReal offset,
269  const std::string& streetName,
270  LaneSpreadFunction spread,
271  bool tryIgnoreNodePositions) {
272  if (myFrom != from) {
273  myFrom->removeEdge(this, false);
274  }
275  if (myTo != to) {
276  myTo->removeEdge(this, false);
277  }
279  myFrom = from;
280  myTo = to;
281  myPriority = priority;
282  //?myTurnDestination(0),
283  //?myFromJunctionPriority(-1), myToJunctionPriority(-1),
284  myGeom = geom;
285  myLaneSpreadFunction = spread;
287  myStreetName = streetName;
288  //?, myAmTurningWithAngle(0), myAmTurningOf(0),
289  //?myAmInnerEdge(false), myAmMacroscopicConnector(false)
290 
291  // preserve lane-specific settings (geometry must be recomputed)
292  // if new lanes are added they copy the values from the leftmost lane (if specified)
293  const std::vector<Lane> oldLanes = myLanes;
294  init(nolanes, tryIgnoreNodePositions, oldLanes.empty() ? "" : oldLanes[0].origID);
295  for (int i = 0; i < (int)nolanes; ++i) {
296  PositionVector newShape = myLanes[i].shape;
297  myLanes[i] = oldLanes[MIN2(i, (int)oldLanes.size() - 1)];
298  myLanes[i].shape = newShape;
299  }
300  // however, if the new edge defaults are explicityly given, they override the old settings
301  if (offset != UNSPECIFIED_OFFSET) {
302  setEndOffset(-1, offset);
303  }
304  if (laneWidth != UNSPECIFIED_WIDTH) {
305  setLaneWidth(-1, laneWidth);
306  }
307  if (speed != UNSPECIFIED_SPEED) {
308  setSpeed(-1, speed);
309  }
310 }
311 
312 
313 void
315  // connections may still be valid
316  if (from == 0 || to == 0) {
317  throw ProcessError("At least one of edge's '" + myID + "' nodes is not known.");
318  }
319  if (myFrom != from) {
320  myFrom->removeEdge(this, false);
321  myFrom = from;
322  myFrom->addOutgoingEdge(this);
323  }
324  if (myTo != to) {
325  myTo->removeEdge(this, false);
326  myTo = to;
327  myTo->addIncomingEdge(this);
328  }
329  computeAngle();
330 }
331 
332 
333 void
334 NBEdge::init(unsigned int noLanes, bool tryIgnoreNodePositions, const std::string& origID) {
335  if (noLanes == 0) {
336  throw ProcessError("Edge '" + myID + "' needs at least one lane.");
337  }
338  if (myFrom == 0 || myTo == 0) {
339  throw ProcessError("At least one of edge's '" + myID + "' nodes is not known.");
340  }
341  // revisit geometry
342  // should have at least two points at the end...
343  // and in dome cases, the node positions must be added
345  if (!tryIgnoreNodePositions || myGeom.size() < 2) {
346  if (myGeom.size() == 0) {
347  myGeom.push_back(myFrom->getPosition());
348  myGeom.push_back(myTo->getPosition());
349  } else {
352  }
353  }
354  if (myGeom.size() < 2) {
355  myGeom.clear();
356  myGeom.push_back(myFrom->getPosition());
357  myGeom.push_back(myTo->getPosition());
358  }
359  if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
360  WRITE_ERROR("Edge's '" + myID + "' from- and to-node are at the same position.");
362  }
363  //
364  myFrom->addOutgoingEdge(this);
365  myTo->addIncomingEdge(this);
366  // prepare container
368  assert(myGeom.size() >= 2);
369  myLanes.clear();
370  for (unsigned int i = 0; i < noLanes; i++) {
371  myLanes.push_back(Lane(this, origID));
372  }
374  computeAngle();
375 }
376 
377 
379 
380 
381 // ----------- Applying offset
382 void
384  myGeom.add(xoff, yoff, 0);
385  for (unsigned int i = 0; i < myLanes.size(); i++) {
386  myLanes[i].shape.add(xoff, yoff, 0);
387  }
388  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
389 }
390 
391 
392 void
394  myGeom.mirrorX();
395  for (unsigned int i = 0; i < myLanes.size(); i++) {
396  myLanes[i].shape.mirrorX();
397  }
398  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
399  (*i).shape.mirrorX();
400  (*i).viaShape.mirrorX();
401  }
402  computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
403 }
404 
405 
406 // ----------- Edge geometry access and computation
407 const PositionVector
409  return myGeom.getSubpartByIndex(1, (int)myGeom.size() - 2);
410 }
411 
412 
413 bool
415  return myGeom.size() == 2 && hasDefaultGeometryEndpoints();
416 }
417 
418 
419 bool
421  return myGeom.front() == myFrom->getPosition() &&
422  myGeom.back() == myTo->getPosition();
423 }
424 
425 
426 void
427 NBEdge::setGeometry(const PositionVector& s, bool inner) {
428  Position begin = myGeom.front(); // may differ from node position
429  Position end = myGeom.back(); // may differ from node position
430  myGeom = s;
431  if (inner) {
432  myGeom.insert(myGeom.begin(), begin);
433  myGeom.push_back(end);
434  }
436  computeAngle();
437 }
438 
439 
442  PositionVector shape = old;
443  shape = startShapeAt(shape, myFrom);
444  if (shape.size() >= 2) {
445  shape = startShapeAt(shape.reverse(), myTo).reverse();
446  }
447  // sanity checks
448  if (shape.length() < POSITION_EPS) {
449  if (old.length() < 2 * POSITION_EPS) {
450  shape = old;
451  } else {
452  const SUMOReal midpoint = old.length() / 2;
453  // EPS*2 because otherwhise shape has only a single point
454  shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
455  assert(shape.size() >= 2);
456  assert(shape.length() > 0);
457  }
458  } else {
459  // @note If the node shapes are overlapping we may get a shape which goes in the wrong direction
460  // in this case the result shape should shortened
461  if (DEG2RAD(135) < fabs(GeomHelper::angleDiff(shape.beginEndAngle(), old.beginEndAngle()))) {
462  shape = shape.reverse();
463  shape = shape.getSubpart(0, 2 * POSITION_EPS); // *2 because otherwhise shape has only a single point
464  }
465  }
466  return shape;
467 }
468 
469 
470 void
472  for (unsigned int i = 0; i < myLanes.size(); i++) {
473  myLanes[i].shape = cutAtIntersection(myLanes[i].shape);
474  }
475  // recompute edge's length as the average of lane lenghts
476  SUMOReal avgLength = 0;
477  for (unsigned int i = 0; i < myLanes.size(); i++) {
478  assert(myLanes[i].shape.length() > 0);
479  avgLength += myLanes[i].shape.length();
480  }
481  myLength = avgLength / (SUMOReal) myLanes.size();
482  computeAngle(); // update angles using the finalized node and lane shapes
483 }
484 
485 
487 NBEdge::startShapeAt(const PositionVector& laneShape, const NBNode* startNode) const {
488  const PositionVector& nodeShape = startNode->getShape();
489  PositionVector lb(laneShape.begin(), laneShape.begin() + 2);
490  // this doesn't look reasonable @todo use lb.extrapolateFirstBy(100.0);
491  lb.extrapolate(100.0);
492  if (nodeShape.intersects(laneShape)) {
493  // shape intersects directly
494  std::vector<SUMOReal> pbv = laneShape.intersectsAtLengths2D(nodeShape);
495  assert(pbv.size() > 0);
496  // ensure that the subpart has at least two points
498  if (pb < 0) {
499  return laneShape;
500  }
501  PositionVector ns = laneShape.getSubpart2D(pb, laneShape.length2D());
502  //PositionVector ns = pb < (laneShape.length() - POSITION_EPS) ? laneShape.getSubpart2D(pb, laneShape.length()) : laneShape;
503  ns[0].set(ns[0].x(), ns[0].y(), startNode->getPosition().z());
504  assert(ns.size() >= 2);
505  return ns;
506  } else if (nodeShape.intersects(lb)) {
507  // extension of first segment intersects
508  std::vector<SUMOReal> pbv = lb.intersectsAtLengths2D(nodeShape);
509  assert(pbv.size() > 0);
511  assert(pb >= 0);
512  PositionVector result = laneShape.getSubpartByIndex(1, (int)laneShape.size() - 1);
513  Position np = PositionVector::positionAtOffset2D(lb[0], lb[1], pb);
514  result.push_front_noDoublePos(Position(np.x(), np.y(), startNode->getPosition().z()));
515  return result;
516  //if (result.size() >= 2) {
517  // return result;
518  //} else {
519  // WRITE_WARNING(error + " (resulting shape is too short)");
520  // return laneShape;
521  //}
522  } else {
523  // could not find proper intersection. Probably the edge is very short
524  // and lies within nodeShape
525  // @todo enable warning WRITE_WARNING(error + " (laneShape lies within nodeShape)");
526  return laneShape;
527  }
528 }
529 
530 
531 const PositionVector&
532 NBEdge::getLaneShape(unsigned int i) const {
533  return myLanes[i].shape;
534 }
535 
536 
537 void
539  myLaneSpreadFunction = spread;
540 }
541 
542 
543 void
544 NBEdge::addGeometryPoint(int index, const Position& p) {
545  if (index >= 0) {
546  myGeom.insert(myGeom.begin() + index, p);
547  } else {
548  myGeom.insert(myGeom.end() + index, p);
549  }
550 }
551 
552 
553 bool
555  // check whether there any splits to perform
556  if (myGeom.size() < 3) {
557  return false;
558  }
559  // ok, split
560  NBNode* newFrom = myFrom;
561  NBNode* myLastNode = myTo;
562  NBNode* newTo = 0;
563  NBEdge* currentEdge = this;
564  for (int i = 1; i < (int) myGeom.size() - 1; i++) {
565  // build the node first
566  if (i != (int)myGeom.size() - 2) {
567  std::string nodename = myID + "_in_between#" + toString(i);
568  if (!nc.insert(nodename, myGeom[i])) {
569  throw ProcessError("Error on adding in-between node '" + nodename + "'.");
570  }
571  newTo = nc.retrieve(nodename);
572  } else {
573  newTo = myLastNode;
574  }
575  if (i == 1) {
576  currentEdge->myTo->removeEdge(this);
577  currentEdge->myTo = newTo;
578  newTo->addIncomingEdge(currentEdge);
579  } else {
580  std::string edgename = myID + "[" + toString(i - 1) + "]";
581  // @bug lane-specific width, speed, overall offset and restrictions are ignored
582  currentEdge = new NBEdge(edgename, newFrom, newTo, myType, mySpeed, (unsigned int) myLanes.size(),
584  if (!ec.insert(currentEdge, true)) {
585  throw ProcessError("Error on adding splitted edge '" + edgename + "'.");
586  }
587  }
588  newFrom = newTo;
589  }
590  myGeom.clear();
591  myGeom.push_back(myFrom->getPosition());
592  myGeom.push_back(myTo->getPosition());
593  myStep = INIT;
594  return true;
595 }
596 
597 
598 void
600  myGeom.removeDoublePoints(minDist, true);
601 }
602 
603 
604 void
605 NBEdge::checkGeometry(const SUMOReal maxAngle, const SUMOReal minRadius, bool fix) {
606  if (myGeom.size() < 3) {
607  return;
608  }
609  //std::cout << "checking geometry of " << getID() << " geometry = " << toString(myGeom) << "\n";
610  std::vector<SUMOReal> angles; // absolute segment angles
611  //std::cout << " absolute angles:";
612  for (int i = 0; i < (int)myGeom.size() - 1; ++i) {
613  angles.push_back(myGeom.angleAt2D(i));
614  //std::cout << " " << angles.back();
615  }
616  //std::cout << "\n relative angles: ";
617  for (int i = 0; i < (int)angles.size() - 1; ++i) {
618  const SUMOReal relAngle = fabs(GeomHelper::angleDiff(angles[i], angles[i + 1]));
619  //std::cout << relAngle << " ";
620  if (maxAngle > 0 && relAngle > maxAngle) {
621  WRITE_WARNING("Found angle of " + toString(RAD2DEG(relAngle)) + " degrees at edge '" + getID() + "', segment " + toString(i));
622  }
623  if (relAngle < DEG2RAD(1)) {
624  continue;
625  }
626  if (i == 0 || i == (int)angles.size() - 2) {
627  const bool start = i == 0;
628  const SUMOReal dist = (start ? myGeom[0].distanceTo2D(myGeom[1]) : myGeom[-2].distanceTo2D(myGeom[-1]));
629  const SUMOReal r = tan(0.5 * (M_PI - relAngle)) * dist;
630  //std::cout << (start ? " start" : " end") << " length=" << dist << " radius=" << r << " ";
631  if (minRadius > 0 && r < minRadius) {
632  if (fix) {
633  WRITE_MESSAGE("Removing sharp turn with radius " + toString(r) + " at the " +
634  (start ? "start" : "end") + " of edge '" + getID() + "'.");
635  myGeom.erase(myGeom.begin() + (start ? 1 : i + 1));
636  checkGeometry(maxAngle, minRadius, fix);
637  return;
638  } else {
639  WRITE_WARNING("Found sharp turn with radius " + toString(r) + " at the " +
640  (start ? "start" : "end") + " of edge '" + getID() + "'.");
641  }
642  }
643  }
644  }
645  //std::cout << "\n";
646 }
647 
648 
649 // ----------- Setting and getting connections
650 bool
653  return true;
654  }
655  // check whether the node was merged and now a connection between
656  // not matching edges is tried to be added
657  // This happens f.e. within the ptv VISSIM-example "Beijing"
658  if (dest != 0 && myTo != dest->myFrom) {
659  return false;
660  }
661  if (dest == 0) {
663  myConnections.push_back(Connection(-1, dest, -1));
664  } else if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(dest)) == myConnections.end()) {
665  myConnections.push_back(Connection(-1, dest, -1));
666  }
667  if (myStep < EDGE2EDGES) {
668  myStep = EDGE2EDGES;
669  }
670  return true;
671 }
672 
673 
674 bool
675 NBEdge::addLane2LaneConnection(unsigned int from, NBEdge* dest,
676  unsigned int toLane, Lane2LaneInfoType type,
677  bool mayUseSameDestination,
678  bool mayDefinitelyPass,
679  bool keepClear,
680  SUMOReal contPos) {
682  return true;
683  }
684  // check whether the node was merged and now a connection between
685  // not matching edges is tried to be added
686  // This happens f.e. within the ptv VISSIM-example "Beijing"
687  if (myTo != dest->myFrom) {
688  return false;
689  }
690  if (!addEdge2EdgeConnection(dest)) {
691  return false;
692  }
693  setConnection(from, dest, toLane, type, mayUseSameDestination, mayDefinitelyPass, keepClear, contPos);
694  return true;
695 }
696 
697 
698 bool
699 NBEdge::addLane2LaneConnections(unsigned int fromLane,
700  NBEdge* dest, unsigned int toLane,
701  unsigned int no, Lane2LaneInfoType type,
702  bool invalidatePrevious,
703  bool mayDefinitelyPass) {
704  if (invalidatePrevious) {
705  invalidateConnections(true);
706  }
707  bool ok = true;
708  for (unsigned int i = 0; i < no && ok; i++) {
709  ok &= addLane2LaneConnection(fromLane + i, dest, toLane + i, type, false, mayDefinitelyPass);
710  }
711  return ok;
712 }
713 
714 
715 void
716 NBEdge::setConnection(unsigned int lane, NBEdge* destEdge,
717  unsigned int destLane, Lane2LaneInfoType type,
718  bool mayUseSameDestination,
719  bool mayDefinitelyPass,
720  bool keepClear,
721  SUMOReal contPos) {
723  return;
724  }
725  // some kind of a misbehaviour which may occure when the junction's outgoing
726  // edge priorities were not properly computed, what may happen due to
727  // an incomplete or not proper input
728  // what happens is that under some circumstances a single lane may set to
729  // be approached more than once by the one of our lanes.
730  // This must not be!
731  // we test whether it is the case and do nothing if so - the connection
732  // will be refused
733  //
734  if (!mayUseSameDestination && hasConnectionTo(destEdge, destLane)) {
735  return;
736  }
737  if (find_if(myConnections.begin(), myConnections.end(), connections_finder(lane, destEdge, destLane)) != myConnections.end()) {
738  return;
739  }
740  if (myLanes.size() <= lane) {
741  WRITE_ERROR("Could not set connection from '" + getLaneIDInsecure(lane) + "' to '" + destEdge->getLaneIDInsecure(destLane) + "'.");
742  return;
743  }
744  if (destEdge->getNumLanes() <= destLane) {
745  WRITE_ERROR("Could not set connection from '" + getLaneIDInsecure(lane) + "' to '" + destEdge->getLaneIDInsecure(destLane) + "'.");
746  return;
747  }
748  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
749  if ((*i).toEdge == destEdge && ((*i).fromLane == -1 || (*i).toLane == -1)) {
750  i = myConnections.erase(i);
751  } else {
752  ++i;
753  }
754  }
755  myConnections.push_back(Connection(lane, destEdge, destLane));
756  if (mayDefinitelyPass) {
757  myConnections.back().mayDefinitelyPass = true;
758  }
759  myConnections.back().keepClear = keepClear;
760  myConnections.back().contPos = contPos;
761  if (type == L2L_USER) {
763  } else {
764  // check whether we have to take another look at it later
765  if (type == L2L_COMPUTED) {
766  // yes, the connection was set using an algorithm which requires a recheck
768  } else {
769  // ok, let's only not recheck it if we did no add something that has to be recheked
770  if (myStep != LANES2LANES_RECHECK) {
772  }
773  }
774  }
775 }
776 
777 
778 std::vector<NBEdge::Connection>
779 NBEdge::getConnectionsFromLane(unsigned int lane) const {
780  std::vector<NBEdge::Connection> ret;
781  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
782  if ((*i).fromLane == static_cast<int>(lane)) {
783  ret.push_back(*i);
784  }
785  }
786  return ret;
787 }
788 
789 
791 NBEdge::getConnection(int fromLane, const NBEdge* to, int toLane) const {
792  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
793  if (
794  (*i).fromLane == fromLane
795  && (*i).toEdge == to
796  && (*i).toLane == toLane) {
797  return *i;
798  }
799  }
800  throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
801  + " to " + to->getID() + "_" + toString(toLane) + " not found");
802 }
803 
804 
805 bool
806 NBEdge::hasConnectionTo(NBEdge* destEdge, unsigned int destLane, int fromLane) const {
807  return destEdge != 0 && find_if(myConnections.begin(), myConnections.end(), connections_toedgelane_finder(destEdge, destLane, fromLane)) != myConnections.end();
808 }
809 
810 
811 bool
813  if (e == myTurnDestination) {
814  return true;
815  }
816  return
817  find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(e))
818  !=
819  myConnections.end();
820 
821 }
822 
823 
824 const EdgeVector*
826  // check whether connections exist and if not, use edges from the node
827  EdgeVector outgoing;
828  if (myConnections.size() == 0) {
829  outgoing = myTo->getOutgoingEdges();
830  } else {
831  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
832  if (find(outgoing.begin(), outgoing.end(), (*i).toEdge) == outgoing.end()) {
833  outgoing.push_back((*i).toEdge);
834  }
835  }
836  }
837  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
838  if (it->fromLane < 0 && it->toLane < 0) {
839  // found an edge that shall not be connected
840  EdgeVector::iterator forbidden = find(outgoing.begin(), outgoing.end(), it->toEdge);
841  if (forbidden != outgoing.end()) {
842  outgoing.erase(forbidden);
843  }
844  }
845  }
846  // allocate the sorted container
847  unsigned int size = (unsigned int) outgoing.size();
848  EdgeVector* edges = new EdgeVector();
849  edges->reserve(size);
850  for (EdgeVector::const_iterator i = outgoing.begin(); i != outgoing.end(); i++) {
851  NBEdge* outedge = *i;
852  if (outedge != 0 && outedge != myTurnDestination) {
853  edges->push_back(outedge);
854  }
855  }
856  sort(edges->begin(), edges->end(), NBContHelper::relative_outgoing_edge_sorter(this));
857  return edges;
858 }
859 
860 
863  EdgeVector ret;
864  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
865  if (find(ret.begin(), ret.end(), (*i).toEdge) == ret.end()) {
866  ret.push_back((*i).toEdge);
867  }
868  }
869  return ret;
870 }
871 
872 
873 std::vector<int>
874 NBEdge::getConnectionLanes(NBEdge* currentOutgoing) const {
875  std::vector<int> ret;
876  if (currentOutgoing != myTurnDestination) {
877  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
878  if ((*i).toEdge == currentOutgoing) {
879  ret.push_back((*i).fromLane);
880  }
881  }
882  }
883  return ret;
884 }
885 
886 
887 void
890 }
891 
892 
893 void
895  sort(myConnections.begin(), myConnections.end(), connections_sorter);
896 }
897 
898 
899 void
901  EdgeVector connected = getConnectedEdges();
902  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
903  NBEdge* inc = *i;
904  // We have to do this
905  inc->myStep = EDGE2EDGES;
906  // add all connections
907  for (EdgeVector::iterator j = connected.begin(); j != connected.end(); j++) {
908  inc->addEdge2EdgeConnection(*j);
909  }
910  inc->removeFromConnections(this);
911  }
912 }
913 
914 
915 void
916 NBEdge::removeFromConnections(NBEdge* toEdge, int fromLane, int toLane, bool tryLater) {
917  // remove from "myConnections"
918  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
919  Connection& c = *i;
920  if (c.toEdge == toEdge
921  && (fromLane < 0 || c.fromLane == fromLane)
922  && (toLane < 0 || c.toLane == toLane)) {
923  i = myConnections.erase(i);
924  tryLater = false;
925  } else {
926  ++i;
927  }
928  }
929  // check whether it was the turn destination
930  if (myTurnDestination == toEdge && fromLane < 0) {
931  myTurnDestination = 0;
932  }
933  if (myPossibleTurnDestination == toEdge && fromLane < 0) {
935  }
936  if (tryLater) {
937  myConnectionsToDelete.push_back(Connection(fromLane, toEdge, toLane));
938  }
939 }
940 
941 
942 void
943 NBEdge::invalidateConnections(bool reallowSetting) {
944  myTurnDestination = 0;
945  myConnections.clear();
946  if (reallowSetting) {
947  myStep = INIT;
948  } else {
950  }
951 }
952 
953 
954 void
955 NBEdge::replaceInConnections(NBEdge* which, NBEdge* by, unsigned int laneOff) {
956  // replace in "_connectedEdges"
957  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
958  if ((*i).toEdge == which) {
959  (*i).toEdge = by;
960  (*i).toLane += laneOff;
961  }
962  }
963  // check whether it was the turn destination
964  if (myTurnDestination == which) {
965  myTurnDestination = by;
966  }
967 }
968 
969 void
970 NBEdge::replaceInConnections(NBEdge* which, const std::vector<NBEdge::Connection>& origConns) {
971  std::map<int, int> laneMap;
972  int minLane = -1;
973  int maxLane = -1;
974  // get lanes used to approach the edge to remap
975  bool wasConnected = false;
976  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
977  if ((*i).toEdge != which) {
978  continue;
979  }
980  wasConnected = true;
981  if ((*i).fromLane != -1) {
982  int fromLane = (*i).fromLane;
983  laneMap[(*i).toLane] = fromLane;
984  if (minLane == -1 || minLane > fromLane) {
985  minLane = fromLane;
986  }
987  if (maxLane == -1 || maxLane < fromLane) {
988  maxLane = fromLane;
989  }
990  }
991  }
992  if (!wasConnected) {
993  return;
994  }
995  // remove the remapped edge from connections
996  removeFromConnections(which);
997  // add new connections
998  std::vector<NBEdge::Connection> conns = origConns;
999  for (std::vector<NBEdge::Connection>::iterator i = conns.begin(); i != conns.end(); ++i) {
1000  if ((*i).toEdge == which) {
1001  continue;
1002  }
1003  int fromLane = (*i).fromLane;
1004  int toUse = -1;
1005  if (laneMap.find(fromLane) == laneMap.end()) {
1006  if (fromLane >= 0 && fromLane <= minLane) {
1007  toUse = minLane;
1008  }
1009  if (fromLane >= 0 && fromLane >= maxLane) {
1010  toUse = maxLane;
1011  }
1012  } else {
1013  toUse = laneMap[fromLane];
1014  }
1015  if (toUse == -1) {
1016  toUse = 0;
1017  }
1018  setConnection(toUse, (*i).toEdge, (*i).toLane, L2L_COMPUTED, false, (*i).mayDefinitelyPass);
1019  }
1020 }
1021 
1022 
1023 void
1025  myStep = src->myStep;
1027 }
1028 
1029 
1030 bool
1031 NBEdge::canMoveConnection(const Connection& con, unsigned int newFromLane) const {
1032  // only allow using newFromLane if at least 1 vClass is permitted to use
1033  // this connection. If the connection shall be moved to a sidewalk, only create the connection if there is no walking area
1034  const SVCPermissions common = (getPermissions(newFromLane) & con.toEdge->getPermissions(con.toLane));
1035  return (common > 0 && common != SVC_PEDESTRIAN);
1036 }
1037 
1038 
1039 void
1040 NBEdge::moveConnectionToLeft(unsigned int lane) {
1041  unsigned int index = 0;
1042  for (unsigned int i = 0; i < myConnections.size(); ++i) {
1043  if (myConnections[i].fromLane == (int)(lane) && canMoveConnection(myConnections[i], lane + 1)) {
1044  index = i;
1045  }
1046  }
1047  std::vector<Connection>::iterator i = myConnections.begin() + index;
1048  Connection c = *i;
1049  myConnections.erase(i);
1050  setConnection(lane + 1, c.toEdge, c.toLane, L2L_VALIDATED, false);
1051 }
1052 
1053 
1054 void
1055 NBEdge::moveConnectionToRight(unsigned int lane) {
1056  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1057  if ((*i).fromLane == (int)lane && canMoveConnection(*i, lane - 1)) {
1058  Connection c = *i;
1059  i = myConnections.erase(i);
1060  setConnection(lane - 1, c.toEdge, c.toLane, L2L_VALIDATED, false);
1061  return;
1062  }
1063  }
1064 }
1065 
1066 
1067 void
1068 NBEdge::buildInnerEdges(const NBNode& n, unsigned int noInternalNoSplits, unsigned int& linkIndex, unsigned int& splitIndex) {
1069  const int numPoints = OptionsCont::getOptions().getInt("junctions.internal-link-detail");
1070  std::string innerID = ":" + n.getID();
1071  NBEdge* toEdge = 0;
1072  unsigned int edgeIndex = linkIndex;
1073  unsigned int internalLaneIndex = 0;
1074  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1075  Connection& con = *i;
1076  con.haveVia = false; // reset first since this may be called multiple times
1077  if (con.toEdge == 0) {
1078  continue;
1079  }
1080  if (con.toEdge != toEdge) {
1081  // skip indices to keep some correspondence between edge ids and link indices:
1082  // internalEdgeIndex + internalLaneIndex = linkIndex
1083  edgeIndex = linkIndex;
1084  toEdge = (*i).toEdge;
1085  internalLaneIndex = 0;
1086  }
1087  PositionVector shape = n.computeInternalLaneShape(this, con, numPoints);
1088  std::vector<unsigned int> foeInternalLinks;
1089 
1090  LinkDirection dir = n.getDirection(this, con.toEdge);
1091  const bool isRightTurn = (dir == LINKDIR_RIGHT || dir == LINKDIR_PARTRIGHT);
1092  const bool isTurn = (isRightTurn || dir == LINKDIR_LEFT || dir == LINKDIR_PARTLEFT);
1093  if (dir != LINKDIR_STRAIGHT && shape.length() < POSITION_EPS) {
1094  WRITE_WARNING("Connection '" + getID() + "_" + toString(con.fromLane) + "->" + con.toEdge->getID() + "_" + toString(con.toLane) + "' is only " + toString(shape.length()) + " short.");
1095  }
1096 
1097  // crossingPosition, list of foe link indices
1098  std::pair<SUMOReal, std::vector<unsigned int> > crossingPositions(-1, std::vector<unsigned int>());
1099  std::set<std::string> tmpFoeIncomingLanes;
1100  switch (dir) {
1101  case LINKDIR_RIGHT:
1102  case LINKDIR_PARTRIGHT:
1103  case LINKDIR_LEFT:
1104  case LINKDIR_PARTLEFT:
1105  case LINKDIR_TURN: {
1106  unsigned int index = 0;
1107  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
1108  for (EdgeVector::const_iterator i2 = incoming.begin(); i2 != incoming.end(); ++i2) {
1109  const std::vector<Connection>& elv = (*i2)->getConnections();
1110  for (std::vector<NBEdge::Connection>::const_iterator k2 = elv.begin(); k2 != elv.end(); k2++) {
1111  if ((*k2).toEdge == 0) {
1112  continue;
1113  }
1114  bool needsCont = n.needsCont(this, *i2, con, *k2);
1115  // compute the crossing point
1116  if (needsCont) {
1117  crossingPositions.second.push_back(index);
1118  const PositionVector otherShape = n.computeInternalLaneShape(*i2, *k2, numPoints);
1119  // vehicles are typically less wide than the lane
1120  // they drive on but but bicycle lanes should be kept clear for their whole width
1121  SUMOReal width2 = (*k2).toEdge->getLaneWidth((*k2).toLane);
1122  if ((*k2).toEdge->getPermissions((*k2).toLane) != SVC_BICYCLE) {
1123  width2 *= 0.5;
1124  }
1125  const SUMOReal minDV = firstIntersection(shape, otherShape, width2);
1126  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1127  assert(minDV >= 0);
1128  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1129  crossingPositions.first = minDV;
1130  }
1131  }
1132  }
1133  const bool rightTurnConflict = NBNode::rightTurnConflict(
1134  this, con.toEdge, con.fromLane, (*i2), (*k2).toEdge, (*k2).fromLane);
1135  // compute foe internal lanes
1136  if (n.foes(this, con.toEdge, *i2, (*k2).toEdge) || rightTurnConflict) {
1137  foeInternalLinks.push_back(index);
1138  }
1139  // compute foe incoming lanes
1140  const bool signalised = hasSignalisedConnectionTo(con.toEdge);
1141  if ((n.forbids(*i2, (*k2).toEdge, this, con.toEdge, signalised) || rightTurnConflict) && (needsCont || dir == LINKDIR_TURN)) {
1142  tmpFoeIncomingLanes.insert((*i2)->getID() + "_" + toString((*k2).fromLane));
1143  }
1144  index++;
1145  }
1146  }
1147  // foe pedestrian crossings
1148  const std::vector<NBNode::Crossing>& crossings = n.getCrossings();
1149  for (std::vector<NBNode::Crossing>::const_iterator it_c = crossings.begin(); it_c != crossings.end(); ++it_c) {
1150  const NBNode::Crossing& crossing = *it_c;
1151  for (EdgeVector::const_iterator it_e = crossing.edges.begin(); it_e != crossing.edges.end(); ++it_e) {
1152  const NBEdge* edge = *it_e;
1153  // compute foe internal lanes
1154  if (this == edge || con.toEdge == edge) {
1155  foeInternalLinks.push_back(index);
1156  if (con.toEdge == edge &&
1157  ((isRightTurn && getJunctionPriority(&n) > 0) || (isTurn && n.isTLControlled()))) {
1158  // build internal junctions (not for left turns at uncontrolled intersections)
1159  PositionVector crossingShape = crossing.shape;
1160  crossingShape.extrapolate(1.0); // sometimes shapes miss each other by a small margin
1161  const SUMOReal minDV = firstIntersection(shape, crossingShape, crossing.width / 2);
1162  if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) {
1163  assert(minDV >= 0);
1164  if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1165  crossingPositions.first = minDV;
1166  }
1167  }
1168  }
1169  }
1170  }
1171  index++;
1172  }
1173 
1174  if (dir == LINKDIR_TURN && crossingPositions.first < 0 && crossingPositions.second.size() != 0 && shape.length() > 2. * POSITION_EPS) {
1175  // let turnarounds wait in the middle if no other crossing point was found and it has a sensible length
1176  // (if endOffset is used, the crossing point is in the middle of the part within the junction shape)
1177  crossingPositions.first = (SUMOReal)(shape.length() + getEndOffset(con.fromLane)) / 2.;
1178  }
1179  }
1180  break;
1181  default:
1182  break;
1183  }
1184  if (con.contPos != UNSPECIFIED_CONTPOS) {
1185  // apply custom internal junction position
1186  if (con.contPos <= 0 || con.contPos >= shape.length()) {
1187  // disable internal junction
1188  crossingPositions.first = -1;
1189  } else {
1190  // set custom position
1191  crossingPositions.first = con.contPos;
1192  }
1193  }
1194 
1195  // @todo compute the maximum speed allowed based on angular velocity
1196  // see !!! for an explanation (with a_lat_mean ~0.3)
1197  /*
1198  SUMOReal vmax = (SUMOReal) 0.3 * (SUMOReal) 9.80778 *
1199  getLaneShape(con.fromLane).back().distanceTo(
1200  con.toEdge->getLaneShape(con.toLane).front())
1201  / (SUMOReal) 2.0 / (SUMOReal) M_PI;
1202  vmax = MIN2(vmax, ((getSpeed() + con.toEdge->getSpeed()) / (SUMOReal) 2.0));
1203  */
1204  SUMOReal vmax = (getSpeed() + con.toEdge->getSpeed()) / (SUMOReal) 2.0;
1205  //
1206  Position end = con.toEdge->getLaneShape(con.toLane).front();
1207  Position beg = getLaneShape(con.fromLane).back();
1208 
1209  assert(shape.size() >= 2);
1210  // get internal splits if any
1211  if (crossingPositions.first >= 0) {
1212  std::pair<PositionVector, PositionVector> split = shape.splitAt(crossingPositions.first);
1213  con.id = innerID + "_" + toString(edgeIndex);
1214  con.shape = split.first;
1215  con.foeIncomingLanes = joinToString(tmpFoeIncomingLanes, " ");
1216  con.foeInternalLinks = foeInternalLinks; // resolve link indices to lane ids later
1217  con.viaID = innerID + "_" + toString(splitIndex + noInternalNoSplits);
1218  ++splitIndex;
1219  con.viaVmax = vmax;
1220  con.viaShape = split.second;
1221  con.haveVia = true;
1222  } else {
1223  con.id = innerID + "_" + toString(edgeIndex);
1224  con.shape = shape;
1225  }
1226  con.vmax = vmax;
1227  con.internalLaneIndex = internalLaneIndex;
1228  ++internalLaneIndex;
1229  ++linkIndex;
1230  }
1231 }
1232 
1233 
1234 SUMOReal
1237  if (v2.length() < POSITION_EPS) {
1238  return intersect;
1239  }
1240  PositionVector v2Right = v2;
1241  v2Right.move2side(width2);
1242 
1243  PositionVector v2Left = v2;
1244  v2Left.move2side(-width2);
1245 
1246  // intersect center line of v1 with left and right border of v2
1247  std::vector<SUMOReal> tmp = v1.intersectsAtLengths2D(v2Right);
1248  if (tmp.size() > 0) {
1249  intersect = MIN2(intersect, tmp[0]);
1250  }
1251  tmp = v1.intersectsAtLengths2D(v2Left);
1252  if (tmp.size() > 0) {
1253  intersect = MIN2(intersect, tmp[0]);
1254  }
1255  return intersect;
1256 }
1257 
1258 
1259 // -----------
1260 int
1261 NBEdge::getJunctionPriority(const NBNode* const node) const {
1262  if (node == myFrom) {
1263  return myFromJunctionPriority;
1264  } else {
1265  return myToJunctionPriority;
1266  }
1267 }
1268 
1269 
1270 void
1271 NBEdge::setJunctionPriority(const NBNode* const node, int prio) {
1272  if (node == myFrom) {
1273  myFromJunctionPriority = prio;
1274  } else {
1275  myToJunctionPriority = prio;
1276  }
1277 }
1278 
1279 
1280 SUMOReal
1281 NBEdge::getAngleAtNode(const NBNode* const atNode) const {
1282  // myStartAngle, myEndAngle are in [0,360] and this returns results in [-180,180]
1283  if (atNode == myFrom) {
1285  } else {
1286  assert(atNode == myTo);
1288  }
1289 }
1290 
1291 
1292 SUMOReal
1293 NBEdge::getAngleAtNodeToCenter(const NBNode* const atNode) const {
1294  if (atNode == myFrom) {
1295  SUMOReal res = myStartAngle - 180;
1296  if (res < 0) {
1297  res += 360;
1298  }
1299  return res;
1300  } else {
1301  assert(atNode == myTo);
1302  return myEndAngle;
1303  }
1304 }
1305 
1306 
1307 void
1308 NBEdge::setTurningDestination(NBEdge* e, bool onlyPossible) {
1309  if (!onlyPossible) {
1310  myTurnDestination = e;
1311  }
1313 }
1314 
1315 
1316 SUMOReal
1317 NBEdge::getLaneSpeed(unsigned int lane) const {
1318  return myLanes[lane].speed;
1319 }
1320 
1321 
1322 void
1324  // vissim needs this
1325  if (myFrom == myTo) {
1326  return;
1327  }
1328  // compute lane offset, first
1329  std::vector<SUMOReal> offsets;
1330  for (unsigned int i = 0; i < myLanes.size(); ++i) {
1331  offsets.push_back(0);
1332  }
1333  SUMOReal offset = 0;
1334  for (int i = (int)myLanes.size() - 2; i >= 0; --i) {
1335  offset += (getLaneWidth(i) + getLaneWidth(i + 1)) / 2. + SUMO_const_laneOffset;
1336  offsets[i] = offset;
1337  }
1339  SUMOReal laneWidth = myLanes.back().width != UNSPECIFIED_WIDTH ? myLanes.back().width : SUMO_const_laneWidth;
1340  offset = (laneWidth + SUMO_const_laneOffset) / 2.; // @todo: why is the lane offset counted in here?
1341  } else {
1342  SUMOReal width = 0;
1343  for (unsigned int i = 0; i < myLanes.size(); ++i) {
1344  width += getLaneWidth(i);
1345  }
1346  width += SUMO_const_laneOffset * SUMOReal(myLanes.size() - 1);
1347  offset = -width / 2. + getLaneWidth((int)myLanes.size() - 1) / 2.;
1348  }
1349  for (unsigned int i = 0; i < myLanes.size(); ++i) {
1350  offsets[i] += offset;
1351  }
1352 
1353  // build the shape of each lane
1354  for (unsigned int i = 0; i < myLanes.size(); ++i) {
1355  try {
1356  myLanes[i].shape = computeLaneShape(i, offsets[i]);
1357  } catch (InvalidArgument& e) {
1358  WRITE_WARNING("In edge '" + getID() + "': lane shape could not be determined (" + e.what() + ").");
1359  myLanes[i].shape = myGeom;
1360  }
1361  }
1362 }
1363 
1364 
1366 NBEdge::computeLaneShape(unsigned int lane, SUMOReal offset) const {
1367  PositionVector shape = myGeom;
1368  try {
1369  shape.move2side(offset);
1370  } catch (InvalidArgument& e) {
1371  WRITE_WARNING("In lane '" + getLaneID(lane) + "': Could not build shape (" + e.what() + ").");
1372  }
1373  return shape;
1374 }
1375 
1376 
1377 void
1379  // taking the angle at the first might be unstable, thus we take the angle
1380  // at a certain distance. (To compare two edges, additional geometry
1381  // segments are considered to resolve ambiguities)
1382  const bool hasFromShape = myFrom->getShape().size() > 0;
1383  const bool hasToShape = myTo->getShape().size() > 0;
1384  Position fromCenter = (hasFromShape ? myFrom->getShape().getCentroid() : myFrom->getPosition());
1385  Position toCenter = (hasToShape ? myTo->getShape().getCentroid() : myTo->getPosition());
1386  PositionVector shape = ((hasFromShape || hasToShape) && getNumLanes() > 0 ?
1388  myLanes[getNumLanes() - 1].shape
1389  : myLanes[getNumLanes() / 2].shape)
1390  : myGeom);
1391 
1392  // if the junction shape is suspicious we cannot trust the angle to the centroid
1393  if ((hasFromShape && (myFrom->getShape().distance(shape[0]) > 2 * POSITION_EPS
1394  || myFrom->getShape().around(shape[-1])))
1395  || (hasToShape && (myTo->getShape().distance(shape[-1]) > 2 * POSITION_EPS
1396  || myTo->getShape().around(shape[0])))) {
1397  fromCenter = myFrom->getPosition();
1398  toCenter = myTo->getPosition();
1399  shape = myGeom;
1400  }
1401 
1402  const SUMOReal angleLookahead = MIN2(shape.length2D() / 2, ANGLE_LOOKAHEAD);
1403  const Position referencePosStart = shape.positionAtOffset2D(angleLookahead);
1404  myStartAngle = GeomHelper::legacyDegree(fromCenter.angleTo2D(referencePosStart), true);
1405  const Position referencePosEnd = shape.positionAtOffset2D(shape.length() - angleLookahead);
1406  myEndAngle = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(toCenter), true);
1408 }
1409 
1410 
1411 bool
1413  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1414  if ((*i).permissions != SVCAll) {
1415  return true;
1416  }
1417  }
1418  return false;
1419 }
1420 
1421 
1422 bool
1424  std::vector<Lane>::const_iterator i = myLanes.begin();
1425  SVCPermissions firstLanePermissions = i->permissions;
1426  i++;
1427  for (; i != myLanes.end(); ++i) {
1428  if (i->permissions != firstLanePermissions) {
1429  return true;
1430  }
1431  }
1432  return false;
1433 }
1434 
1435 
1436 bool
1438  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1439  if (i->width != myLanes.begin()->width) {
1440  return true;
1441  }
1442  }
1443  return false;
1444 }
1445 
1446 
1447 bool
1449  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1450  if (i->speed != getSpeed()) {
1451  return true;
1452  }
1453  }
1454  return false;
1455 }
1456 
1457 
1458 bool
1460  for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
1461  if (i->endOffset != myLanes.begin()->endOffset) {
1462  return true;
1463  }
1464  }
1465  return false;
1466 }
1467 
1468 
1469 bool
1472 }
1473 
1474 
1475 
1476 bool
1477 NBEdge::computeEdge2Edges(bool noLeftMovers) {
1478  // return if this relationship has been build in previous steps or
1479  // during the import
1480  if (myStep >= EDGE2EDGES) {
1481  return true;
1482  }
1483  if (myConnections.size() == 0) {
1484  const EdgeVector& o = myTo->getOutgoingEdges();
1485  for (EdgeVector::const_iterator i = o.begin(); i != o.end(); ++i) {
1486  if (noLeftMovers && myTo->isLeftMover(this, *i)) {
1487  continue;
1488  }
1489  myConnections.push_back(Connection(-1, *i, -1));
1490  }
1491  }
1492  myStep = EDGE2EDGES;
1493  return true;
1494 }
1495 
1496 
1497 bool
1499  // return if this relationship has been build in previous steps or
1500  // during the import
1501  if (myStep >= LANES2EDGES) {
1502  return true;
1503  }
1504  assert(myStep == EDGE2EDGES);
1505  // get list of possible outgoing edges sorted by direction clockwise
1506  // the edge in the backward direction (turnaround) is not in the list
1507  const EdgeVector* edges = getConnectedSorted();
1508  if (myConnections.size() != 0 && edges->size() == 0) {
1509  // dead end per definition!?
1510  myConnections.clear();
1511  } else {
1512  // divide the lanes on reachable edges
1513  divideOnEdges(edges);
1514  }
1515  delete edges;
1516  myStep = LANES2EDGES;
1517  return true;
1518 }
1519 
1520 
1521 bool
1523  std::vector<unsigned int> connNumbersPerLane(myLanes.size(), 0);
1524  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1525  if ((*i).toEdge == 0 || (*i).fromLane < 0 || (*i).toLane < 0) {
1526  i = myConnections.erase(i);
1527  } else {
1528  if ((*i).fromLane >= 0) {
1529  ++connNumbersPerLane[(*i).fromLane];
1530  }
1531  ++i;
1532  }
1533  }
1535  // check #1:
1536  // If there is a lane with no connections and any neighbour lane has
1537  // more than one connections, try to move one of them.
1538  // This check is only done for edges which connections were assigned
1539  // using the standard algorithm.
1540  for (unsigned int i = 0; i < myLanes.size(); i++) {
1541  if (connNumbersPerLane[i] == 0 && !isForbidden(getPermissions((int)i))) {
1542  if (i > 0 && connNumbersPerLane[i - 1] > 1) {
1543  moveConnectionToLeft(i - 1);
1544  } else if (i < myLanes.size() - 1 && connNumbersPerLane[i + 1] > 1) {
1545  moveConnectionToRight(i + 1);
1546  }
1547  }
1548  }
1549  // check restrictions
1550  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1551  Connection& c = *i;
1553  if (common == SVC_PEDESTRIAN || getPermissions(c.fromLane) == SVC_PEDESTRIAN) {
1554  // these are computed in NBNode::buildWalkingAreas
1555  i = myConnections.erase(i);
1556  } else if (common == 0) {
1557  // no common permissions.
1558  // try to find a suitable target lane to the right
1559  const int origToLane = c.toLane;
1560  c.toLane = -1; // ignore this connection when calling hasConnectionTo
1561  int toLane = origToLane;
1562  while (toLane > 0
1563  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
1564  && !hasConnectionTo(c.toEdge, toLane)
1565  ) {
1566  toLane--;
1567  }
1568  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
1569  && !hasConnectionTo(c.toEdge, toLane)) {
1570  c.toLane = toLane;
1571  ++i;
1572  } else {
1573  // try to find a suitable target lane to the left
1574  int toLane = origToLane;
1575  while (toLane < (int)c.toEdge->getNumLanes() - 1
1576  && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
1577  && !hasConnectionTo(c.toEdge, toLane)
1578  ) {
1579  toLane++;
1580  }
1581  if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
1582  && !hasConnectionTo(c.toEdge, toLane)) {
1583  c.toLane = toLane;
1584  ++i;
1585  } else {
1586  // no alternative target found
1587  i = myConnections.erase(i);
1588  }
1589  }
1590  } else {
1591  ++i;
1592  }
1593  }
1594  }
1595  // check delayed removals
1596  for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
1597  removeFromConnections(it->toEdge, it->fromLane, it->toLane);
1598  }
1599  return true;
1600 }
1601 
1602 
1603 void
1605  if (outgoing->size() == 0) {
1606  // we have to do this, because the turnaround may have been added before
1607  myConnections.clear();
1608  return;
1609  }
1610  // precompute edge priorities; needed as some kind of assumptions for
1611  // priorities of directions (see preparePriorities)
1612  std::vector<unsigned int>* priorities = prepareEdgePriorities(outgoing);
1613  // compute the indices of lanes that should have connections (excluding
1614  // forbidden lanes and pedestrian lanes that will be connected via walkingAreas)
1615 
1616 
1617  // build connections for miv lanes
1618  std::vector<int> availableLanes;
1619  for (int i = 0; i < (int)myLanes.size(); ++i) {
1620  const SVCPermissions perms = getPermissions(i);
1621  if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) == 0 || isForbidden(perms)) {
1622  continue;
1623  }
1624  availableLanes.push_back(i);
1625  }
1626  if (availableLanes.size() > 0) {
1627  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
1628  }
1629  // build connections for busses (possibly combined with bicycles)
1630  availableLanes.clear();
1631  for (int i = 0; i < (int)myLanes.size(); ++i) {
1632  const SVCPermissions perms = getPermissions(i);
1633  if (perms != SVC_BUS && perms != (SVC_BUS | SVC_BICYCLE)) {
1634  continue;
1635  }
1636  availableLanes.push_back(i);
1637  }
1638  if (availableLanes.size() > 0) {
1639  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
1640  }
1641  // build connections for bicycles (possibly combined with pedestrians)
1642  availableLanes.clear();
1643  for (int i = 0; i < (int)myLanes.size(); ++i) {
1644  const SVCPermissions perms = getPermissions(i);
1645  if (perms != SVC_BICYCLE && perms != (SVC_BICYCLE | SVC_PEDESTRIAN)) {
1646  continue;
1647  }
1648  availableLanes.push_back(i);
1649  }
1650  if (availableLanes.size() > 0) {
1651  divideSelectedLanesOnEdges(outgoing, availableLanes, priorities);
1652  }
1653  // clean up unassigned fromLanes
1654  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1655  if ((*i).fromLane == -1) {
1656  i = myConnections.erase(i);
1657  } else {
1658  ++i;
1659  }
1660  }
1662 
1663  delete priorities;
1664 }
1665 
1666 
1667 void
1668 NBEdge::divideSelectedLanesOnEdges(const EdgeVector* outgoing, const std::vector<int>& availableLanes, const std::vector<unsigned int>* priorities) {
1669  //std::cout << "divideSelectedLanesOnEdges " << getID() << " out=" << toString(*outgoing) << " prios=" << toString(*priorities) << " avail=" << toString(availableLanes) << "\n";
1670  // compute the sum of priorities (needed for normalisation)
1671  unsigned int prioSum = computePrioritySum(*priorities);
1672  // compute the resulting number of lanes that should be used to
1673  // reach the following edge
1674  const int numOutgoing = (int) outgoing->size();
1675  std::vector<SUMOReal> resultingLanes;
1676  resultingLanes.reserve(numOutgoing);
1677  SUMOReal sumResulting = 0.; // the sum of resulting lanes
1678  SUMOReal minResulting = 10000.; // the least number of lanes to reach an edge
1679  for (int i = 0; i < numOutgoing; i++) {
1680  // res will be the number of lanes which are meant to reach the
1681  // current outgoing edge
1682  SUMOReal res =
1683  (SUMOReal)(*priorities)[i] *
1684  (SUMOReal) availableLanes.size() / (SUMOReal) prioSum;
1685  // do not let this number be greater than the number of available lanes
1686  if (res > availableLanes.size()) {
1687  res = (SUMOReal) availableLanes.size();
1688  }
1689  // add it to the list
1690  resultingLanes.push_back(res);
1691  sumResulting += res;
1692  if (minResulting > res && res > 0) {
1693  // prevent minResulting from becoming 0
1694  minResulting = res;
1695  }
1696  }
1697  // compute the number of virtual edges
1698  // a virtual edge is used as a replacement for a real edge from now on
1699  // it shall allow to divide the existing lanes on this structure without
1700  // regarding the structure of outgoing edges
1701  const int numVirtual = (int)(sumResulting / minResulting + 0.5);
1702  // compute the transition from virtual to real edges
1703  EdgeVector transition;
1704  transition.reserve(numOutgoing);
1705  for (int i = 0; i < numOutgoing; i++) {
1706  // tmpNo will be the number of connections from this edge
1707  // to the next edge
1708  assert(i < (int)resultingLanes.size());
1709  const SUMOReal tmpNum = resultingLanes[i] / minResulting;
1710  for (SUMOReal j = 0; j < tmpNum; j++) {
1711  transition.push_back((*outgoing)[i]);
1712  }
1713  }
1714  // assign lanes to edges
1715  // (conversion from virtual to real edges is done)
1716  ToEdgeConnectionsAdder adder(transition);
1717  Bresenham::compute(&adder, static_cast<unsigned int>(availableLanes.size()), numVirtual);
1718  const std::map<NBEdge*, std::vector<unsigned int> >& l2eConns = adder.getBuiltConnections();
1719  for (std::map<NBEdge*, std::vector<unsigned int> >::const_iterator i = l2eConns.begin(); i != l2eConns.end(); ++i) {
1720  NBEdge* target = (*i).first;
1721  const std::vector<unsigned int> lanes = (*i).second;
1722  for (std::vector<unsigned int>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
1723  const int fromIndex = availableLanes[*j];
1724  if ((getPermissions(fromIndex) & target->getPermissions()) == 0) {
1725  // exclude connection if fromLane and toEdge have no common permissions
1726  continue;
1727  }
1728  if ((getPermissions(fromIndex) & target->getPermissions()) == SVC_PEDESTRIAN) {
1729  // exclude connection if the only commonly permitted class are pedestrians
1730  // these connections are later built in NBNode::buildWalkingAreas
1731  continue;
1732  }
1733  // avoid building more connections than the edge has viable lanes (earlier
1734  // ones have precedence). This is necessary when running divideSelectedLanesOnEdges more than once.
1735  // @todo To decide which target lanes are still available we need to do a
1736  // preliminary lane-to-lane assignment in regard to permisions (rather than to ordering)
1737  const int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
1738  int targetLanes = (int)target->getNumLanes();
1739  if (target->getPermissions(0) == SVC_PEDESTRIAN) {
1740  --targetLanes;
1741  }
1742  if (numConsToTarget >= targetLanes) {
1743  // let bicycles move onto the road to allow continuation
1744  // the speed limit is taken from rural roads (which allow cycles)
1745  // (pending implementation of #1859)
1746  if (getPermissions(fromIndex) == SVC_BICYCLE && getSpeed() <= (101 / 3.6)) {
1747  for (unsigned int ii = 0; ii < myLanes.size(); ++ii) {
1748  if (myLanes[ii].permissions != SVC_PEDESTRIAN) {
1749  myLanes[ii].permissions |= SVC_BICYCLE;
1750  }
1751  }
1752  }
1753  continue;
1754  }
1755 
1756  myConnections.push_back(Connection(fromIndex, target, -1));
1757  }
1758  }
1759 }
1760 
1761 
1762 std::vector<unsigned int>*
1764  // copy the priorities first
1765  std::vector<unsigned int>* priorities = new std::vector<unsigned int>();
1766  if (outgoing->size() == 0) {
1767  return priorities;
1768  }
1769  priorities->reserve(outgoing->size());
1770  EdgeVector::const_iterator i;
1771  for (i = outgoing->begin(); i != outgoing->end(); i++) {
1772  int prio = (*i)->getJunctionPriority(myTo);
1773  assert((prio + 1) * 2 > 0);
1774  prio = (prio + 1) * 2;
1775  priorities->push_back(prio);
1776  }
1777  // when the right turning direction has not a higher priority, divide
1778  // the importance by 2 due to the possibility to leave the junction
1779  // faster from this lane
1780  MainDirections mainDirections(*outgoing, this, myTo);
1781  EdgeVector tmp(*outgoing);
1782  sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(this));
1783  i = find(outgoing->begin(), outgoing->end(), *(tmp.begin()));
1784  unsigned int dist = (unsigned int) distance(outgoing->begin(), i);
1785  if (dist != 0 && !mainDirections.includes(MainDirections::DIR_RIGHTMOST)) {
1786  assert(priorities->size() > 0);
1787  (*priorities)[0] /= 2;
1788  }
1789  // HEURISTIC:
1790  // when no higher priority exists, let the forward direction be
1791  // the main direction
1792  if (mainDirections.empty()) {
1793  assert(dist < priorities->size());
1794  (*priorities)[dist] *= 2;
1795  }
1796  if (mainDirections.includes(MainDirections::DIR_FORWARD)) {
1797  if (myLanes.size() > 2) {
1798  (*priorities)[dist] *= 2;
1799  } else {
1800  (*priorities)[dist] *= 3;
1801  }
1802  }
1803  // return
1804  return priorities;
1805 }
1806 
1807 
1808 unsigned int
1809 NBEdge::computePrioritySum(const std::vector<unsigned int>& priorities) {
1810  unsigned int sum = 0;
1811  for (std::vector<unsigned int>::const_iterator i = priorities.begin(); i != priorities.end(); i++) {
1812  sum += (int) * i;
1813  }
1814  return sum;
1815 }
1816 
1817 
1818 void
1819 NBEdge::appendTurnaround(bool noTLSControlled) {
1820  // do nothing if no turnaround is known
1821  if (myTurnDestination == 0) {
1822  return;
1823  }
1824  // do nothing if the destination node is controlled by a tls and no turnarounds
1825  // shall be appended for such junctions
1826  if (noTLSControlled && myTo->isTLControlled()) {
1827  return;
1828  }
1829  setConnection((unsigned int)(myLanes.size() - 1), myTurnDestination, myTurnDestination->getNumLanes() - 1, L2L_VALIDATED);
1830 }
1831 
1832 
1833 bool
1834 NBEdge::isTurningDirectionAt(const NBEdge* const edge) const {
1835  // maybe it was already set as the turning direction
1836  if (edge == myTurnDestination) {
1837  return true;
1838  } else if (myTurnDestination != 0) {
1839  // otherwise - it's not if a turning direction exists
1840  return false;
1841  }
1842  return edge == myPossibleTurnDestination;
1843 }
1844 
1845 
1846 NBNode*
1848  // return the from-node when the position is at the begin of the edge
1849  if (pos < tolerance) {
1850  return myFrom;
1851  }
1852  // return the to-node when the position is at the end of the edge
1853  if (pos > myLength - tolerance) {
1854  return myTo;
1855  }
1856  return 0;
1857 }
1858 
1859 
1860 void
1861 NBEdge::moveOutgoingConnectionsFrom(NBEdge* e, unsigned int laneOff) {
1862  unsigned int lanes = e->getNumLanes();
1863  for (unsigned int i = 0; i < lanes; i++) {
1864  std::vector<NBEdge::Connection> elv = e->getConnectionsFromLane(i);
1865  for (std::vector<NBEdge::Connection>::iterator j = elv.begin(); j != elv.end(); j++) {
1866  NBEdge::Connection el = *j;
1867  assert(el.tlID == "");
1868  bool ok = addLane2LaneConnection(i + laneOff, el.toEdge, el.toLane, L2L_COMPUTED);
1869  assert(ok);
1870  UNUSED_PARAMETER(ok); // only used for assertion
1871  }
1872  }
1873 }
1874 
1875 
1876 bool
1879 }
1880 
1881 
1882 SUMOReal
1885 }
1886 
1887 
1888 bool
1889 NBEdge::mayBeTLSControlled(int fromLane, NBEdge* toEdge, int toLane) const {
1891  tpl.fromLane = fromLane;
1892  tpl.to = toEdge;
1893  tpl.toLane = toLane;
1894  std::vector<TLSDisabledConnection>::const_iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
1895  return i == myTLSDisabledConnections.end();
1896 }
1897 
1898 
1899 bool
1900 NBEdge::setControllingTLInformation(const NBConnection& c, const std::string& tlID) {
1901  const int fromLane = c.getFromLane();
1902  NBEdge* toEdge = c.getTo();
1903  const int toLane = c.getToLane();
1904  const int tlIndex = c.getTLIndex();
1905  // check whether the connection was not set as not to be controled previously
1907  tpl.fromLane = fromLane;
1908  tpl.to = toEdge;
1909  tpl.toLane = toLane;
1910  std::vector<TLSDisabledConnection>::iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
1911  if (i != myTLSDisabledConnections.end()) {
1912  return false;
1913  }
1914 
1915  assert(fromLane < 0 || fromLane < (int) myLanes.size());
1916  // try to use information about the connections if given
1917  if (fromLane >= 0 && toLane >= 0) {
1918  // find the specified connection
1919  std::vector<Connection>::iterator i =
1920  find_if(myConnections.begin(), myConnections.end(), connections_finder(fromLane, toEdge, toLane));
1921  // ok, we have to test this as on the removal of self-loop edges some connections
1922  // will be reassigned
1923  if (i != myConnections.end()) {
1924  // get the connection
1925  Connection& connection = *i;
1926  // set the information about the tl
1927  connection.tlID = tlID;
1928  connection.tlLinkNo = tlIndex;
1929  return true;
1930  }
1931  }
1932  // if the original connection was not found, set the information for all
1933  // connections
1934  unsigned int no = 0;
1935  bool hadError = false;
1936  for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1937  if ((*i).toEdge != toEdge) {
1938  continue;
1939  }
1940  if (fromLane >= 0 && fromLane != (*i).fromLane) {
1941  continue;
1942  }
1943  if (toLane >= 0 && toLane != (*i).toLane) {
1944  continue;
1945  }
1946  if ((*i).tlID == "") {
1947  (*i).tlID = tlID;
1948  (*i).tlLinkNo = tlIndex;
1949  no++;
1950  } else {
1951  if ((*i).tlID != tlID && static_cast<int>((*i).tlLinkNo) == tlIndex) {
1952  WRITE_WARNING("The lane '" + toString<int>((*i).fromLane) + "' on edge '" + getID() + "' already had a traffic light signal.");
1953  hadError = true;
1954  }
1955  }
1956  }
1957  if (hadError && no == 0) {
1958  WRITE_WARNING("Could not set any signal of the tlLogic '" + tlID + "' (unknown group)");
1959  }
1960  return true;
1961 }
1962 
1963 
1964 void
1966  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); it++) {
1967  it->tlID = "";
1968  }
1969 }
1970 
1971 
1972 void
1973 NBEdge::disableConnection4TLS(int fromLane, NBEdge* toEdge, int toLane) {
1975  c.fromLane = fromLane;
1976  c.to = toEdge;
1977  c.toLane = toLane;
1978  myTLSDisabledConnections.push_back(c);
1979 }
1980 
1981 
1984  PositionVector ret;
1985  SUMOReal width;
1986  if (myFrom == (&n)) {
1987  // outgoing
1988  ret = myLanes[0].shape;
1989  width = getLaneWidth(0);
1990  } else {
1991  // incoming
1992  ret = myLanes.back().shape.reverse();
1993  width = getLaneWidth((int)getNumLanes() - 1);
1994  }
1995  ret.move2side(width * 0.5);
1996  return ret;
1997 }
1998 
1999 
2002  PositionVector ret;
2003  SUMOReal width;
2004  if (myFrom == (&n)) {
2005  // outgoing
2006  ret = myLanes.back().shape;
2007  width = getLaneWidth((int)getNumLanes() - 1);
2008  } else {
2009  // incoming
2010  ret = myLanes[0].shape.reverse();
2011  width = getLaneWidth(0);
2012  }
2013  ret.move2side(-width * 0.5);
2014  return ret;
2015 }
2016 
2017 
2018 bool
2019 NBEdge::expandableBy(NBEdge* possContinuation) const {
2020  // ok, the number of lanes must match
2021  if (myLanes.size() != possContinuation->myLanes.size()) {
2022  return false;
2023  }
2024  // the priority, too (?)
2025  if (getPriority() != possContinuation->getPriority()) {
2026  return false;
2027  }
2028  // the speed allowed
2029  if (mySpeed != possContinuation->mySpeed) {
2030  return false;
2031  }
2032  // spreadtype should match or it will look ugly
2033  if (myLaneSpreadFunction != possContinuation->myLaneSpreadFunction) {
2034  return false;
2035  }
2036  // do not create self loops
2037  if (myFrom == possContinuation->myTo) {
2038  return false;
2039  }
2040 
2041  // the vehicle class constraints, too
2049  // also, check whether the connections - if any exit do allow to join
2050  // both edges
2051  // This edge must have a one-to-one connection to the following lanes
2052  switch (myStep) {
2054  break;
2055  case INIT:
2056  break;
2057  case EDGE2EDGES: {
2058  // the following edge must be connected
2059  const EdgeVector& conn = getConnectedEdges();
2060  if (find(conn.begin(), conn.end(), possContinuation)
2061  == conn.end()) {
2062 
2063  return false;
2064  }
2065  }
2066  break;
2067  case LANES2EDGES:
2068  case LANES2LANES_RECHECK:
2069  case LANES2LANES_DONE:
2070  case LANES2LANES_USER: {
2071  // the possible continuation must be connected
2072  if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(possContinuation)) == myConnections.end()) {
2073  return false;
2074  }
2075  // all lanes must go to the possible continuation
2076  std::vector<int> conns = getConnectionLanes(possContinuation);
2077  if (conns.size() != myLanes.size()) {
2078  return false;
2079  }
2080  }
2081  break;
2082  default:
2083  break;
2084  }
2085  return true;
2086 }
2087 
2088 
2089 void
2091  // append geometry
2092  myGeom.append(e->myGeom);
2093  for (unsigned int i = 0; i < myLanes.size(); i++) {
2094  myLanes[i].shape.append(e->myLanes[i].shape);
2095  }
2096  // recompute length
2097  myLength += e->myLength;
2098  // copy the connections and the building step if given
2099  myStep = e->myStep;
2103  // set the node
2104  myTo = e->myTo;
2107  } else {
2108  mySignalOffset += e->getLength();
2109  }
2110  computeAngle(); // myEndAngle may be different now
2111 }
2112 
2113 
2114 bool
2116  for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
2117  if ((*i).toEdge == e && (*i).tlID != "") {
2118  return true;
2119  }
2120  }
2121  return false;
2122 }
2123 
2124 
2125 NBEdge*
2126 NBEdge::getTurnDestination(bool possibleDestination) const {
2127  if (myTurnDestination == 0 && possibleDestination) {
2129  }
2130  return myTurnDestination;
2131 }
2132 
2133 
2134 std::string
2135 NBEdge::getLaneID(unsigned int lane) const {
2136  return myID + "_" + toString(lane);
2137 }
2138 
2139 
2140 std::string
2141 NBEdge::getLaneIDInsecure(unsigned int lane) const {
2142  return myID + "_" + toString(lane);
2143 }
2144 
2145 
2146 bool
2148  std::vector<SUMOReal> distances = myGeom.distances(e->getGeometry());
2149  assert(distances.size() > 0);
2150  return VectorHelper<SUMOReal>::maxValue(distances) < threshold;
2151 }
2152 
2153 
2154 void
2155 NBEdge::addLane(unsigned int index, bool recompute) {
2156  assert(index <= myLanes.size());
2157  myLanes.insert(myLanes.begin() + index, Lane(this, ""));
2158  // copy attributes
2159  if (myLanes.size() > 1) {
2160  int templateIndex = index > 0 ? index - 1 : index + 1;
2161  myLanes[index].speed = myLanes[templateIndex].speed;
2162  myLanes[index].permissions = myLanes[templateIndex].permissions;
2163  myLanes[index].preferred = myLanes[templateIndex].preferred;
2164  myLanes[index].endOffset = myLanes[templateIndex].endOffset;
2165  myLanes[index].width = myLanes[templateIndex].width;
2166  myLanes[index].origID = myLanes[templateIndex].origID;
2167  }
2168  const EdgeVector& incs = myFrom->getIncomingEdges();
2169  if (recompute) {
2171  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
2172  (*i)->invalidateConnections(true);
2173  }
2174  invalidateConnections(true);
2175  }
2176 }
2177 
2178 void
2179 NBEdge::incLaneNo(unsigned int by) {
2180  unsigned int newLaneNo = (unsigned int) myLanes.size() + by;
2181  while (myLanes.size() < newLaneNo) {
2182  // recompute shapes on last addition
2183  const bool recompute = myLanes.size() == newLaneNo - 1;
2184  addLane((unsigned int)myLanes.size(), recompute);
2185  }
2186 }
2187 
2188 
2189 void
2190 NBEdge::deleteLane(unsigned int index, bool recompute) {
2191  assert(index < myLanes.size());
2192  myLanes.erase(myLanes.begin() + index);
2193  const EdgeVector& incs = myFrom->getIncomingEdges();
2194  if (recompute) {
2196  for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
2197  (*i)->invalidateConnections(true);
2198  }
2199  invalidateConnections(true);
2200  }
2201 }
2202 
2203 
2204 void
2205 NBEdge::decLaneNo(unsigned int by) {
2206  unsigned int newLaneNo = (unsigned int) myLanes.size() - by;
2207  assert(newLaneNo > 0);
2208  while (myLanes.size() > newLaneNo) {
2209  // recompute shapes on last removal
2210  const bool recompute = myLanes.size() == newLaneNo + 1;
2211  deleteLane((unsigned int)((int)myLanes.size() - 1), recompute);
2212  }
2213 }
2214 
2215 
2216 void
2218  assert(myTo->getOutgoingEdges().size() == 0);
2220 }
2221 
2222 
2223 void
2225  if (lane < 0) { // all lanes are meant...
2226  for (unsigned int i = 0; i < myLanes.size(); i++) {
2227  allowVehicleClass((int) i, vclass);
2228  }
2229  } else {
2230  assert(lane < (int) myLanes.size());
2231  myLanes[lane].permissions |= vclass;
2232  }
2233 }
2234 
2235 
2236 void
2238  if (lane < 0) { // all lanes are meant...
2239  for (unsigned int i = 0; i < myLanes.size(); i++) {
2240  disallowVehicleClass((int) i, vclass);
2241  }
2242  } else {
2243  assert(lane < (int) myLanes.size());
2244  myLanes[lane].permissions &= ~vclass;
2245  }
2246 }
2247 
2248 
2249 void
2251  if (lane < 0) { // all lanes are meant...
2252  for (unsigned int i = 0; i < myLanes.size(); i++) {
2253  allowVehicleClass((int) i, vclass);
2254  }
2255  } else {
2256  assert(lane < (int) myLanes.size());
2257  myLanes[lane].preferred |= vclass;
2258  }
2259 }
2260 
2261 
2262 void
2263 NBEdge::setLaneWidth(int lane, SUMOReal width) {
2264  if (lane < 0) {
2265  // all lanes are meant...
2266  myLaneWidth = width;
2267  for (unsigned int i = 0; i < myLanes.size(); i++) {
2268  // ... do it for each lane
2269  setLaneWidth((int) i, width);
2270  }
2271  return;
2272  }
2273  assert(lane < (int) myLanes.size());
2274  myLanes[lane].width = width;
2275 }
2276 
2277 
2278 SUMOReal
2279 NBEdge::getLaneWidth(int lane) const {
2280  return myLanes[lane].width != UNSPECIFIED_WIDTH
2281  ? myLanes[lane].width
2283 }
2284 
2285 
2286 SUMOReal
2288  SUMOReal result = 0;
2289  for (unsigned int i = 0; i < myLanes.size(); i++) {
2290  result += getLaneWidth(i);
2291  }
2292  return result;
2293 }
2294 
2295 SUMOReal
2296 NBEdge::getEndOffset(int lane) const {
2297  return myLanes[lane].endOffset != UNSPECIFIED_OFFSET ? myLanes[lane].endOffset : getEndOffset();
2298 }
2299 
2300 
2301 void
2302 NBEdge::setEndOffset(int lane, SUMOReal offset) {
2303  if (lane < 0) {
2304  // all lanes are meant...
2305  myEndOffset = offset;
2306  for (unsigned int i = 0; i < myLanes.size(); i++) {
2307  // ... do it for each lane
2308  setEndOffset((int) i, offset);
2309  }
2310  return;
2311  }
2312  assert(lane < (int) myLanes.size());
2313  myLanes[lane].endOffset = offset;
2314 }
2315 
2316 
2317 void
2318 NBEdge::setSpeed(int lane, SUMOReal speed) {
2319  if (lane < 0) {
2320  // all lanes are meant...
2321  mySpeed = speed;
2322  for (unsigned int i = 0; i < myLanes.size(); i++) {
2323  // ... do it for each lane
2324  setSpeed((int) i, speed);
2325  }
2326  return;
2327  }
2328  assert(lane < (int) myLanes.size());
2329  myLanes[lane].speed = speed;
2330 }
2331 
2332 
2333 void
2334 NBEdge::setPermissions(SVCPermissions permissions, int lane) {
2335  if (lane < 0) {
2336  for (unsigned int i = 0; i < myLanes.size(); i++) {
2337  // ... do it for each lane
2338  setPermissions(permissions, i);
2339  }
2340  } else {
2341  assert(lane < (int) myLanes.size());
2342  myLanes[lane].permissions = permissions;
2343  }
2344 }
2345 
2346 
2347 void
2349  if (lane < 0) {
2350  for (unsigned int i = 0; i < myLanes.size(); i++) {
2351  // ... do it for each lane
2352  setPreferredVehicleClass(permissions, i);
2353  }
2354  } else {
2355  assert(lane < (int) myLanes.size());
2356  myLanes[lane].preferred = permissions;
2357  }
2358 }
2359 
2360 
2362 NBEdge::getPermissions(int lane) const {
2363  if (lane < 0) {
2364  SVCPermissions result = 0;
2365  for (unsigned int i = 0; i < myLanes.size(); i++) {
2366  result |= getPermissions(i);
2367  }
2368  return result;
2369  } else {
2370  assert(lane < (int) myLanes.size());
2371  return myLanes[lane].permissions;
2372  }
2373 }
2374 
2375 
2376 void
2378  myLoadedLength = val;
2379 }
2380 
2381 
2382 void
2384  for (std::vector<Lane>::iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2385  (*i).permissions = SVCAll;
2386  (*i).preferred = 0;
2387  }
2388 }
2389 
2390 
2391 bool
2393  if (c1.fromLane != c2.fromLane) {
2394  return c1.fromLane < c2.fromLane;
2395  }
2396  if (c1.toEdge != c2.toEdge) {
2397  return false; // do not change ordering among toEdges as this is determined by angle in an earlier step
2398  }
2399  return c1.toLane < c2.toLane;
2400 }
2401 
2402 
2403 int
2404 NBEdge::getFirstNonPedestrianLaneIndex(int direction, bool exclusive) const {
2405  assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
2406  const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
2407  const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
2408  for (int i = start; i != end; i += direction) {
2409  // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
2410  // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
2411  if ((exclusive && myLanes[i].permissions != SVC_PEDESTRIAN && myLanes[i].permissions != 0)
2412  || (myLanes[i].permissions == SVCAll || ((myLanes[i].permissions & SVC_PEDESTRIAN) == 0 && myLanes[i].permissions != 0))) {
2413  return i;
2414  }
2415  }
2416  return -1;
2417 }
2418 
2419 
2420 SUMOReal
2422  SUMOReal angle = getAngleAtNode(node) + (getFromNode() == node ? 180.0 : 0.0);
2423  if (angle < 0) {
2424  angle += 360.0;
2425  }
2426  if (angle >= 360) {
2427  angle -= 360.0;
2428  }
2429  if (gDebugFlag1) {
2430  std::cout << getID() << " angle=" << getAngleAtNode(node) << " convAngle=" << angle << "\n";
2431  }
2432  return angle;
2433 }
2434 
2435 
2438  int index = getFirstNonPedestrianLaneIndex(direction);
2439  if (index < 0) {
2440  throw ProcessError("Edge " + getID() + " allows pedestrians on all lanes");
2441  }
2442  return myLanes[index];
2443 }
2444 
2445 
2446 void
2449 }
2450 
2451 
2452 void
2455 }
2456 
2457 
2458 void
2460  if (myLanes[0].permissions == vclass) {
2461  WRITE_WARNING("Edge '" + getID() + "' already has a dedicated lane for " + toString(vclass) + "s. Not adding another one.");
2462  return;
2463  }
2465  myGeom.move2side(width / 2);
2466  }
2467  // disallow pedestrians on all lanes to ensure that sidewalks are used and
2468  // crossings can be guessed
2469  disallowVehicleClass(-1, vclass);
2470  // add new lane
2471  myLanes.insert(myLanes.begin(), Lane(this, myLanes[0].origID));
2472  myLanes[0].permissions = vclass;
2473  myLanes[0].width = width;
2474  // shift outgoing connections to the left
2475  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
2476  Connection& c = *it;
2477  if (c.fromLane >= 0) {
2478  c.fromLane += 1;
2479  }
2480  }
2481  // shift incoming connections to the left
2482  const EdgeVector& incoming = myFrom->getIncomingEdges();
2483  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
2484  (*it)->shiftToLanesToEdge(this, 1);
2485  }
2487  myTo->shiftTLConnectionLaneIndex(this, 1);
2489 }
2490 
2491 
2492 void
2493 NBEdge::shiftToLanesToEdge(NBEdge* to, unsigned int laneOff) {
2495  for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
2496  if ((*it).toEdge == to && (*it).toLane >= 0) {
2497  (*it).toLane += laneOff;
2498  }
2499  }
2500 }
2501 
2502 
2503 void
2506  const int i = (node == myTo ? -1 : 0);
2507  const int i2 = (node == myTo ? 0 : -1);
2508  const SUMOReal dist = myGeom[i].distanceTo2D(node->getPosition());
2509  const SUMOReal neededOffset = (getTotalWidth() + getNumLanes() * SUMO_const_laneOffset) / 2;
2510  const SUMOReal dist2 = MIN2(myGeom.distance(other->getGeometry()[i2]),
2511  other->getGeometry().distance(myGeom[i]));
2512  const SUMOReal neededOffset2 = neededOffset + (other->getTotalWidth() + other->getNumLanes() * SUMO_const_laneOffset) / 2;
2513  if (dist < neededOffset && dist2 < neededOffset2) {
2514  PositionVector tmp = myGeom;
2515  // @note this doesn't work well for vissim networks
2516  //tmp.move2side(MIN2(neededOffset - dist, neededOffset2 - dist2));
2517  tmp.move2side(neededOffset - dist);
2518  myGeom[i] = tmp[i];
2519  }
2520  }
2521 }
2522 
2523 /****************************************************************************/
NBEdge::Lane getFirstNonPedestrianLane(int direction) const
Definition: NBEdge.cpp:2437
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:102
std::string id
Definition: NBEdge.h:181
void invalidateConnections(bool reallowSetting=false)
Definition: NBEdge.cpp:943
The link is a partial left direction.
const PositionVector & getLaneShape(unsigned int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:532
std::vector< Lane > myLanes
Lane information.
Definition: NBEdge.h:1315
bool includes(Direction d) const
Definition: NBEdge.cpp:165
PositionVector cutAtIntersection(const PositionVector &old) const
cut shape at the intersection shapes
Definition: NBEdge.cpp:441
bool hasConnectionTo(NBEdge *destEdge, unsigned int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:806
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges.
Definition: NBNode.h:240
const std::string & getTypeID() const
Definition: NBEdge.h:905
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:1900
void divideOnEdges(const EdgeVector *outgoing)
Definition: NBEdge.cpp:1604
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:148
int toLane
The lane the connections yields in.
Definition: NBEdge.h:166
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:201
SUMOReal width
This lane&#39;s width.
Definition: NBNode.h:143
SUMOReal myTotalAngle
Definition: NBEdge.h:1272
SUMOReal distance(const Position &p, bool perpendicular=false) const
std::string foeIncomingLanes
Definition: NBEdge.h:191
const SUMOReal SUMO_const_laneWidth
Definition: StdDefs.h:49
is a pedestrian
int getTLIndex() const
Definition: NBConnection.h:101
SUMOReal myEndOffset
This edges&#39;s offset to the intersection begin (will be applied to all lanes)
Definition: NBEdge.h:1307
std::vector< TLSDisabledConnection > myTLSDisabledConnections
Definition: NBEdge.h:1332
~NBEdge()
Destructor.
Definition: NBEdge.cpp:378
static const SUMOReal UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
Definition: NBEdge.h:212
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition: NBEdge.h:1304
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
SUMOReal viaVmax
Definition: NBEdge.h:187
void sortOutgoingConnectionsByAngle()
sorts the outgoing connections by their angle relative to their junction
Definition: NBEdge.cpp:888
std::string viaID
Definition: NBEdge.h:186
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:164
bool hasDefaultGeometry() const
Returns whether the geometry consists only of the node positions.
Definition: NBEdge.cpp:414
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset)
patches loaded signal plans by modifying lane indices
Definition: NBNode.cpp:373
void mirrorX()
mirror coordinates along the x-axis
Definition: NBEdge.cpp:393
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
NBNode * myTo
Definition: NBEdge.h:1264
The relationships between edges are computed/loaded.
Definition: NBEdge.h:94
bool empty() const
Definition: NBEdge.cpp:159
void appendTurnaround(bool noTLSControlled)
Add a connection to the previously computed turnaround, if wished.
Definition: NBEdge.cpp:1819
#define M_PI
Definition: angles.h:37
bool hasLaneSpecificEndOffset() const
whether lanes differ in offset
Definition: NBEdge.cpp:1459
void setLaneWidth(int lane, SUMOReal width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:2263
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:304
void setSpeed(int lane, SUMOReal speed)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.cpp:2318
Some static methods for string processing.
Definition: StringUtils.h:45
void moveOutgoingConnectionsFrom(NBEdge *e, unsigned int laneOff)
Definition: NBEdge.cpp:1861
const SUMOReal SUMO_const_laneWidthAndOffset
Definition: StdDefs.h:53
void addSidewalk(SUMOReal width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:2447
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1173
vehicle is a bicycle
void addIncomingEdge(NBEdge *edge)
adds an incoming edge
Definition: NBNode.cpp:424
int SVCPermissions
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:314
void clearControllingTLInformation()
clears tlID for all connections
Definition: NBEdge.cpp:1965
Lane2LaneInfoType
Modes of setting connections between lanes.
Definition: NBEdge.h:109
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
Definition: NBEdge.cpp:1889
bool hasDefaultGeometryEndpoints() const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:420
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
void incLaneNo(unsigned int by)
Definition: NBEdge.cpp:2179
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:2001
bool intersects(const Position &p1, const Position &p2) const
bool addLane2LaneConnection(unsigned int fromLane, NBEdge *dest, unsigned int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, SUMOReal contPos=UNSPECIFIED_CONTPOS)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:675
const std::vector< Crossing > & getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.h:640
bool addLane2LaneConnections(unsigned int fromLane, NBEdge *dest, unsigned int toLane, unsigned int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp:699
static const SUMOReal UNSPECIFIED_SPEED
unspecified lane speed
Definition: NBEdge.h:205
void buildInnerEdges(const NBNode &n, unsigned int noInternalNoSplits, unsigned int &linkIndex, unsigned int &splitIndex)
Definition: NBEdge.cpp:1068
void markAsInLane2LaneState()
Definition: NBEdge.cpp:2217
SUMOReal getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:2287
Lanes to lanes - relationships are computed; should be recheked.
Definition: NBEdge.h:98
SUMOReal getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:447
std::string getLaneIDInsecure(unsigned int lane) const
Definition: NBEdge.cpp:2141
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:2334
PositionVector shape
The lane&#39;s shape.
Definition: NBNode.h:141
int myFromJunctionPriority
The priority normalised for the node the edge is outgoing of.
Definition: NBEdge.h:1295
void computeLaneShapes()
Definition: NBEdge.cpp:1323
PositionVector getSubpartByIndex(int beginIndex, int count) const
PositionVector myGeom
The geometry for the edge.
Definition: NBEdge.h:1301
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:900
#define RAD2DEG(x)
Definition: GeomHelper.h:46
SUMOReal distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:221
static const SUMOReal UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition: NBEdge.h:207
const SUMOReal SUMO_const_laneOffset
Definition: StdDefs.h:52
bool around(const Position &p, SUMOReal offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point ...
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVCAll
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:203
SUMOReal beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position ...
static SUMOReal angleDiff(const SUMOReal angle1, const SUMOReal angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:178
std::vector< Connection > getConnectionsFromLane(unsigned int lane) const
Returns connections from a given lane.
Definition: NBEdge.cpp:779
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:434
Position positionAtOffset2D(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge&#39;s geometry
Definition: NBEdge.cpp:427
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:39
static SUMOReal firstIntersection(const PositionVector &v1, const PositionVector &v2, SUMOReal width2)
Definition: NBEdge.cpp:1235
The link is a (hard) left direction.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
The connection was computed and validated.
Definition: NBEdge.h:115
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:69
PositionVector startShapeAt(const PositionVector &laneShape, const NBNode *startNode) const
Definition: NBEdge.cpp:487
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:1263
SUMOReal vmax
Definition: NBEdge.h:183
PositionVector reverse() const
The edge has been loaded, nothing is computed yet.
Definition: NBEdge.h:92
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:1298
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:862
The link is a straight direction.
PositionVector shape
Definition: NBEdge.h:182
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges.
Definition: NBNode.h:248
void moveConnectionToRight(unsigned int lane)
Definition: NBEdge.cpp:1055
bool hasPermissions() const
whether at least one lane has restrictions
Definition: NBEdge.cpp:1412
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:122
const std::string & getID() const
Returns the id.
Definition: Named.h:65
SUMOReal length2D() const
Returns the length.
SUMOReal mySpeed
The maximal speed.
Definition: NBEdge.h:1278
std::vector< SUMOReal > distances(const PositionVector &s, bool perpendicular=false) const
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:600
bool addEdge2EdgeConnection(NBEdge *dest)
Adds a connection to another edge.
Definition: NBEdge.cpp:651
bool myAmMacroscopicConnector
Information whether this edge is a (macroscopic) connector.
Definition: NBEdge.h:1324
bool isConnectedTo(NBEdge *e)
Returns the information whethe a connection to the given edge has been added (or computed) ...
Definition: NBEdge.cpp:812
const PositionVector getInnerGeometry() const
Returns the geometry of the edge without the endpoints.
Definition: NBEdge.cpp:408
void push_front_noDoublePos(const Position &p)
void reshiftPosition(SUMOReal xoff, SUMOReal yoff)
Applies an offset to the edge.
Definition: NBEdge.cpp:383
const Position & getPosition() const
Returns the position of this node.
Definition: NBNode.h:228
void divideSelectedLanesOnEdges(const EdgeVector *outgoing, const std::vector< int > &availableLanes, const std::vector< unsigned int > *priorities)
Definition: NBEdge.cpp:1668
static unsigned int computePrioritySum(const std::vector< unsigned int > &priorities)
Definition: NBEdge.cpp:1809
bool computeLanes2Edges()
computes the edge, step2: computation of which lanes approach the edges)
Definition: NBEdge.cpp:1498
#define max(a, b)
Definition: polyfonts.c:65
NBEdge * myTurnDestination
The turn destination edge (if a connection exists)
Definition: NBEdge.h:1290
const std::map< NBEdge *, std::vector< unsigned int > > & getBuiltConnections() const
Definition: NBEdge.h:1124
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
Definition: NBEdge.h:102
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:791
int operator()(const Connection &c1, const Connection &c2) const
comparing operation
Definition: NBEdge.cpp:174
bool hasLaneSpecificSpeed() const
whether lanes differ in speed
Definition: NBEdge.cpp:1448
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:353
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:161
void checkGeometry(const SUMOReal maxAngle, const SUMOReal minRadius, bool fix)
Check the angles of successive geometry segments.
Definition: NBEdge.cpp:605
std::string getLaneID(unsigned int lane) const
Definition: NBEdge.cpp:2135
void moveConnectionToLeft(unsigned int lane)
Definition: NBEdge.cpp:1040
static SUMOReal legacyDegree(const SUMOReal angle, const bool positive=false)
Definition: GeomHelper.cpp:204
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:183
void mirrorX()
mirror coordinates along the x-axis
std::string tlID
The id of the traffic light that controls this connection.
Definition: NBEdge.h:168
std::string getInternalLaneID() const
Definition: NBEdge.cpp:79
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:162
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
A list of positions.
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
SUMOReal myEndAngle
Definition: NBEdge.h:1271
bool hasLaneSpecificPermissions() const
whether lanes differ in allowed vehicle classes
Definition: NBEdge.cpp:1423
bool lanesWereAssigned() const
Definition: NBEdge.cpp:1877
static bool connections_sorter(const Connection &c1, const Connection &c2)
Definition: NBEdge.cpp:2392
std::vector< unsigned int > foeInternalLinks
Definition: NBEdge.h:190
unsigned int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:345
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
NBEdge * myPossibleTurnDestination
The edge that would be the turn destination if there was one.
Definition: NBEdge.h:1292
PositionVector getCWBoundaryLine(const NBNode &n) const
get the outer boundary of this edge when going clock-wise around the given node
Definition: NBEdge.cpp:1983
bool canMoveConnection(const Connection &con, unsigned int newFromLane) const
whether the connection can originate on newFromLane
Definition: NBEdge.cpp:1031
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:1834
SUMOReal contPos
custom position for internal junction on this connection
Definition: NBEdge.h:176
SUMOReal myLaneWidth
This width of this edge&#39;s lanes.
Definition: NBEdge.h:1310
int myPriority
The priority of the edge.
Definition: NBEdge.h:1275
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:2404
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:73
bool needsLaneSpecificOutput() const
whether at least one lane has values differing from the edges values
Definition: NBEdge.cpp:1470
The link is a (hard) right direction.
EdgeBuildingStep myStep
The building step.
Definition: NBEdge.h:1258
#define POSITION_EPS
Definition: config.h:188
#define DEG2RAD(x)
Definition: GeomHelper.h:45
SUMOReal 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:1293
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:1427
std::vector< Connection > myConnections
List of connections to following edges.
Definition: NBEdge.h:1283
void setLoadedLength(SUMOReal val)
Definition: NBEdge.cpp:2377
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:53
The connection was given by the user.
Definition: NBEdge.h:113
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1591
SUMOReal getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
Definition: NBEdge.h:487
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:916
The link is a partial right direction.
static void compute(BresenhamCallBack *callBack, const unsigned int val1, const unsigned int val2)
Definition: Bresenham.cpp:45
SUMOReal getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:476
bool myAmInnerEdge
Information whether this is a junction-inner edge.
Definition: NBEdge.h:1321
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:1310
Base class for objects which have an id.
Definition: Named.h:45
bool recheckLanes()
Definition: NBEdge.cpp:1522
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1261
SUMOReal myLoadedLength
An optional length to use (-1 if not valid)
Definition: NBEdge.h:1318
std::pair< PositionVector, PositionVector > splitAt(SUMOReal where) const
Returns the two lists made when this list vector is splitted at the given point.
static std::string convertUmlaute(std::string str)
Converts german "Umlaute" to their latin-version.
Definition: StringUtils.cpp:95
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2362
SUMOReal getCrossingAngle(NBNode *node)
return the angle for computing pedestrian crossings at the given node
Definition: NBEdge.cpp:2421
SUMOReal length() const
Returns the length.
vehicle is a bus
void addRestrictedLane(SUMOReal width, SUMOVehicleClass vclass)
add a lane of the given width, restricted to the given class and shift existing connctions ...
Definition: NBEdge.cpp:2459
void setTurningDestination(NBEdge *e, bool onlyPossible=false)
Sets the turing destination at the given edge.
Definition: NBEdge.cpp:1308
static const int BACKWARD
Definition: NBNode.h:184
void addBikeLane(SUMOReal width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:2453
void decLaneNo(unsigned int by)
Definition: NBEdge.cpp:2205
std::string myID
The name of the object.
Definition: Named.h:133
PositionVector computeInternalLaneShape(NBEdge *fromE, const NBEdge::Connection &con, int numPoints) const
Compute the shape for an internal lane.
Definition: NBNode.cpp:559
std::vector< int > getConnectionLanes(NBEdge *currentOutgoing) const
Returns the list of lanes that may be used to reach the given edge.
Definition: NBEdge.cpp:874
void removeDoublePoints(SUMOReal minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
void execute(const unsigned int lane, const unsigned int virtEdge)
executes a bresenham - step
Definition: NBEdge.cpp:87
void computeEdgeShape()
Recomputeds the lane shapes to terminate at the node shape For every lane the intersection with the f...
Definition: NBEdge.cpp:471
void disableConnection4TLS(int fromLane, NBEdge *toEdge, int toLane)
Definition: NBEdge.cpp:1973
PositionVector viaShape
Definition: NBEdge.h:188
SUMOReal angleAt2D(int pos) const
SUMOReal getMaxLaneOffset()
Definition: NBEdge.cpp:1883
static const SUMOReal UNSPECIFIED_LOADED_LENGTH
no length override given
Definition: NBEdge.h:210
void deleteLane(unsigned int index, bool recompute=true)
Definition: NBEdge.cpp:2190
std::vector< NBEdge * > EdgeVector
Definition: NBCont.h:41
std::vector< unsigned int > * prepareEdgePriorities(const EdgeVector *outgoing)
Definition: NBEdge.cpp:1763
SUMOReal myLength
The length of the edge.
Definition: NBEdge.h:1267
void setPreferredVehicleClass(SVCPermissions permissions, int lane=-1)
Definition: NBEdge.cpp:2348
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:521
The edge has been loaded and connections shall not be added.
Definition: NBEdge.h:90
int getToLane() const
returns the to-lane
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
std::vector< Connection > myConnectionsToDelete
List of connections marked for delayed removal.
Definition: NBEdge.h:1287
PositionVector computeLaneShape(unsigned int lane, SUMOReal offset) const
Computes the shape for the given lane.
Definition: NBEdge.cpp:1366
void reduceGeometry(const SUMOReal minDist)
Removes points with a distance lesser than the given.
Definition: NBEdge.cpp:599
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:1271
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:80
void replaceInConnections(NBEdge *which, NBEdge *by, unsigned int laneOff)
Definition: NBEdge.cpp:955
const EdgeVector * getConnectedSorted()
Returns the list of outgoing edges without the turnaround sorted in clockwise direction.
Definition: NBEdge.cpp:825
void sortOutgoingConnectionsByIndex()
sorts the outgoing connections by their from-lane-index and their to-lane-index
Definition: NBEdge.cpp:894
SUMOReal mySignalOffset
the offset of a traffic light signal from the end of this edge (-1 for None)
Definition: NBEdge.h:1343
std::string myType
The type of the edge.
Definition: NBEdge.h:1261
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge&#39;s lateral offset shal...
void append(NBEdge *continuation)
Definition: NBEdge.cpp:2090
unsigned int tlLinkNo
The index of this connection within the controlling traffic light.
Definition: NBEdge.h:170
NBEdge * getTo() const
returns the to-edge (end of the connection)
SUMOReal getLaneSpeed(unsigned int lane) const
Definition: NBEdge.cpp:1317
void shiftToLanesToEdge(NBEdge *to, unsigned int laneOff)
modifify the toLane for all connections to the given edge
Definition: NBEdge.cpp:2493
NBNode * tryGetNodeAtPosition(SUMOReal pos, SUMOReal tolerance=5.0) const
Returns the node at the given edges length (using an epsilon) When no node is existing at the given p...
Definition: NBEdge.cpp:1847
The connection was computed.
Definition: NBEdge.h:111
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge&#39;s lanes&#39; lateral offset is computed.
Definition: NBEdge.h:601
SUMOReal myStartAngle
The angles of the edge.
Definition: NBEdge.h:1270
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:139
Represents a single node (junction) during network building.
Definition: NBNode.h:74
void dismissVehicleClassInformation()
Definition: NBEdge.cpp:2383
bool hasSignalisedConnectionTo(const NBEdge *const e) const
Definition: NBEdge.cpp:2115
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
Definition: NBEdge.h:100
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:159
A definition of a pedestrian crossing.
Definition: NBNode.h:132
void move2side(SUMOReal amount)
bool hasLaneSpecificWidth() const
whether lanes differ in width
Definition: NBEdge.cpp:1437
void setEndOffset(int lane, SUMOReal offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition: NBEdge.cpp:2302
Direction
enum of possible directions
Definition: NBEdge.h:1148
#define SUMOReal
Definition: config.h:214
bool isNearEnough2BeJoined2(NBEdge *e, SUMOReal threshold) const
Definition: NBEdge.cpp:2147
void preferVehicleClass(int lane, SUMOVehicleClass vclass)
Definition: NBEdge.cpp:2250
#define NUMERICAL_EPS
Definition: config.h:161
void push_back_noDoublePos(const Position &p)
void allowVehicleClass(int lane, SUMOVehicleClass vclass)
set allowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:2224
void addGeometryPoint(int index, const Position &p)
Adds a further geometry point.
Definition: NBEdge.cpp:544
void computeAngle()
computes the angle of this edge and stores it in myAngle
Definition: NBEdge.cpp:1378
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:109
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:429
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:64
bool computeEdge2Edges(bool noLeftMovers)
computes the edge (step1: computation of approached edges)
Definition: NBEdge.cpp:1477
static T maxValue(const std::vector< T > &v)
Definition: VectorHelper.h:98
unsigned int internalLaneIndex
The lane index of this internal lane within the internal edge.
Definition: NBEdge.h:194
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
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:1339
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:538
NBEdge(const std::string &id, NBNode *from, NBNode *to, std::string type, SUMOReal speed, unsigned int nolanes, int priority, SUMOReal width, SUMOReal offset, const std::string &streetName="", LaneSpreadFunction spread=LANESPREAD_RIGHT)
Constructor.
Definition: NBEdge.cpp:185
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:201
std::vector< SUMOReal > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
Lanes to edges - relationships are computed/loaded.
Definition: NBEdge.h:96
std::string myStreetName
The street name (or whatever arbitrary string you wish to attach)
Definition: NBEdge.h:1336
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:463
void setConnection(unsigned int lane, NBEdge *destEdge, unsigned int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, SUMOReal contPos=UNSPECIFIED_CONTPOS)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:716
void addLane(unsigned int index, bool recompute=true)
Definition: NBEdge.cpp:2155
NBNode * myFrom
The source and the destination node.
Definition: NBEdge.h:1264
bool expandableBy(NBEdge *possContinuation) const
Definition: NBEdge.cpp:2019
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:2126
void init(unsigned int noLanes, bool tryIgnoreNodePositions, const std::string &origID)
Initialization routines common to all constructors.
Definition: NBEdge.cpp:334
PositionVector getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const
~MainDirections()
destructor
Definition: NBEdge.cpp:155
void shiftPositionAtNode(NBNode *node, NBEdge *opposite)
shift geometry at the given node to avoid overlap
Definition: NBEdge.cpp:2504
void disallowVehicleClass(int lane, SUMOVehicleClass vclass)
set disallowed class for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:2237
SUMOReal angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:243
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
MainDirections(const EdgeVector &outgoing, NBEdge *parent, NBNode *to)
constructor
Definition: NBEdge.cpp:118
void extrapolate(const SUMOReal val, const bool onlyFirst=false)
void copyConnectionsFrom(NBEdge *src)
Definition: NBEdge.cpp:1024
void reinit(NBNode *from, NBNode *to, const std::string &type, SUMOReal speed, unsigned int nolanes, int priority, PositionVector geom, SUMOReal width, SUMOReal offset, const std::string &streetName, LaneSpreadFunction spread=LANESPREAD_RIGHT, bool tryIgnoreNodePositions=false)
Resets initial values.
Definition: NBEdge.cpp:266
static const SUMOReal ANGLE_LOOKAHEAD
the distance at which to take the default angle
Definition: NBEdge.h:214
SUMOReal getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:404
SUMOReal getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1281
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:1329
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:361
bool splitGeometry(NBEdgeCont &ec, NBNodeCont &nc)
Splits this edge at geometry points.
Definition: NBEdge.cpp:554