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