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