Eclipse SUMO - Simulation of Urban MObility
NBNode.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
17 // The representation of a single node
18 /****************************************************************************/
19 
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include <string>
27 #include <map>
28 #include <cassert>
29 #include <algorithm>
30 #include <vector>
31 #include <deque>
32 #include <set>
33 #include <cmath>
34 #include <iterator>
38 #include <utils/geom/GeomHelper.h>
40 #include <utils/common/StdDefs.h>
41 #include <utils/common/ToString.h>
44 #include <iomanip>
45 #include "NBNode.h"
46 #include "NBAlgorithms.h"
47 #include "NBNodeCont.h"
48 #include "NBNodeShapeComputer.h"
49 #include "NBEdgeCont.h"
50 #include "NBTypeCont.h"
51 #include "NBHelpers.h"
52 #include "NBDistrict.h"
53 #include "NBContHelper.h"
54 #include "NBRequest.h"
55 #include "NBOwnTLDef.h"
56 #include "NBLoadedSUMOTLDef.h"
59 
60 // allow to extend a crossing across multiple edges
61 #define EXTEND_CROSSING_ANGLE_THRESHOLD 35.0 // degrees
62 // create intermediate walking areas if either of the following thresholds is exceeded
63 #define SPLIT_CROSSING_WIDTH_THRESHOLD 1.5 // meters
64 #define SPLIT_CROSSING_ANGLE_THRESHOLD 5 // degrees
65 
66 // minimum length for a weaving section at a combined on-off ramp
67 #define MIN_WEAVE_LENGTH 20.0
68 
69 //#define DEBUG_CONNECTION_GUESSING
70 //#define DEBUG_SMOOTH_GEOM
71 //#define DEBUG_PED_STRUCTURES
72 //#define DEBUG_EDGE_SORTING
73 //#define DEBUGCOND true
74 #define DEBUG_NODE_ID "F"
75 #define DEBUGCOND (getID() == DEBUG_NODE_ID)
76 #define DEBUGCOND2(obj) ((obj != 0 && (obj)->getID() == DEBUG_NODE_ID))
77 
78 // ===========================================================================
79 // static members
80 // ===========================================================================
81 const int NBNode::FORWARD(1);
82 const int NBNode::BACKWARD(-1);
83 const double NBNode::UNSPECIFIED_RADIUS = -1;
84 const int NBNode::AVOID_WIDE_LEFT_TURN(1);
86 const int NBNode::FOUR_CONTROL_POINTS(4);
88 const int NBNode::SCURVE_IGNORE(16);
89 
90 // ===========================================================================
91 // method definitions
92 // ===========================================================================
93 /* -------------------------------------------------------------------------
94  * NBNode::ApproachingDivider-methods
95  * ----------------------------------------------------------------------- */
97  const EdgeVector& approaching, NBEdge* currentOutgoing) :
98  myApproaching(approaching),
99  myCurrentOutgoing(currentOutgoing),
100  myIsBikeEdge(currentOutgoing->getPermissions() == SVC_BICYCLE) {
101  // collect lanes which are expliclity targeted
102  std::set<int> approachedLanes;
103  for (const NBEdge* const approachingEdge : myApproaching) {
104  for (const NBEdge::Connection& con : approachingEdge->getConnections()) {
105  if (con.toEdge == myCurrentOutgoing) {
106  approachedLanes.insert(con.toLane);
107  }
108  }
109  }
110  // compute the indices of lanes that should be targeted (excluding pedestrian
111  // lanes that will be connected from walkingAreas and forbidden lanes)
112  // if the lane is targeted by an explicitly set connection we need
113  // to make it available anyway
114  for (int i = 0; i < currentOutgoing->getNumLanes(); ++i) {
115  if ((currentOutgoing->getPermissions(i) == SVC_PEDESTRIAN
116  // don't consider bicycle lanes as targets unless the target
117  // edge is exclusively for bicycles
118  || (currentOutgoing->getPermissions(i) == SVC_BICYCLE && !myIsBikeEdge)
119  || isForbidden(currentOutgoing->getPermissions(i)))
120  && approachedLanes.count(i) == 0) {
121  continue;
122  }
123  myAvailableLanes.push_back(i);
124  }
125 }
126 
127 
129 
130 
131 void
132 NBNode::ApproachingDivider::execute(const int src, const int dest) {
133  assert((int)myApproaching.size() > src);
134  // get the origin edge
135  NBEdge* incomingEdge = myApproaching[src];
136  if (incomingEdge->getStep() == NBEdge::EdgeBuildingStep::LANES2LANES_DONE || incomingEdge->getStep() == NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
137  return;
138  }
139  if (myAvailableLanes.size() == 0) {
140  return;
141  }
142  std::vector<int> approachingLanes = incomingEdge->getConnectionLanes(myCurrentOutgoing, myIsBikeEdge || incomingEdge->getPermissions() == SVC_BICYCLE);
143  if (approachingLanes.size() == 0) {
144  return;
145  }
146 #ifdef DEBUG_CONNECTION_GUESSING
147  if (DEBUGCOND2(incomingEdge->getToNode())) {
148  std::cout << "Bre:ex src=" << src << " dest=" << dest << " in=" << incomingEdge->getID() << " apLanes=" << toString(approachingLanes) << "\n";
149  }
150 
151 #endif
152  std::deque<int>* approachedLanes = spread(approachingLanes, dest);
153  assert(approachedLanes->size() <= myAvailableLanes.size());
154  // set lanes
155  for (int i = 0; i < (int)approachedLanes->size(); i++) {
156  assert((int)approachingLanes.size() > i);
157  int approached = myAvailableLanes[(*approachedLanes)[i]];
158  incomingEdge->setConnection(approachingLanes[i], myCurrentOutgoing, approached, NBEdge::L2L_COMPUTED);
159  }
160  delete approachedLanes;
161 }
162 
163 
164 std::deque<int>*
165 NBNode::ApproachingDivider::spread(const std::vector<int>& approachingLanes, int dest) const {
166  std::deque<int>* ret = new std::deque<int>();
167  const int numLanes = (int)approachingLanes.size();
168  // when only one lane is approached, we check, whether the double-value
169  // is assigned more to the left or right lane
170  if (numLanes == 1) {
171  ret->push_back(dest);
172  return ret;
173  }
174 
175  const int numOutgoingLanes = (int)myAvailableLanes.size();
176  //
177  ret->push_back(dest);
178  int noSet = 1;
179  int roffset = 1;
180  int loffset = 1;
181  while (noSet < numLanes) {
182  // It may be possible, that there are not enough lanes the source
183  // lanes may be divided on
184  // In this case, they remain unset
185  // !!! this is only a hack. It is possible, that this yields in
186  // uncommon divisions
187  if (numOutgoingLanes == noSet) {
188  return ret;
189  }
190 
191  // as due to the conversion of double->uint the numbers will be lower
192  // than they should be, we try to append to the left side first
193  //
194  // check whether the left boundary of the approached street has
195  // been overridden; if so, move all lanes to the right
196  if (dest + loffset >= numOutgoingLanes) {
197  loffset -= 1;
198  roffset += 1;
199  for (int i = 0; i < (int)ret->size(); i++) {
200  (*ret)[i] = (*ret)[i] - 1;
201  }
202  }
203  // append the next lane to the left of all edges
204  // increase the position (destination edge)
205  ret->push_back(dest + loffset);
206  noSet++;
207  loffset += 1;
208 
209  // as above
210  if (numOutgoingLanes == noSet) {
211  return ret;
212  }
213 
214  // now we try to append the next lane to the right side, when needed
215  if (noSet < numLanes) {
216  // check whether the right boundary of the approached street has
217  // been overridden; if so, move all lanes to the right
218  if (dest < roffset) {
219  loffset += 1;
220  roffset -= 1;
221  for (int i = 0; i < (int)ret->size(); i++) {
222  (*ret)[i] = (*ret)[i] + 1;
223  }
224  }
225  ret->push_front(dest - roffset);
226  noSet++;
227  roffset += 1;
228  }
229  }
230  return ret;
231 }
232 
233 
234 NBNode::Crossing::Crossing(const NBNode* _node, const EdgeVector& _edges, double _width, bool _priority, int _customTLIndex, int _customTLIndex2, const PositionVector& _customShape) :
235  Parameterised(),
236  node(_node),
237  edges(_edges),
238  customWidth(_width),
239  width(_width),
240  priority(_priority),
241  customShape(_customShape),
242  tlLinkIndex(_customTLIndex),
243  tlLinkIndex2(_customTLIndex2),
244  customTLIndex(_customTLIndex),
245  customTLIndex2(_customTLIndex2),
246  valid(true) {
247 }
248 
249 /* -------------------------------------------------------------------------
250  * NBNode-methods
251  * ----------------------------------------------------------------------- */
252 NBNode::NBNode(const std::string& id, const Position& position,
253  SumoXMLNodeType type) :
254  Named(StringUtils::convertUmlaute(id)),
255  myPosition(position),
256  myType(type),
257  myDistrict(nullptr),
258  myHaveCustomPoly(false),
259  myRequest(nullptr),
261  myKeepClear(OptionsCont::getOptions().getBool("default.junctions.keep-clear")),
262  myRightOfWay(SUMOXMLDefinitions::RightOfWayValues.get(OptionsCont::getOptions().getString("default.right-of-way"))),
264  myDiscardAllCrossings(false),
267  myIsBentPriority(false),
268  myTypeWasGuessed(false) {
270  throw ProcessError("Invalid node id '" + myID + "'.");
271  }
272 }
273 
274 
275 NBNode::NBNode(const std::string& id, const Position& position, NBDistrict* district) :
276  Named(StringUtils::convertUmlaute(id)),
277  myPosition(position),
278  myType(district == nullptr ? NODETYPE_UNKNOWN : NODETYPE_DISTRICT),
279  myDistrict(district),
280  myHaveCustomPoly(false),
281  myRequest(nullptr),
282  myRadius(UNSPECIFIED_RADIUS),
283  myKeepClear(OptionsCont::getOptions().getBool("default.junctions.keep-clear")),
284  myRightOfWay(SUMOXMLDefinitions::RightOfWayValues.get(OptionsCont::getOptions().getString("default.right-of-way"))),
285  myFringeType(FRINGE_TYPE_DEFAULT),
286  myDiscardAllCrossings(false),
287  myCrossingsLoadedFromSumoNet(0),
288  myDisplacementError(0),
289  myIsBentPriority(false),
290  myTypeWasGuessed(false) {
292  throw ProcessError("Invalid node id '" + myID + "'.");
293  }
294 }
295 
296 
298  delete myRequest;
299 }
300 
301 
302 void
304  bool updateEdgeGeometries) {
305  myPosition = position;
306  // patch type
307  myType = type;
308  if (!isTrafficLight(myType)) {
310  }
311  if (updateEdgeGeometries) {
312  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
313  PositionVector geom = (*i)->getGeometry();
314  geom[-1] = myPosition;
315  (*i)->setGeometry(geom);
316  }
317  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
318  PositionVector geom = (*i)->getGeometry();
319  geom[0] = myPosition;
320  (*i)->setGeometry(geom);
321  }
322  }
323 }
324 
325 
326 
327 // ----------- Applying offset
328 void
329 NBNode::reshiftPosition(double xoff, double yoff) {
330  myPosition.add(xoff, yoff, 0);
331  myPoly.add(xoff, yoff, 0);
332  for (auto& wacs : myWalkingAreaCustomShapes) {
333  wacs.shape.add(xoff, yoff, 0);
334  }
335  for (auto& c : myCrossings) {
336  c->customShape.add(xoff, yoff, 0);
337  }
338 }
339 
340 
341 void
343  myPosition.mul(1, -1);
344  myPoly.mirrorX();
345  // mirror pre-computed geometry of crossings and walkingareas
346  for (auto& c : myCrossings) {
347  c->customShape.mirrorX();
348  c->shape.mirrorX();
349  }
350  for (auto& wa : myWalkingAreas) {
351  wa.shape.mirrorX();
352  }
353  for (auto& wacs : myWalkingAreaCustomShapes) {
354  wacs.shape.mirrorX();
355  }
356 }
357 
358 
359 // ----------- Methods for dealing with assigned traffic lights
360 void
362  myTrafficLights.insert(tlDef);
363  // rail signals receive a temporary traffic light in order to set connection tl-linkIndex
366  }
367 }
368 
369 
370 void
372  tlDef->removeNode(this);
373  myTrafficLights.erase(tlDef);
374 }
375 
376 
377 void
379  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
380  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
381  removeTrafficLight(*i);
382  }
383 }
384 
385 
386 void
387 NBNode::invalidateTLS(NBTrafficLightLogicCont& tlCont, bool removedConnections, bool addedConnections) {
388  if (isTLControlled()) {
389  std::set<NBTrafficLightDefinition*> oldDefs(myTrafficLights);
390  for (std::set<NBTrafficLightDefinition*>::iterator it = oldDefs.begin(); it != oldDefs.end(); ++it) {
391  NBTrafficLightDefinition* orig = *it;
392  if (dynamic_cast<NBLoadedSUMOTLDef*>(orig) != nullptr) {
393  dynamic_cast<NBLoadedSUMOTLDef*>(orig)->registerModifications(removedConnections, addedConnections);
394  } else if (dynamic_cast<NBOwnTLDef*>(orig) == nullptr) {
395  NBTrafficLightDefinition* newDef = new NBOwnTLDef(orig->getID(), orig->getOffset(), orig->getType());
396  const std::vector<NBNode*>& nodes = orig->getNodes();
397  while (!nodes.empty()) {
398  newDef->addNode(nodes.front());
399  nodes.front()->removeTrafficLight(orig);
400  }
401  tlCont.removeFully(orig->getID());
402  tlCont.insert(newDef);
403  }
404  }
405  }
406 }
407 
408 
409 void
410 NBNode::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
411  for (std::set<NBTrafficLightDefinition*>::iterator it = myTrafficLights.begin(); it != myTrafficLights.end(); ++it) {
412  (*it)->shiftTLConnectionLaneIndex(edge, offset, threshold);
413  }
414 }
415 
416 // ----------- Prunning the input
417 int
419  int ret = 0;
420  int pos = 0;
421  EdgeVector::const_iterator j = myIncomingEdges.begin();
422  while (j != myIncomingEdges.end()) {
423  // skip edges which are only incoming and not outgoing
424  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), *j) == myOutgoingEdges.end()) {
425  ++j;
426  ++pos;
427  continue;
428  }
429  // an edge with both its origin and destination being the current
430  // node should be removed
431  NBEdge* dummy = *j;
432  WRITE_WARNINGF(" Removing self-looping edge '%'", dummy->getID());
433  // get the list of incoming edges connected to the self-loop
434  EdgeVector incomingConnected = dummy->getIncomingEdges();
435  // get the list of outgoing edges connected to the self-loop
436  EdgeVector outgoingConnected = dummy->getConnectedEdges();
437  // let the self-loop remap its connections
438  dummy->remapConnections(incomingConnected);
439  remapRemoved(tc, dummy, incomingConnected, outgoingConnected);
440  // delete the self-loop
441  ec.erase(dc, dummy);
442  j = myIncomingEdges.begin() + pos;
443  ++ret;
444  }
445  return ret;
446 }
447 
448 
449 // -----------
450 void
452  assert(edge != 0);
453  if (find(myIncomingEdges.begin(), myIncomingEdges.end(), edge) == myIncomingEdges.end()) {
454  myIncomingEdges.push_back(edge);
455  myAllEdges.push_back(edge);
456  }
457 }
458 
459 
460 void
462  assert(edge != 0);
463  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge) == myOutgoingEdges.end()) {
464  myOutgoingEdges.push_back(edge);
465  myAllEdges.push_back(edge);
466  }
467 }
468 
469 
470 bool
471 NBNode::isSimpleContinuation(bool checkLaneNumbers, bool checkWidth) const {
472  // one in, one out->continuation
473  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
474  NBEdge* in = myIncomingEdges.front();
475  NBEdge* out = myOutgoingEdges.front();
476  // both must have the same number of lanes
477  return ((!checkLaneNumbers || in->getNumLanes() == out->getNumLanes())
478  && (!checkWidth || in->getTotalWidth() == out->getTotalWidth()));
479  }
480  // two in and two out and both in reverse direction
481  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
482  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
483  NBEdge* in = *i;
484  EdgeVector::const_iterator opposite = find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(), NBContHelper::opposite_finder(in));
485  // must have an opposite edge
486  if (opposite == myOutgoingEdges.end()) {
487  return false;
488  }
489  // both must have the same number of lanes
491  if (checkLaneNumbers && in->getNumLanes() != (*opposite)->getNumLanes()) {
492  return false;
493  }
494  if (checkWidth && in->getTotalWidth() != (*opposite)->getTotalWidth()) {
495  return false;
496  }
497  }
498  return true;
499  }
500  // nope
501  return false;
502 }
503 
504 
507  const PositionVector& endShape,
508  int numPoints,
509  bool isTurnaround,
510  double extrapolateBeg,
511  double extrapolateEnd,
512  NBNode* recordError,
513  int shapeFlag) const {
514 
515  bool ok = true;
516  PositionVector init = bezierControlPoints(begShape, endShape, isTurnaround, extrapolateBeg, extrapolateEnd, ok, recordError, DEG2RAD(5), shapeFlag);
517 #ifdef DEBUG_SMOOTH_GEOM
518  if (DEBUGCOND) {
519  std::cout << "computeSmoothShape node " << getID() << " init=" << init << "\n";
520  }
521 #endif
522  if (init.size() == 0) {
523  PositionVector ret;
524  ret.push_back(begShape.back());
525  ret.push_back(endShape.front());
526  return ret;
527  } else {
528  return init.bezier(numPoints).smoothedZFront();
529  }
530 }
531 
534  const PositionVector& begShape,
535  const PositionVector& endShape,
536  bool isTurnaround,
537  double extrapolateBeg,
538  double extrapolateEnd,
539  bool& ok,
540  NBNode* recordError,
541  double straightThresh,
542  int shapeFlag) {
543 
544  const Position beg = begShape.back();
545  const Position end = endShape.front();
546  const double dist = beg.distanceTo2D(end);
547  PositionVector init;
548  if (dist < POSITION_EPS || beg.distanceTo2D(begShape[-2]) < POSITION_EPS || end.distanceTo2D(endShape[1]) < POSITION_EPS) {
549 #ifdef DEBUG_SMOOTH_GEOM
550  if (DEBUGCOND2(recordError)) std::cout << " bezierControlPoints failed beg=" << beg << " end=" << end
551  << " dist=" << dist
552  << " distBegLast=" << beg.distanceTo2D(begShape[-2])
553  << " distEndFirst=" << end.distanceTo2D(endShape[1])
554  << "\n";
555 #endif
556  // typically, this node a is a simpleContinuation. see also #2539
557  return init;
558  } else {
559  init.push_back(beg);
560  if (isTurnaround) {
561  // turnarounds:
562  // - end of incoming lane
563  // - position between incoming/outgoing end/begin shifted by the distance orthogonally
564  // - begin of outgoing lane
565  Position center = PositionVector::positionAtOffset2D(beg, end, beg.distanceTo2D(end) / (double) 2.);
566  center.sub(beg.y() - end.y(), end.x() - beg.x());
567  init.push_back(center);
568  } else {
569  const double angle = GeomHelper::angleDiff(begShape.angleAt2D(-2), endShape.angleAt2D(0));
570  PositionVector endShapeBegLine(endShape[0], endShape[1]);
571  PositionVector begShapeEndLineRev(begShape[-1], begShape[-2]);
572  endShapeBegLine.extrapolate2D(100, true);
573  begShapeEndLineRev.extrapolate2D(100, true);
574  if (fabs(angle) < M_PI / 4.) {
575  // very low angle: could be an s-shape or a straight line
576  const double displacementAngle = GeomHelper::angleDiff(begShape.angleAt2D(-2), beg.angleTo2D(end));
577  const double bendDeg = RAD2DEG(fabs(displacementAngle - angle));
578  const double halfDistance = dist / 2;
579  if (fabs(displacementAngle) <= straightThresh && fabs(angle) <= straightThresh) {
580 #ifdef DEBUG_SMOOTH_GEOM
581  if (DEBUGCOND2(recordError)) std::cout << " bezierControlPoints identified straight line beg=" << beg << " end=" << end
582  << " angle=" << RAD2DEG(angle) << " displacementAngle=" << RAD2DEG(displacementAngle) << "\n";
583 #endif
584  return PositionVector();
585  } else if (bendDeg > 22.5 && pow(bendDeg / 45, 2) / dist > 0.13) {
586  // do not allow s-curves with extreme bends
587  // (a linear dependency is to restrictive at low displacementAngles and too permisive at high angles)
588 #ifdef DEBUG_SMOOTH_GEOM
589  if (DEBUGCOND2(recordError)) std::cout << " bezierControlPoints found extreme s-curve, falling back to straight line beg=" << beg << " end=" << end
590  << " angle=" << RAD2DEG(angle) << " displacementAngle=" << RAD2DEG(displacementAngle)
591  << " dist=" << dist << " bendDeg=" << bendDeg << " bd2=" << pow(bendDeg / 45, 2)
592  << " displacementError=" << sin(displacementAngle) * dist
593  << " begShape=" << begShape << " endShape=" << endShape << "\n";
594 #endif
595  ok = false;
596  if (recordError != nullptr && (shapeFlag & SCURVE_IGNORE) == 0) {
597  recordError->myDisplacementError = MAX2(recordError->myDisplacementError, (double)fabs(sin(displacementAngle) * dist));
598  }
599  return PositionVector();
600  } else {
601  const double endLength = begShape[-2].distanceTo2D(begShape[-1]);
602  const double off1 = endLength + MIN2(extrapolateBeg, halfDistance);
603  init.push_back(PositionVector::positionAtOffset2D(begShapeEndLineRev[1], begShapeEndLineRev[0], off1));
604  const double off2 = 100. - MIN2(extrapolateEnd, halfDistance);
605  init.push_back(PositionVector::positionAtOffset2D(endShapeBegLine[0], endShapeBegLine[1], off2));
606 #ifdef DEBUG_SMOOTH_GEOM
607  if (DEBUGCOND2(recordError)) std::cout << " bezierControlPoints found s-curve beg=" << beg << " end=" << end
608  << " angle=" << RAD2DEG(angle) << " displacementAngle=" << RAD2DEG(displacementAngle)
609  << " halfDistance=" << halfDistance << "\n";
610 #endif
611  }
612  } else {
613  // turning
614  // - end of incoming lane
615  // - intersection of the extrapolated lanes
616  // - begin of outgoing lane
617  // attention: if there is no intersection, use a straight line
618  Position intersect = endShapeBegLine.intersectionPosition2D(begShapeEndLineRev);
619  if (intersect == Position::INVALID) {
620 #ifdef DEBUG_SMOOTH_GEOM
621  if (DEBUGCOND2(recordError)) {
622  std::cout << " bezierControlPoints failed beg=" << beg << " end=" << end << " intersect=" << intersect
623  << " endShapeBegLine=" << endShapeBegLine
624  << " begShapeEndLineRev=" << begShapeEndLineRev
625  << "\n";
626  }
627 #endif
628  ok = false;
629  if (recordError != nullptr && (shapeFlag & SCURVE_IGNORE) == 0) {
630  // it's unclear if this error can be solved via stretching the intersection.
631  recordError->myDisplacementError = MAX2(recordError->myDisplacementError, (double)1.0);
632  }
633  return PositionVector();
634  }
635  const double minControlLength = MIN2((double)1.0, dist / 2);
636  const double distBeg = intersect.distanceTo2D(beg);
637  const double distEnd = intersect.distanceTo2D(end);
638  const bool lengthenBeg = distBeg <= minControlLength;
639  const bool lengthenEnd = distEnd <= minControlLength;
640  if (lengthenBeg && lengthenEnd) {
641 #ifdef DEBUG_SMOOTH_GEOM
642  if (DEBUGCOND2(recordError)) std::cout << " bezierControlPoints failed beg=" << beg << " end=" << end << " intersect=" << intersect
643  << " distBeg=" << distBeg << " distEnd=" << distEnd << "\n";
644 #endif
645  if (recordError != nullptr && (shapeFlag & SCURVE_IGNORE) == 0) {
646  // This should be fixable with minor stretching
647  recordError->myDisplacementError = MAX2(recordError->myDisplacementError, (double)1.0);
648  }
649  ok = false;
650  return PositionVector();
651  } else if ((shapeFlag & FOUR_CONTROL_POINTS)) {
652  init.push_back(begShapeEndLineRev.positionAtOffset2D(100 - extrapolateBeg));
653  init.push_back(endShapeBegLine.positionAtOffset2D(100 - extrapolateEnd));
654  } else if (lengthenBeg || lengthenEnd) {
655  init.push_back(begShapeEndLineRev.positionAtOffset2D(100 - minControlLength));
656  init.push_back(endShapeBegLine.positionAtOffset2D(100 - minControlLength));
657  } else if ((shapeFlag & AVOID_WIDE_LEFT_TURN) != 0
658  // there are two reasons for enabling special geometry rules:
659  // 1) sharp edge angles which could cause overshoot
660  // 2) junction geometries with a large displacement between opposite left turns
661  // which would cause the default geometry to overlap
662  && ((shapeFlag & AVOID_INTERSECTING_LEFT_TURNS) != 0
663  || (angle > DEG2RAD(95) && (distBeg > 20 || distEnd > 20)))) {
664  //std::cout << " bezierControlPoints intersect=" << intersect << " dist=" << dist << " distBeg=" << distBeg << " distEnd=" << distEnd << " angle=" << RAD2DEG(angle) << " flag=" << shapeFlag << "\n";
665  const double factor = ((shapeFlag & AVOID_INTERSECTING_LEFT_TURNS) == 0 ? 1
666  : MIN2(0.6, 16 / dist));
667  init.push_back(begShapeEndLineRev.positionAtOffset2D(100 - MIN2(distBeg * factor / 1.2, dist * factor / 1.8)));
668  init.push_back(endShapeBegLine.positionAtOffset2D(100 - MIN2(distEnd * factor / 1.2, dist * factor / 1.8)));
669  } else if ((shapeFlag & AVOID_WIDE_RIGHT_TURN) != 0 && angle < DEG2RAD(-95) && (distBeg > 20 || distEnd > 20)) {
670  //std::cout << " bezierControlPoints intersect=" << intersect << " distBeg=" << distBeg << " distEnd=" << distEnd << "\n";
671  init.push_back(begShapeEndLineRev.positionAtOffset2D(100 - MIN2(distBeg / 1.4, dist / 2)));
672  init.push_back(endShapeBegLine.positionAtOffset2D(100 - MIN2(distEnd / 1.4, dist / 2)));
673  } else {
674  double z;
675  const double z1 = begShapeEndLineRev.positionAtOffset2D(begShapeEndLineRev.nearest_offset_to_point2D(intersect)).z();
676  const double z2 = endShapeBegLine.positionAtOffset2D(endShapeBegLine.nearest_offset_to_point2D(intersect)).z();
677  const double z3 = 0.5 * (beg.z() + end.z());
678  // if z1 and z2 are on the same side in regard to z3 then we
679  // can use their avarage. Otherwise, the intersection in 3D
680  // is not good and we are better of using z3
681  if ((z1 <= z3 && z2 <= z3) || (z1 >= z3 && z2 >= z3)) {
682  z = 0.5 * (z1 + z2);
683  } else {
684  z = z3;
685  }
686  intersect.set(intersect.x(), intersect.y(), z);
687  init.push_back(intersect);
688  }
689  }
690  }
691  init.push_back(end);
692  }
693  return init;
694 }
695 
696 
698 NBNode::computeInternalLaneShape(NBEdge* fromE, const NBEdge::Connection& con, int numPoints, NBNode* recordError, int shapeFlag) const {
699  if (con.fromLane >= fromE->getNumLanes()) {
700  throw ProcessError("Connection '" + con.getDescription(fromE) + "' starts at a non-existant lane.");
701  }
702  if (con.toLane >= con.toEdge->getNumLanes()) {
703  throw ProcessError("Connection '" + con.getDescription(fromE) + "' targets a non-existant lane.");
704  }
705  PositionVector fromShape = fromE->getLaneShape(con.fromLane);
706  PositionVector toShape = con.toEdge->getLaneShape(con.toLane);
707  PositionVector ret;
708  bool useCustomShape = con.customShape.size() > 0;
709  if (useCustomShape) {
710  // ensure that the shape starts and ends at the intersection boundary
711  PositionVector startBorder = fromE->getNodeBorder(this);
712  if (startBorder.size() == 0) {
713  startBorder = fromShape.getOrthogonal(fromShape.back(), 1, true);
714  }
715  PositionVector tmp = NBEdge::startShapeAt(con.customShape, this, startBorder);
716  if (tmp.size() < 2) {
717  WRITE_WARNINGF("Could not use custom shape for connection %.", con.getDescription(fromE));
718  useCustomShape = false;
719  } else {
720  if (tmp.length2D() > con.customShape.length2D() + POSITION_EPS) {
721  // shape was lengthened at the start, make sure it attaches at the center of the lane
722  tmp[0] = fromShape.back();
723  } else if (recordError != nullptr) {
724  const double offset = tmp[0].distanceTo2D(fromShape.back());
725  if (offset > fromE->getLaneWidth(con.fromLane) / 2) {
726  WRITE_WARNINGF("Custom shape has distance % to incoming lane for connection %.", offset, con.getDescription(fromE));
727  }
728  }
729  PositionVector endBorder = con.toEdge->getNodeBorder(this);
730  if (endBorder.size() == 0) {
731  endBorder = toShape.getOrthogonal(toShape.front(), 1, false);
732  }
733  ret = NBEdge::startShapeAt(tmp.reverse(), this, endBorder).reverse();
734  if (ret.size() < 2) {
735  WRITE_WARNINGF("Could not use custom shape for connection %.", con.getDescription(fromE));
736  useCustomShape = false;
737  } else if (ret.length2D() > tmp.length2D() + POSITION_EPS) {
738  // shape was lengthened at the end, make sure it attaches at the center of the lane
739  ret[-1] = toShape.front();
740  } else if (recordError != nullptr) {
741  const double offset = ret[-1].distanceTo2D(toShape.front());
742  if (offset > con.toEdge->getLaneWidth(con.toLane) / 2) {
743  WRITE_WARNINGF("Custom shape has distance % to outgoing lane for connection %.", offset, con.getDescription(fromE));
744  }
745  }
746  }
747  }
748  if (!useCustomShape) {
749  displaceShapeAtWidthChange(fromE, con, fromShape, toShape);
750  double extrapolateBeg = 5. * fromE->getNumLanes();
751  double extrapolateEnd = 5. * con.toEdge->getNumLanes();
752  LinkDirection dir = getDirection(fromE, con.toEdge);
753  if (dir == LINKDIR_LEFT || dir == LINKDIR_TURN) {
754  shapeFlag += AVOID_WIDE_LEFT_TURN;
755  }
756 #ifdef DEBUG_SMOOTH_GEOM
757  if (DEBUGCOND) {
758  std::cout << "computeInternalLaneShape node " << getID() << " fromE=" << fromE->getID() << " toE=" << con.toEdge->getID() << "\n";
759  }
760 #endif
761  ret = computeSmoothShape(fromShape, toShape,
762  numPoints, fromE->getTurnDestination() == con.toEdge,
763  extrapolateBeg, extrapolateEnd, recordError, shapeFlag);
764  }
765  const NBEdge::Lane& lane = fromE->getLaneStruct(con.fromLane);
766  if (lane.endOffset > 0) {
767  PositionVector beg = lane.shape.getSubpart(lane.shape.length() - lane.endOffset, lane.shape.length());
768  beg.append(ret);
769  ret = beg;
770  }
771  if (con.toEdge->isBidiRail() && con.toEdge->getTurnDestination(true)->getEndOffset() > 0) {
772  PositionVector end = toShape.getSubpart(0, con.toEdge->getTurnDestination(true)->getEndOffset());
773  ret.append(end);
774  }
775  return ret;
776 }
777 
778 
779 bool
781  return (myIncomingEdges.size() == 1
782  && myOutgoingEdges.size() == 1
783  && myIncomingEdges[0]->getNumLanes() != myOutgoingEdges[0]->getNumLanes()
784  && myIncomingEdges[0]->getTotalWidth() == myOutgoingEdges[0]->getTotalWidth());
785 }
786 
787 void
789  PositionVector& fromShape, PositionVector& toShape) const {
791  // displace shapes
792  NBEdge* in = myIncomingEdges[0];
793  NBEdge* out = myOutgoingEdges[0];
794  double outCenter = out->getLaneWidth(con.toLane) / 2;
795  for (int i = 0; i < con.toLane; ++i) {
796  outCenter += out->getLaneWidth(i);
797  }
798  double inCenter = in->getLaneWidth(con.fromLane) / 2;
799  for (int i = 0; i < con.fromLane; ++i) {
800  inCenter += in->getLaneWidth(i);
801  }
802  //std::cout << "displaceShapeAtWidthChange inCenter=" << inCenter << " outCenter=" << outCenter << "\n";
803  try {
804  if (in->getNumLanes() > out->getNumLanes()) {
805  // shift toShape so the internal lane ends straight at the displaced entry point
806  toShape.move2side(outCenter - inCenter);
807  } else {
808  // shift fromShape so the internal lane starts straight at the displaced exit point
809  fromShape.move2side(inCenter - outCenter);
810 
811  }
812  } catch (InvalidArgument&) { }
813  } else {
814  SVCPermissions fromP = from->getPermissions(con.fromLane);
815  SVCPermissions toP = con.toEdge->getPermissions(con.toLane);
816  if ((fromP & toP) == SVC_BICYCLE && (fromP | toP) != SVC_BICYCLE) {
817  double shift = (from->getLaneWidth(con.fromLane) - con.toEdge->getLaneWidth(con.toLane)) / 2;
818  if (toP == SVC_BICYCLE) {
819  // let connection to dedicated bicycle lane start on the right side of a mixed lane for straight an right-going connections
820  // (on the left side for left turns)
821  // XXX indirect left turns should also start on the right side
822  LinkDirection dir = getDirection(from, con.toEdge);
823  if (dir == LINKDIR_LEFT || dir == LINKDIR_PARTLEFT || dir == LINKDIR_TURN) {
824  fromShape.move2side(-shift);
825  } else {
826  fromShape.move2side(shift);
827  }
828  } else if (fromP == SVC_BICYCLE) {
829  // let connection from dedicated bicycle end on the right side of a mixed lane
830  toShape.move2side(-shift);
831  }
832  }
833  }
834 }
835 
836 bool
837 NBNode::needsCont(const NBEdge* fromE, const NBEdge* otherFromE,
838  const NBEdge::Connection& c, const NBEdge::Connection& otherC) const {
839  const NBEdge* toE = c.toEdge;
840  const NBEdge* otherToE = otherC.toEdge;
841 
843  return false;
844  }
845  LinkDirection d1 = getDirection(fromE, toE);
846  const bool thisRight = (d1 == LINKDIR_RIGHT || d1 == LINKDIR_PARTRIGHT);
847  const bool rightTurnConflict = (thisRight &&
848  NBNode::rightTurnConflict(fromE, toE, c.fromLane, otherFromE, otherToE, otherC.fromLane));
849  if (thisRight && !rightTurnConflict) {
850  return false;
851  }
852  if (!(foes(otherFromE, otherToE, fromE, toE) || myRequest == nullptr || rightTurnConflict)) {
853  // if they do not cross, no waiting place is needed
854  return false;
855  }
856  LinkDirection d2 = getDirection(otherFromE, otherToE);
857  if (d2 == LINKDIR_TURN) {
858  return false;
859  }
860  const bool thisLeft = (d1 == LINKDIR_LEFT || d1 == LINKDIR_TURN);
861  const bool otherLeft = (d2 == LINKDIR_LEFT || d2 == LINKDIR_TURN);
862  const bool bothLeft = thisLeft && otherLeft;
863  if (fromE == otherFromE && !thisRight) {
864  // ignore same edge links except for right-turns
865  return false;
866  }
867  if (thisRight && d2 != LINKDIR_STRAIGHT) {
868  return false;
869  }
870  if (c.tlID != "" && !bothLeft) {
872  for (std::set<NBTrafficLightDefinition*>::const_iterator it = myTrafficLights.begin(); it != myTrafficLights.end(); ++it) {
873  if ((*it)->needsCont(fromE, toE, otherFromE, otherToE)) {
874  return true;
875  }
876  }
877  return false;
878  }
879  if (fromE->getJunctionPriority(this) > 0 && otherFromE->getJunctionPriority(this) > 0) {
880  return mustBrake(fromE, toE, c.fromLane, c.toLane, false);
881  }
882  return false;
883 }
884 
885 bool
887  const NBEdge* foeFrom, const NBEdge::Connection& foe) const {
888  return (foe.haveVia && isTLControlled() && c.tlLinkIndex >= 0 && foe.tlLinkIndex >= 0
889  && !foeFrom->isTurningDirectionAt(foe.toEdge)
890  && foes(from, c.toEdge, foeFrom, foe.toEdge)
891  && !needsCont(foeFrom, from, foe, c));
892 }
893 
894 
895 void
897  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
898  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
899  // if this is the only controlled node we keep the tlDef as it is to generate a warning later
900  if ((*i)->getNodes().size() > 1) {
901  myTrafficLights.erase(*i);
902  (*i)->removeNode(this);
903  (*i)->setParticipantsInformation();
904  (*i)->setTLControllingInformation();
905  }
906  }
907 }
908 
909 
910 void
912  delete myRequest; // possibly recomputation step
913  myRequest = nullptr;
914  if (myIncomingEdges.size() == 0 || myOutgoingEdges.size() == 0) {
915  // no logic if nothing happens here
918  return;
919  }
920  // compute the logic if necessary or split the junction
922  // build the request
924  // check whether it is not too large
925  int numConnections = numNormalConnections();
926  if (numConnections >= SUMO_MAX_CONNECTIONS) {
927  // yep -> make it untcontrolled, warn
928  delete myRequest;
929  myRequest = nullptr;
932  } else {
934  }
935  WRITE_WARNINGF("Junction '%' is too complicated (% connections, max %); will be set to %.",
936  getID(), numConnections, SUMO_MAX_CONNECTIONS, toString(myType));
937  } else if (numConnections == 0) {
938  delete myRequest;
939  myRequest = nullptr;
942  } else {
944  }
945  }
946 }
947 
948 
949 void
950 NBNode::computeLogic2(bool checkLaneFoes) {
951  if (myRequest != nullptr) {
952  myRequest->computeLogic(checkLaneFoes);
953  }
954 }
955 
956 
957 bool
959  if (myRequest) {
960  myRequest->writeLogic(into);
961  return true;
962  }
963  return false;
964 }
965 
966 
967 const std::string
968 NBNode::getFoes(int linkIndex) const {
969  if (myRequest == nullptr) {
970  return "";
971  } else {
972  return myRequest->getFoes(linkIndex);
973  }
974 }
975 
976 
977 const std::string
978 NBNode::getResponse(int linkIndex) const {
979  if (myRequest == nullptr) {
980  return "";
981  } else {
982  return myRequest->getResponse(linkIndex);
983  }
984 }
985 
986 
987 void
988 NBNode::computeNodeShape(double mismatchThreshold) {
989  if (myHaveCustomPoly) {
990  return;
991  }
992  if (myIncomingEdges.size() == 0 && myOutgoingEdges.size() == 0) {
993  // may be an intermediate step during network editing
994  myPoly.clear();
995  myPoly.push_back(myPosition);
996  return;
997  }
998  if (OptionsCont::getOptions().getFloat("default.junctions.radius") < 0) {
999  // skip shape computation by option
1000  return;
1001  }
1002  try {
1003  NBNodeShapeComputer computer(*this);
1004  myPoly = computer.compute();
1005  if (myRadius == UNSPECIFIED_RADIUS && !OptionsCont::getOptions().isDefault("default.junctions.radius")) {
1006  myRadius = computer.getRadius();
1007  }
1008  if (myPoly.size() > 0) {
1009  PositionVector tmp = myPoly;
1010  tmp.push_back_noDoublePos(tmp[0]); // need closed shape
1011  if (mismatchThreshold >= 0
1012  && !tmp.around(myPosition)
1013  && tmp.distance2D(myPosition) > mismatchThreshold) {
1014  WRITE_WARNINGF("Shape for junction '%' has distance % to its given position.", myID, tmp.distance2D(myPosition));
1015  }
1016  }
1017  } catch (InvalidArgument&) {
1018  WRITE_WARNINGF("For junction '%': could not compute shape.", myID);
1019  // make sure our shape is not empty because our XML schema forbids empty attributes
1020  myPoly.clear();
1021  myPoly.push_back(myPosition);
1022  }
1023 }
1024 
1025 
1026 void
1028  // special case a):
1029  // one in, one out, the outgoing has one lane more
1030  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
1031  NBEdge* in = myIncomingEdges[0];
1032  NBEdge* out = myOutgoingEdges[0];
1033  // check if it's not the turnaround
1034  if (in->getTurnDestination() == out) {
1035  // will be added later or not...
1036  return;
1037  }
1038 #ifdef DEBUG_CONNECTION_GUESSING
1039  if (DEBUGCOND) {
1040  std::cout << "l2l node=" << getID() << " specialCase a\n";
1041  }
1042 #endif
1043  const int inOffset = MAX2(0, in->getFirstNonPedestrianLaneIndex(FORWARD, true));
1044  const int outOffset = MAX2(0, out->getFirstNonPedestrianLaneIndex(FORWARD, true));
1046  && in->getNumLanes() - inOffset == out->getNumLanes() - outOffset - 1
1047  && in != out
1048  && in->isConnectedTo(out)) {
1049  for (int i = inOffset; i < in->getNumLanes(); ++i) {
1050  in->setConnection(i, out, i - inOffset + outOffset + 1, NBEdge::L2L_COMPUTED);
1051  }
1052  in->setConnection(inOffset, out, outOffset, NBEdge::L2L_COMPUTED);
1053  return;
1054  }
1055  }
1056  // special case b):
1057  // two in, one out, the outgoing has the same number of lanes as the sum of the incoming
1058  // --> highway on-ramp
1059  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 1) {
1060  NBEdge* out = myOutgoingEdges[0];
1061  NBEdge* in1 = myIncomingEdges[0];
1062  NBEdge* in2 = myIncomingEdges[1];
1063  const int outOffset = MAX2(0, out->getFirstNonPedestrianLaneIndex(FORWARD, true));
1064  int in1Offset = MAX2(0, in1->getFirstNonPedestrianLaneIndex(FORWARD, true));
1065  int in2Offset = MAX2(0, in2->getFirstNonPedestrianLaneIndex(FORWARD, true));
1066  if (in1->getNumLanes() + in2->getNumLanes() - in1Offset - in2Offset == out->getNumLanes() - outOffset
1069  && in1 != out
1070  && in2 != out
1071  && in1->isConnectedTo(out)
1072  && in2->isConnectedTo(out)
1073  && in1->getSpecialLane(SVC_BICYCLE) == -1
1074  && in2->getSpecialLane(SVC_BICYCLE) == -1
1075  && out->getSpecialLane(SVC_BICYCLE) == -1
1076  && isLongEnough(out, MIN_WEAVE_LENGTH)) {
1077 #ifdef DEBUG_CONNECTION_GUESSING
1078  if (DEBUGCOND) {
1079  std::cout << "l2l node=" << getID() << " specialCase b\n";
1080  }
1081 #endif
1082  // for internal: check which one is the rightmost
1083  double a1 = in1->getAngleAtNode(this);
1084  double a2 = in2->getAngleAtNode(this);
1085  double ccw = GeomHelper::getCCWAngleDiff(a1, a2);
1086  double cw = GeomHelper::getCWAngleDiff(a1, a2);
1087  if (ccw > cw) {
1088  std::swap(in1, in2);
1089  std::swap(in1Offset, in2Offset);
1090  }
1091  in1->addLane2LaneConnections(in1Offset, out, outOffset, in1->getNumLanes() - in1Offset, NBEdge::L2L_VALIDATED, true);
1092  in2->addLane2LaneConnections(in2Offset, out, in1->getNumLanes() + outOffset - in1Offset, in2->getNumLanes() - in2Offset, NBEdge::L2L_VALIDATED, true);
1093  return;
1094  }
1095  }
1096  // special case c):
1097  // one in, two out, the incoming has the same number of lanes or only 1 lane less than the sum of the outgoing lanes
1098  // --> highway off-ramp
1099  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 2) {
1100  NBEdge* in = myIncomingEdges[0];
1101  NBEdge* out1 = myOutgoingEdges[0];
1102  NBEdge* out2 = myOutgoingEdges[1];
1103  const int inOffset = MAX2(0, in->getFirstNonPedestrianLaneIndex(FORWARD, true));
1104  int out1Offset = MAX2(0, out1->getFirstNonPedestrianLaneIndex(FORWARD, true));
1105  int out2Offset = MAX2(0, out2->getFirstNonPedestrianLaneIndex(FORWARD, true));
1106  const int deltaLaneSum = (out2->getNumLanes() + out1->getNumLanes() - out1Offset - out2Offset) - (in->getNumLanes() - inOffset);
1107  if ((deltaLaneSum == 0 || (deltaLaneSum == 1 && in->getPermissionVariants(inOffset, in->getNumLanes()).size() == 1))
1109  && in != out1
1110  && in != out2
1111  && in->isConnectedTo(out1)
1112  && in->isConnectedTo(out2)
1113  && !in->isTurningDirectionAt(out1)
1114  && !in->isTurningDirectionAt(out2)
1115  ) {
1116 #ifdef DEBUG_CONNECTION_GUESSING
1117  if (DEBUGCOND) {
1118  std::cout << "l2l node=" << getID() << " specialCase c\n";
1119  }
1120 #endif
1121  // for internal: check which one is the rightmost
1122  if (NBContHelper::relative_outgoing_edge_sorter(in)(out2, out1)) {
1123  std::swap(out1, out2);
1124  std::swap(out1Offset, out2Offset);
1125  }
1126  in->addLane2LaneConnections(inOffset, out1, out1Offset, out1->getNumLanes() - out1Offset, NBEdge::L2L_VALIDATED, true);
1127  in->addLane2LaneConnections(out1->getNumLanes() + inOffset - out1Offset - deltaLaneSum, out2, out2Offset, out2->getNumLanes() - out2Offset, NBEdge::L2L_VALIDATED, false);
1128  return;
1129  }
1130  }
1131  // special case d):
1132  // one in, one out, the outgoing has one lane less and node has type 'zipper'
1133  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1 && myType == NODETYPE_ZIPPER) {
1134  NBEdge* in = myIncomingEdges[0];
1135  NBEdge* out = myOutgoingEdges[0];
1136  // check if it's not the turnaround
1137  if (in->getTurnDestination() == out) {
1138  // will be added later or not...
1139  return;
1140  }
1141 #ifdef DEBUG_CONNECTION_GUESSING
1142  if (DEBUGCOND) {
1143  std::cout << "l2l node=" << getID() << " specialCase d\n";
1144  }
1145 #endif
1146  const int inOffset = MAX2(0, in->getFirstNonPedestrianLaneIndex(FORWARD, true));
1147  const int outOffset = MAX2(0, out->getFirstNonPedestrianLaneIndex(FORWARD, true));
1149  && in->getNumLanes() - inOffset == out->getNumLanes() - outOffset + 1
1150  && in != out
1151  && in->isConnectedTo(out)) {
1152  for (int i = inOffset; i < in->getNumLanes(); ++i) {
1153  in->setConnection(i, out, MIN2(outOffset + i, out->getNumLanes() - 1), NBEdge::L2L_COMPUTED, true);
1154  }
1155  return;
1156  }
1157  }
1158  // special case f):
1159  // one in, one out, out has reduced or same number of lanes
1160  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
1161  NBEdge* in = myIncomingEdges[0];
1162  NBEdge* out = myOutgoingEdges[0];
1163  // check if it's not the turnaround
1164  if (in->getTurnDestination() == out) {
1165  // will be added later or not...
1166  return;
1167  }
1168 #ifdef DEBUG_CONNECTION_GUESSING
1169  if (DEBUGCOND) {
1170  std::cout << "l2l node=" << getID() << " specialCase f\n";
1171  }
1172 #endif
1173  int inOffset = MAX2(0, in->getFirstNonPedestrianLaneIndex(FORWARD, true));
1174  const int outOffset = MAX2(0, out->getFirstNonPedestrianLaneIndex(FORWARD, true));
1175  const int reduction = (in->getNumLanes() - inOffset) - (out->getNumLanes() - outOffset);
1177  && reduction >= 0
1178  && in != out
1179  && in->isConnectedTo(out)) {
1180  // in case of reduced lane number, let the rightmost lanse end
1181  inOffset += reduction;
1182  for (int i = outOffset; i < out->getNumLanes(); ++i) {
1183  in->setConnection(i + inOffset - outOffset, out, i, NBEdge::L2L_COMPUTED);
1184  }
1185  //std::cout << " special case f at node=" << getID() << " inOffset=" << inOffset << " outOffset=" << outOffset << "\n";
1186  return;
1187  }
1188  }
1189 
1190  // go through this node's outgoing edges
1191  // for every outgoing edge, compute the distribution of the node's
1192  // incoming edges on this edge when approaching this edge
1193  // the incoming edges' steps will then also be marked as LANE2LANE_RECHECK...
1194  EdgeVector approaching;
1195  for (NBEdge* currentOutgoing : myOutgoingEdges) {
1196  // get the information about edges that do approach this edge
1197  getEdgesThatApproach(currentOutgoing, approaching);
1198  const int numApproaching = (int)approaching.size();
1199  if (numApproaching != 0) {
1200  ApproachingDivider divider(approaching, currentOutgoing);
1201  Bresenham::compute(&divider, numApproaching, divider.numAvailableLanes());
1202  }
1203 #ifdef DEBUG_CONNECTION_GUESSING
1204  if (DEBUGCOND) {
1205  std::cout << "l2l node=" << getID() << " bresenham:\n";
1206  for (NBEdge* e : myIncomingEdges) {
1207  const std::vector<NBEdge::Connection>& elv = e->getConnections();
1208  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1209  std::cout << " " << e->getID() << "_" << (*k).fromLane << " -> " << (*k).toEdge->getID() << "_" << (*k).toLane << "\n";
1210  }
1211  }
1212  }
1213 #endif
1214  int bikeLaneTarget = currentOutgoing->getSpecialLane(SVC_BICYCLE);
1215 
1216  // ensure that all modes have a connection if possible
1217  for (NBEdge* incoming : myIncomingEdges) {
1218  if (incoming->getConnectionLanes(currentOutgoing).size() > 0 && incoming->getStep() <= NBEdge::EdgeBuildingStep::LANES2LANES_DONE) {
1219  // no connections are needed for pedestrians during this step
1220  // no satisfaction is possible if the outgoing edge disallows
1221  SVCPermissions unsatisfied = incoming->getPermissions() & currentOutgoing->getPermissions() & ~SVC_PEDESTRIAN;
1222  //std::cout << "initial unsatisfied modes from edge=" << incoming->getID() << " toEdge=" << currentOutgoing->getID() << " deadModes=" << getVehicleClassNames(unsatisfied) << "\n";
1223  const std::vector<NBEdge::Connection>& elv = incoming->getConnections();
1224  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1225  const NBEdge::Connection& c = *k;
1226  if (c.toEdge == currentOutgoing && c.toLane >= 0) {
1227  const SVCPermissions satisfied = (incoming->getPermissions(c.fromLane) & c.toEdge->getPermissions(c.toLane));
1228  //std::cout << " from=" << incoming->getID() << "_" << c.fromLane << " to=" << c.toEdge->getID() << "_" << c.toLane << " satisfied=" << getVehicleClassNames(satisfied) << "\n";
1229  unsatisfied &= ~satisfied;
1230  }
1231  }
1232  if (unsatisfied != 0) {
1233 #ifdef DEBUG_CONNECTION_GUESSING
1234  if (DEBUGCOND) {
1235  std::cout << " unsatisfied modes from edge=" << incoming->getID() << " toEdge=" << currentOutgoing->getID() << " deadModes=" << getVehicleClassNames(unsatisfied) << "\n";
1236  }
1237 #endif
1238  int fromLane = 0;
1239  while (unsatisfied != 0 && fromLane < incoming->getNumLanes()) {
1240  if ((incoming->getPermissions(fromLane) & unsatisfied) != 0) {
1241  for (int toLane = 0; toLane < currentOutgoing->getNumLanes(); ++toLane) {
1242  const SVCPermissions satisfied = incoming->getPermissions(fromLane) & currentOutgoing->getPermissions(toLane) & unsatisfied;
1243  if (satisfied != 0 && !incoming->getLaneStruct(fromLane).connectionsDone) {
1244  incoming->setConnection((int)fromLane, currentOutgoing, toLane, NBEdge::L2L_COMPUTED);
1245 #ifdef DEBUG_CONNECTION_GUESSING
1246  if (DEBUGCOND) {
1247  std::cout << " new connection from=" << fromLane << " to=" << currentOutgoing->getID() << "_" << toLane << " satisfies=" << getVehicleClassNames(satisfied) << "\n";
1248  }
1249 #endif
1250  unsatisfied &= ~satisfied;
1251  }
1252  }
1253  }
1254  fromLane++;
1255  }
1256 #ifdef DEBUG_CONNECTION_GUESSING
1257  if (DEBUGCOND) {
1258  if (unsatisfied != 0) {
1259  std::cout << " still unsatisfied modes from edge=" << incoming->getID() << " toEdge=" << currentOutgoing->getID() << " deadModes=" << getVehicleClassNames(unsatisfied) << "\n";
1260  }
1261  }
1262 #endif
1263  }
1264  }
1265  // prevent dead-end bicycle lanes (they were excluded by the ApproachingDivider)
1266  // and the bicycle mode might already be satisfied by other lanes
1267  // assume that left-turns and turn-arounds are better satisfied from lanes to the left
1268  LinkDirection dir = getDirection(incoming, currentOutgoing);
1269  if (incoming->getStep() <= NBEdge::EdgeBuildingStep::LANES2LANES_DONE
1270  && ((bikeLaneTarget >= 0 && dir != LINKDIR_TURN)
1271  || dir == LINKDIR_RIGHT || dir == LINKDIR_PARTRIGHT || dir == LINKDIR_STRAIGHT)) {
1272  bool builtConnection = false;
1273  for (int i = 0; i < (int)incoming->getNumLanes(); i++) {
1274  if (incoming->getPermissions(i) == SVC_BICYCLE
1275  && incoming->getConnectionsFromLane(i, currentOutgoing).size() == 0) {
1276  // find a dedicated bike lane as target
1277  if (bikeLaneTarget >= 0) {
1278  incoming->setConnection(i, currentOutgoing, bikeLaneTarget, NBEdge::L2L_COMPUTED);
1279  builtConnection = true;
1280  } else {
1281  // use any lane that allows bicycles
1282  for (int i2 = 0; i2 < (int)currentOutgoing->getNumLanes(); i2++) {
1283  if ((currentOutgoing->getPermissions(i2) & SVC_BICYCLE) != 0) {
1284  // possibly a double-connection
1285  // XXX could use 'true' here but this requires additional work on tls generation
1286  incoming->setConnection(i, currentOutgoing, i2, NBEdge::L2L_COMPUTED, false);
1287  builtConnection = true;
1288  break;
1289  }
1290  }
1291  }
1292  }
1293  }
1294  if (!builtConnection && bikeLaneTarget >= 0
1295  && incoming->getConnectionsFromLane(-1, currentOutgoing, bikeLaneTarget).size() == 0) {
1296  // find origin lane that allows bicycles
1297  int start = 0;
1298  int end = (int)incoming->getNumLanes();
1299  int inc = 1;
1300  if (dir == LINKDIR_TURN || dir == LINKDIR_LEFT || dir == LINKDIR_PARTLEFT) {
1301  std::swap(start, end);
1302  inc = -1;
1303  }
1304  for (int i = start; i < end; i += inc) {
1305  if ((incoming->getPermissions(i) & SVC_BICYCLE) != 0) {
1306  incoming->setConnection(i, currentOutgoing, bikeLaneTarget, NBEdge::L2L_COMPUTED);
1307  break;
1308  }
1309  }
1310  }
1311  }
1312  }
1313  }
1314  // special case e): rail_crossing
1315  // there should only be straight connections here
1316  if (myType == NODETYPE_RAIL_CROSSING) {
1317  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1318  const std::vector<NBEdge::Connection> cons = (*i)->getConnections();
1319  for (std::vector<NBEdge::Connection>::const_iterator k = cons.begin(); k != cons.end(); ++k) {
1320  if (getDirection(*i, (*k).toEdge) == LINKDIR_TURN) {
1321  (*i)->removeFromConnections((*k).toEdge);
1322  }
1323  }
1324  }
1325  }
1326 
1327  // ... but we may have the case that there are no outgoing edges
1328  // In this case, we have to mark the incoming edges as being in state
1329  // LANE2LANE( not RECHECK) by hand
1330  if (myOutgoingEdges.size() == 0) {
1331  for (NBEdge* incoming : myIncomingEdges) {
1332  incoming->markAsInLane2LaneState();
1333  }
1334  }
1335 
1336 #ifdef DEBUG_CONNECTION_GUESSING
1337  if (DEBUGCOND) {
1338  std::cout << "final connections at " << getID() << "\n";
1339  for (NBEdge* e : myIncomingEdges) {
1340  const std::vector<NBEdge::Connection>& elv = e->getConnections();
1341  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1342  std::cout << " " << e->getID() << "_" << (*k).fromLane << " -> " << (*k).toEdge->getID() << "_" << (*k).toLane << "\n";
1343  }
1344  }
1345  }
1346 #endif
1347 }
1348 
1349 bool
1350 NBNode::isLongEnough(NBEdge* out, double minLength) {
1351  double seen = out->getLoadedLength();
1352  while (seen < minLength) {
1353  // advance along trivial continuations
1354  if (out->getToNode()->getOutgoingEdges().size() != 1
1355  || out->getToNode()->getIncomingEdges().size() != 1) {
1356  return false;
1357  } else {
1358  out = out->getToNode()->getOutgoingEdges()[0];
1359  seen += out->getLoadedLength();
1360  }
1361  }
1362  return true;
1363 }
1364 
1365 
1366 void
1367 NBNode::getEdgesThatApproach(NBEdge* currentOutgoing, EdgeVector& approaching) {
1368  // get the position of the node to get the approaching nodes of
1369  EdgeVector::const_iterator i = std::find(myAllEdges.begin(),
1370  myAllEdges.end(), currentOutgoing);
1371  // get the first possible approaching edge
1373  // go through the list of edges clockwise and add the edges
1374  approaching.clear();
1375  for (; *i != currentOutgoing;) {
1376  // check only incoming edges
1377  if ((*i)->getToNode() == this && (*i)->getTurnDestination() != currentOutgoing) {
1378  std::vector<int> connLanes = (*i)->getConnectionLanes(currentOutgoing);
1379  if (connLanes.size() != 0) {
1380  approaching.push_back(*i);
1381  }
1382  }
1384  }
1385 }
1386 
1387 
1388 void
1389 NBNode::replaceOutgoing(NBEdge* which, NBEdge* by, int laneOff) {
1390  // replace the edge in the list of outgoing nodes
1391  EdgeVector::iterator i = std::find(myOutgoingEdges.begin(), myOutgoingEdges.end(), which);
1392  if (i != myOutgoingEdges.end()) {
1393  (*i) = by;
1394  i = std::find(myAllEdges.begin(), myAllEdges.end(), which);
1395  (*i) = by;
1396  }
1397  // replace the edge in connections of incoming edges
1398  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); ++i) {
1399  (*i)->replaceInConnections(which, by, laneOff);
1400  }
1401  // replace within the connetion prohibition dependencies
1402  replaceInConnectionProhibitions(which, by, 0, laneOff);
1403 }
1404 
1405 
1406 void
1408  // replace edges
1409  int laneOff = 0;
1410  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
1411  replaceOutgoing(*i, by, laneOff);
1412  laneOff += (*i)->getNumLanes();
1413  }
1414  // removed double occurences
1416  // check whether this node belongs to a district and the edges
1417  // must here be also remapped
1418  if (myDistrict != nullptr) {
1419  myDistrict->replaceOutgoing(which, by);
1420  }
1421 }
1422 
1423 
1424 void
1425 NBNode::replaceIncoming(NBEdge* which, NBEdge* by, int laneOff) {
1426  // replace the edge in the list of incoming nodes
1427  EdgeVector::iterator i = std::find(myIncomingEdges.begin(), myIncomingEdges.end(), which);
1428  if (i != myIncomingEdges.end()) {
1429  (*i) = by;
1430  i = std::find(myAllEdges.begin(), myAllEdges.end(), which);
1431  (*i) = by;
1432  }
1433  // replace within the connetion prohibition dependencies
1434  replaceInConnectionProhibitions(which, by, laneOff, 0);
1435 }
1436 
1437 
1438 void
1440  // replace edges
1441  int laneOff = 0;
1442  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
1443  replaceIncoming(*i, by, laneOff);
1444  laneOff += (*i)->getNumLanes();
1445  }
1446  // removed double occurences
1448  // check whether this node belongs to a district and the edges
1449  // must here be also remapped
1450  if (myDistrict != nullptr) {
1451  myDistrict->replaceIncoming(which, by);
1452  }
1453 }
1454 
1455 
1456 
1457 void
1459  int whichLaneOff, int byLaneOff) {
1460  // replace in keys
1461  NBConnectionProhibits::iterator j = myBlockedConnections.begin();
1462  while (j != myBlockedConnections.end()) {
1463  bool changed = false;
1464  NBConnection c = (*j).first;
1465  if (c.replaceFrom(which, whichLaneOff, by, byLaneOff)) {
1466  changed = true;
1467  }
1468  if (c.replaceTo(which, whichLaneOff, by, byLaneOff)) {
1469  changed = true;
1470  }
1471  if (changed) {
1472  myBlockedConnections[c] = (*j).second;
1473  myBlockedConnections.erase(j);
1474  j = myBlockedConnections.begin();
1475  } else {
1476  j++;
1477  }
1478  }
1479  // replace in values
1480  for (j = myBlockedConnections.begin(); j != myBlockedConnections.end(); j++) {
1481  NBConnectionVector& prohibiting = (*j).second;
1482  for (NBConnectionVector::iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
1483  NBConnection& sprohibiting = *k;
1484  sprohibiting.replaceFrom(which, whichLaneOff, by, byLaneOff);
1485  sprohibiting.replaceTo(which, whichLaneOff, by, byLaneOff);
1486  }
1487  }
1488 }
1489 
1490 
1491 
1492 void
1494  // check incoming
1495  for (int i = 0; myIncomingEdges.size() > 0 && i < (int)myIncomingEdges.size() - 1; i++) {
1496  int j = i + 1;
1497  while (j < (int)myIncomingEdges.size()) {
1498  if (myIncomingEdges[i] == myIncomingEdges[j]) {
1499  myIncomingEdges.erase(myIncomingEdges.begin() + j);
1500  } else {
1501  j++;
1502  }
1503  }
1504  }
1505  // check outgoing
1506  for (int i = 0; myOutgoingEdges.size() > 0 && i < (int)myOutgoingEdges.size() - 1; i++) {
1507  int j = i + 1;
1508  while (j < (int)myOutgoingEdges.size()) {
1509  if (myOutgoingEdges[i] == myOutgoingEdges[j]) {
1510  myOutgoingEdges.erase(myOutgoingEdges.begin() + j);
1511  } else {
1512  j++;
1513  }
1514  }
1515  }
1516  // check all
1517  for (int i = 0; myAllEdges.size() > 0 && i < (int)myAllEdges.size() - 1; i++) {
1518  int j = i + 1;
1519  while (j < (int)myAllEdges.size()) {
1520  if (myAllEdges[i] == myAllEdges[j]) {
1521  myAllEdges.erase(myAllEdges.begin() + j);
1522  } else {
1523  j++;
1524  }
1525  }
1526  }
1527 }
1528 
1529 
1530 bool
1531 NBNode::hasIncoming(const NBEdge* const e) const {
1532  return std::find(myIncomingEdges.begin(), myIncomingEdges.end(), e) != myIncomingEdges.end();
1533 }
1534 
1535 
1536 bool
1537 NBNode::hasOutgoing(const NBEdge* const e) const {
1538  return std::find(myOutgoingEdges.begin(), myOutgoingEdges.end(), e) != myOutgoingEdges.end();
1539 }
1540 
1541 
1542 NBEdge*
1544  EdgeVector edges = myIncomingEdges;
1545  if (find(edges.begin(), edges.end(), e) != edges.end()) {
1546  edges.erase(find(edges.begin(), edges.end(), e));
1547  }
1548  if (edges.size() == 0) {
1549  return nullptr;
1550  }
1551  if (e->getToNode() == this) {
1552  sort(edges.begin(), edges.end(), NBContHelper::edge_opposite_direction_sorter(e, this, false));
1553  } else {
1554  sort(edges.begin(), edges.end(), NBContHelper::edge_similar_direction_sorter(e));
1555  }
1556  return edges[0];
1557 }
1558 
1559 
1560 void
1562  const NBConnection& mustStop) {
1563  if (mayDrive.getFrom() == nullptr ||
1564  mayDrive.getTo() == nullptr ||
1565  mustStop.getFrom() == nullptr ||
1566  mustStop.getTo() == nullptr) {
1567 
1568  WRITE_WARNING("Something went wrong during the building of a connection...");
1569  return; // !!! mark to recompute connections
1570  }
1571  NBConnectionVector conn = myBlockedConnections[mustStop];
1572  conn.push_back(mayDrive);
1573  myBlockedConnections[mustStop] = conn;
1574 }
1575 
1576 
1577 NBEdge*
1578 NBNode::getPossiblySplittedIncoming(const std::string& edgeid) {
1579  int size = (int) edgeid.length();
1580  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1581  std::string id = (*i)->getID();
1582  if (id.substr(0, size) == edgeid) {
1583  return *i;
1584  }
1585  }
1586  return nullptr;
1587 }
1588 
1589 
1590 NBEdge*
1591 NBNode::getPossiblySplittedOutgoing(const std::string& edgeid) {
1592  int size = (int) edgeid.length();
1593  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1594  std::string id = (*i)->getID();
1595  if (id.substr(0, size) == edgeid) {
1596  return *i;
1597  }
1598  }
1599  return nullptr;
1600 }
1601 
1602 
1603 void
1604 NBNode::removeEdge(NBEdge* edge, bool removeFromConnections) {
1605  EdgeVector::iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), edge);
1606  if (i != myAllEdges.end()) {
1607  myAllEdges.erase(i);
1608  i = std::find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge);
1609  if (i != myOutgoingEdges.end()) {
1610  myOutgoingEdges.erase(i);
1611  } else {
1612  i = std::find(myIncomingEdges.begin(), myIncomingEdges.end(), edge);
1613  if (i != myIncomingEdges.end()) {
1614  myIncomingEdges.erase(i);
1615  } else {
1616  // edge must have been either incoming or outgoing
1617  assert(false);
1618  }
1619  }
1620  if (removeFromConnections) {
1621  for (i = myAllEdges.begin(); i != myAllEdges.end(); ++i) {
1622  (*i)->removeFromConnections(edge);
1623  }
1624  }
1625  // invalidate controlled connections for loaded traffic light plans
1626  for (std::set<NBTrafficLightDefinition*>::iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
1627  (*i)->replaceRemoved(edge, -1, nullptr, -1);
1628  }
1629  }
1630 }
1631 
1632 
1633 Position
1635  Position pos(0, 0);
1636  EdgeVector::const_iterator i;
1637  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1638  NBNode* conn = (*i)->getFromNode();
1639  Position toAdd = conn->getPosition();
1640  toAdd.sub(myPosition);
1641  toAdd.mul((double) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1642  pos.add(toAdd);
1643  }
1644  for (i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1645  NBNode* conn = (*i)->getToNode();
1646  Position toAdd = conn->getPosition();
1647  toAdd.sub(myPosition);
1648  toAdd.mul((double) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1649  pos.add(toAdd);
1650  }
1651  pos.mul((double) - 1.0 / (myIncomingEdges.size() + myOutgoingEdges.size()));
1652  if (pos.x() == 0 && pos.y() == 0) {
1653  pos = Position(1, 0);
1654  }
1655  pos.norm2d();
1656  return pos;
1657 }
1658 
1659 
1660 
1661 void
1663  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1664  (*i)->invalidateConnections();
1665  }
1666 }
1667 
1668 
1669 void
1671  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1672  (*i)->invalidateConnections();
1673  }
1674 }
1675 
1676 
1677 bool
1678 NBNode::mustBrake(const NBEdge* const from, const NBEdge* const to, int fromLane, int toLane, bool includePedCrossings) const {
1679  // unregulated->does not need to brake
1680  if (myRequest == nullptr) {
1681  return false;
1682  }
1683  // vehicles which do not have a following lane must always decelerate to the end
1684  if (to == nullptr) {
1685  return true;
1686  }
1687  // check whether any other connection on this node prohibits this connection
1688  return myRequest->mustBrake(from, to, fromLane, toLane, includePedCrossings);
1689 }
1690 
1691 bool
1692 NBNode::mustBrakeForCrossing(const NBEdge* const from, const NBEdge* const to, const NBNode::Crossing& crossing) const {
1693  return NBRequest::mustBrakeForCrossing(this, from, to, crossing);
1694 }
1695 
1696 
1697 bool
1698 NBNode::rightTurnConflict(const NBEdge* from, const NBEdge* to, int fromLane,
1699  const NBEdge* prohibitorFrom, const NBEdge* prohibitorTo, int prohibitorFromLane,
1700  bool lefthand) {
1701  if (from != prohibitorFrom) {
1702  return false;
1703  }
1704  if (from->isTurningDirectionAt(to)
1705  || prohibitorFrom->isTurningDirectionAt(prohibitorTo)) {
1706  // XXX should warn if there are any non-turning connections left of this
1707  return false;
1708  }
1709  // conflict if to is between prohibitorTo and from when going clockwise
1710  if (to->getStartAngle() == prohibitorTo->getStartAngle()) {
1711  // reduce rounding errors
1712  return false;
1713  }
1714  const LinkDirection d1 = from->getToNode()->getDirection(from, to);
1715  // must be a right turn to qualify as rightTurnConflict
1716  if (d1 == LINKDIR_STRAIGHT) {
1717  // no conflict for straight going connections
1718  // XXX actually this should check the main direction (which could also
1719  // be a turn)
1720  return false;
1721  } else {
1722  const LinkDirection d2 = prohibitorFrom->getToNode()->getDirection(prohibitorFrom, prohibitorTo);
1723  if (d1 == LINKDIR_LEFT || d1 == LINKDIR_PARTLEFT) {
1724  // check for leftTurnConflicht
1725  lefthand = !lefthand;
1726  if (d2 == LINKDIR_RIGHT || d1 == LINKDIR_PARTRIGHT) {
1727  // assume that the left-turning bicycle goes straight at first
1728  // and thus gets precedence over a right turning vehicle
1729  return false;
1730  }
1731  }
1732  if ((!lefthand && fromLane <= prohibitorFromLane) ||
1733  (lefthand && fromLane >= prohibitorFromLane)) {
1734  return false;
1735  }
1736  const double toAngleAtNode = fmod(to->getStartAngle() + 180, (double)360.0);
1737  const double prohibitorToAngleAtNode = fmod(prohibitorTo->getStartAngle() + 180, (double)360.0);
1738  return (lefthand != (GeomHelper::getCWAngleDiff(from->getEndAngle(), toAngleAtNode) <
1739  GeomHelper::getCWAngleDiff(from->getEndAngle(), prohibitorToAngleAtNode)));
1740  }
1741 }
1742 
1743 
1744 bool
1745 NBNode::turnFoes(const NBEdge* from, const NBEdge* to, int fromLane,
1746  const NBEdge* from2, const NBEdge* to2, int fromLane2,
1747  bool lefthand) const {
1748  UNUSED_PARAMETER(lefthand);
1749  if (from != from2 || to == to2 || fromLane == fromLane2) {
1750  return false;
1751  }
1752  if (from->isTurningDirectionAt(to)
1753  || from2->isTurningDirectionAt(to2)) {
1754  // XXX should warn if there are any non-turning connections left of this
1755  return false;
1756  }
1757  bool result = false;
1758  EdgeVector::const_iterator it = std::find(myAllEdges.begin(), myAllEdges.end(), from);
1759  if (fromLane < fromLane2) {
1760  // conflict if 'to' comes before 'to2' going clockwise starting at 'from'
1761  while (*it != to2) {
1762  if (*it == to) {
1763  result = true;
1764  }
1766  }
1767  } else {
1768  // conflict if 'to' comes before 'to2' going counter-clockwise starting at 'from'
1769  while (*it != to2) {
1770  if (*it == to) {
1771  result = true;
1772  }
1774  }
1775  }
1776  /*
1777  if (result) {
1778  std::cout << "turnFoes node=" << getID()
1779  << " from=" << from->getLaneID(fromLane)
1780  << " to=" << to->getID()
1781  << " from2=" << from2->getLaneID(fromLane2)
1782  << " to2=" << to2->getID()
1783  << "\n";
1784  }
1785  */
1786  return result;
1787 }
1788 
1789 
1790 bool
1791 NBNode::isLeftMover(const NBEdge* const from, const NBEdge* const to) const {
1792  // when the junction has only one incoming edge, there are no
1793  // problems caused by left blockings
1794  if (myIncomingEdges.size() == 1 || myOutgoingEdges.size() == 1) {
1795  return false;
1796  }
1797  double fromAngle = from->getAngleAtNode(this);
1798  double toAngle = to->getAngleAtNode(this);
1799  double cw = GeomHelper::getCWAngleDiff(fromAngle, toAngle);
1800  double ccw = GeomHelper::getCCWAngleDiff(fromAngle, toAngle);
1801  std::vector<NBEdge*>::const_iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), from);
1802  do {
1804  } while ((!hasOutgoing(*i) || from->isTurningDirectionAt(*i)) && *i != from);
1805  return cw < ccw && (*i) == to && myOutgoingEdges.size() > 2;
1806 }
1807 
1808 
1809 bool
1810 NBNode::forbids(const NBEdge* const possProhibitorFrom, const NBEdge* const possProhibitorTo,
1811  const NBEdge* const possProhibitedFrom, const NBEdge* const possProhibitedTo,
1812  bool regardNonSignalisedLowerPriority) const {
1813  return myRequest != nullptr && myRequest->forbids(possProhibitorFrom, possProhibitorTo,
1814  possProhibitedFrom, possProhibitedTo,
1815  regardNonSignalisedLowerPriority);
1816 }
1817 
1818 
1819 bool
1820 NBNode::foes(const NBEdge* const from1, const NBEdge* const to1,
1821  const NBEdge* const from2, const NBEdge* const to2) const {
1822  return myRequest != nullptr && myRequest->foes(from1, to1, from2, to2);
1823 }
1824 
1825 
1826 void
1828  NBEdge* removed, const EdgeVector& incoming,
1829  const EdgeVector& outgoing) {
1830  assert(find(incoming.begin(), incoming.end(), removed) == incoming.end());
1831  bool changed = true;
1832  while (changed) {
1833  changed = false;
1834  NBConnectionProhibits blockedConnectionsTmp = myBlockedConnections;
1835  NBConnectionProhibits blockedConnectionsNew;
1836  // remap in connections
1837  for (NBConnectionProhibits::iterator i = blockedConnectionsTmp.begin(); i != blockedConnectionsTmp.end(); i++) {
1838  const NBConnection& blocker = (*i).first;
1839  const NBConnectionVector& blocked = (*i).second;
1840  // check the blocked connections first
1841  // check whether any of the blocked must be changed
1842  bool blockedChanged = false;
1843  NBConnectionVector newBlocked;
1844  NBConnectionVector::const_iterator j;
1845  for (j = blocked.begin(); j != blocked.end(); j++) {
1846  const NBConnection& sblocked = *j;
1847  if (sblocked.getFrom() == removed || sblocked.getTo() == removed) {
1848  blockedChanged = true;
1849  }
1850  }
1851  // adapt changes if so
1852  for (j = blocked.begin(); blockedChanged && j != blocked.end(); j++) {
1853  const NBConnection& sblocked = *j;
1854  if (sblocked.getFrom() == removed && sblocked.getTo() == removed) {
1855  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1856  !!! newBlocked.push_back(NBConnection(*k, *k));
1857  }*/
1858  } else if (sblocked.getFrom() == removed) {
1859  assert(sblocked.getTo() != removed);
1860  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1861  newBlocked.push_back(NBConnection(*k, sblocked.getTo()));
1862  }
1863  } else if (sblocked.getTo() == removed) {
1864  assert(sblocked.getFrom() != removed);
1865  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1866  newBlocked.push_back(NBConnection(sblocked.getFrom(), *k));
1867  }
1868  } else {
1869  newBlocked.push_back(NBConnection(sblocked.getFrom(), sblocked.getTo()));
1870  }
1871  }
1872  if (blockedChanged) {
1873  blockedConnectionsNew[blocker] = newBlocked;
1874  changed = true;
1875  }
1876  // if the blocked were kept
1877  else {
1878  if (blocker.getFrom() == removed && blocker.getTo() == removed) {
1879  changed = true;
1880  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1881  !!! blockedConnectionsNew[NBConnection(*k, *k)] = blocked;
1882  }*/
1883  } else if (blocker.getFrom() == removed) {
1884  assert(blocker.getTo() != removed);
1885  changed = true;
1886  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1887  blockedConnectionsNew[NBConnection(*k, blocker.getTo())] = blocked;
1888  }
1889  } else if (blocker.getTo() == removed) {
1890  assert(blocker.getFrom() != removed);
1891  changed = true;
1892  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1893  blockedConnectionsNew[NBConnection(blocker.getFrom(), *k)] = blocked;
1894  }
1895  } else {
1896  blockedConnectionsNew[blocker] = blocked;
1897  }
1898  }
1899  }
1900  myBlockedConnections = blockedConnectionsNew;
1901  }
1902  // remap in traffic lights
1903  tc.remapRemoved(removed, incoming, outgoing);
1904 }
1905 
1906 
1907 NBEdge*
1908 NBNode::getNextCompatibleOutgoing(const NBEdge* incoming, SVCPermissions vehPerm, EdgeVector::const_iterator itOut, bool clockwise) const {
1909  EdgeVector::const_iterator i = itOut;
1910  while (*i != incoming) {
1911  if (clockwise) {
1913  } else {
1915  }
1916  if ((*i)->getFromNode() != this) {
1917  // only look for outgoing edges
1918  // @note we use myAllEdges to stop at the incoming edge
1919  continue;
1920  }
1921  if (incoming->isTurningDirectionAt(*i)) {
1922  return nullptr;
1923  }
1924  if ((vehPerm & (*i)->getPermissions()) != 0 || vehPerm == 0) {
1925  return *i;
1926  }
1927  }
1928  return nullptr;
1929 }
1930 
1931 
1933 NBNode::getDirection(const NBEdge* const incoming, const NBEdge* const outgoing, bool leftHand) const {
1934  // ok, no connection at all -> dead end
1935  if (outgoing == nullptr) {
1936  return LINKDIR_NODIR;
1937  }
1938  if (incoming->getJunctionPriority(this) == NBEdge::ROUNDABOUT && outgoing->getJunctionPriority(this) == NBEdge::ROUNDABOUT) {
1939  return LINKDIR_STRAIGHT;
1940  }
1941  // turning direction
1942  if (incoming->isTurningDirectionAt(outgoing)) {
1943  return leftHand ? LINKDIR_TURN_LEFTHAND : LINKDIR_TURN;
1944  }
1945  // get the angle between incoming/outgoing at the junction
1946  const double angle = NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outgoing->getAngleAtNode(this));
1947  // ok, should be a straight connection
1948  EdgeVector::const_iterator itOut = std::find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1949  SVCPermissions vehPerm = incoming->getPermissions() & outgoing->getPermissions();
1950  if (vehPerm != SVC_PEDESTRIAN) {
1951  vehPerm &= ~SVC_PEDESTRIAN;
1952  }
1953  if (abs((int) angle) + 1 < 45) {
1954  // check whether there is a straighter edge
1955  NBEdge* outCW = getNextCompatibleOutgoing(incoming, vehPerm, itOut, true);
1956  if (outCW != nullptr) {
1957  const double angle2 = NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outCW->getAngleAtNode(this));
1958  if (fabs(angle2) < fabs(angle)) {
1959  if (fabs(angle2 - angle) > 5) {
1960  if (angle2 > angle) {
1961  return LINKDIR_PARTLEFT;
1962  } else {
1963  return LINKDIR_PARTRIGHT;
1964  }
1965  }
1966  }
1967  }
1968  NBEdge* outCCW = getNextCompatibleOutgoing(incoming, vehPerm, itOut, false);
1969  if (outCCW != nullptr) {
1970  const double angle2 = NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outCCW->getAngleAtNode(this));
1971  if (fabs(angle2) < fabs(angle)) {
1972  if (fabs(angle2 - angle) > 5) {
1973  if (angle2 > angle) {
1974  return LINKDIR_PARTLEFT;
1975  } else {
1976  return LINKDIR_PARTRIGHT;
1977  }
1978  }
1979  }
1980  }
1981  return LINKDIR_STRAIGHT;
1982  }
1983 
1984  if (angle > 0) {
1985  // check whether any other edge goes further to the right
1986  if (angle > 90) {
1987  return LINKDIR_RIGHT;
1988  }
1989  NBEdge* outCW = getNextCompatibleOutgoing(incoming, vehPerm, itOut, !leftHand);
1990  if (outCW != nullptr) {
1991  return LINKDIR_PARTRIGHT;
1992  } else {
1993  return LINKDIR_RIGHT;
1994  }
1995  } else {
1996  // check whether any other edge goes further to the left
1997  if (angle < -90) {
1998  return LINKDIR_LEFT;
1999  }
2000  NBEdge* outCCW = getNextCompatibleOutgoing(incoming, vehPerm, itOut, leftHand);
2001  if (outCCW != nullptr) {
2002  return LINKDIR_PARTLEFT;
2003  } else {
2004  return LINKDIR_LEFT;
2005  }
2006  }
2007 }
2008 
2009 
2010 LinkState
2011 NBNode::getLinkState(const NBEdge* incoming, NBEdge* outgoing, int fromlane, int toLane,
2012  bool mayDefinitelyPass, const std::string& tlID) const {
2013  if (myType == NODETYPE_RAIL_CROSSING && isRailway(incoming->getPermissions())) {
2014  return LINKSTATE_MAJOR; // the trains must run on time
2015  }
2016  if (tlID != "") {
2017  return mustBrake(incoming, outgoing, fromlane, toLane, true) ? LINKSTATE_TL_OFF_BLINKING : LINKSTATE_TL_OFF_NOSIGNAL;
2018  }
2019  if (outgoing == nullptr) { // always off
2021  }
2023  return LINKSTATE_EQUAL; // all the same
2024  }
2025  if (myType == NODETYPE_ALLWAY_STOP) {
2026  return LINKSTATE_ALLWAY_STOP; // all drive, first one to arrive may drive first
2027  }
2028  if (myType == NODETYPE_ZIPPER && mustBrake(incoming, outgoing, fromlane, toLane, false)) {
2029  return LINKSTATE_ZIPPER;
2030  }
2031  if (!mayDefinitelyPass
2032  && mustBrake(incoming, outgoing, fromlane, toLane, true)
2033  // legacy mode
2034  && (!incoming->isInsideTLS() || getDirection(incoming, outgoing) != LINKDIR_STRAIGHT)
2035  // avoid linkstate minor at pure railway nodes
2036  && (incoming->getPriority() != outgoing->getPriority() || !NBNodeTypeComputer::isRailwayNode(this))) {
2037  return myType == NODETYPE_PRIORITY_STOP ? LINKSTATE_STOP : LINKSTATE_MINOR; // minor road
2038  }
2039  // traffic lights are not regarded here
2040  return LINKSTATE_MAJOR;
2041 }
2042 
2043 bool
2045  std::string reason;
2046  return checkIsRemovableReporting(reason);
2047 }
2048 
2049 bool
2050 NBNode::checkIsRemovableReporting(std::string& reason) const {
2051  // check whether this node is included in a traffic light or crossing
2052  if (myTrafficLights.size() != 0) {
2053  reason = "TLS";
2054  return false;
2055  }
2056  if (myType == NODETYPE_RAIL_SIGNAL) {
2057  reason = "rail_signal";
2058  return false;
2059  }
2060  if (myCrossings.size() != 0) {
2061  reason = "crossing";
2062  return false;
2063  }
2064  EdgeVector::const_iterator i;
2065  // one in, one out -> just a geometry ...
2066  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
2067  // ... if types match ...
2068  if (!myIncomingEdges[0]->expandableBy(myOutgoingEdges[0], reason)) {
2069  reason = "edges incompatible: " + reason;
2070  return false;
2071  }
2072  if (myIncomingEdges[0]->getTurnDestination(true) == myOutgoingEdges[0]) {
2073  reason = "turnaround";
2074  return false;
2075  }
2076  return true;
2077  }
2078  // two in, two out -> may be something else
2079  if (myOutgoingEdges.size() == 2 && myIncomingEdges.size() == 2) {
2080  // check whether the origin nodes of the incoming edges differ
2081  std::set<NBNode*> origSet;
2082  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
2083  origSet.insert((*i)->getFromNode());
2084  }
2085  if (origSet.size() < 2) {
2086  return false;
2087  }
2088  // check whether this node is an intermediate node of
2089  // a two-directional street
2090  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
2091  // each of the edges must have an opposite direction edge
2092  NBEdge* opposite = (*i)->getTurnDestination(true);
2093  if (opposite != nullptr) {
2094  // the other outgoing edges must be the continuation of the current
2095  NBEdge* continuation = opposite == myOutgoingEdges.front() ? myOutgoingEdges.back() : myOutgoingEdges.front();
2096  // check whether the types allow joining
2097  if (!(*i)->expandableBy(continuation, reason)) {
2098  reason = "edges incompatible: " + reason;
2099  return false;
2100  }
2101  } else {
2102  // ok, at least one outgoing edge is not an opposite
2103  // of an incoming one
2104  reason = "not opposites";
2105  return false;
2106  }
2107  }
2108  return true;
2109  }
2110  // ok, a real node
2111  reason = "intersection";
2112  return false;
2113 }
2114 
2115 
2116 std::vector<std::pair<NBEdge*, NBEdge*> >
2118  assert(checkIsRemovable());
2119  std::vector<std::pair<NBEdge*, NBEdge*> > ret;
2120  // one in, one out-case
2121  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
2122  ret.push_back(
2123  std::pair<NBEdge*, NBEdge*>(
2125  return ret;
2126  }
2127  // two in, two out-case
2128  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
2129  // join with the edge that is not a turning direction
2130  NBEdge* opposite = (*i)->getTurnDestination(true);
2131  assert(opposite != 0);
2132  NBEdge* continuation = opposite == myOutgoingEdges.front() ? myOutgoingEdges.back() : myOutgoingEdges.front();
2133  ret.push_back(std::pair<NBEdge*, NBEdge*>(*i, continuation));
2134  }
2135  return ret;
2136 }
2137 
2138 
2139 const PositionVector&
2141  return myPoly;
2142 }
2143 
2144 
2145 void
2147  myPoly = shape;
2148  myHaveCustomPoly = (myPoly.size() > 1);
2149  if (myHaveCustomPoly) {
2150  for (EdgeVector::iterator i = myAllEdges.begin(); i != myAllEdges.end(); i++) {
2151  (*i)->resetNodeBorder(this);
2152  }
2153  }
2154 }
2155 
2156 
2157 NBEdge*
2159  for (NBEdge* e : myOutgoingEdges) {
2160  if (e->getToNode() == n && e->getPermissions() != 0) {
2161  return e;
2162  }
2163  }
2164  return nullptr;
2165 }
2166 
2167 
2168 bool
2170  if (isDistrict()) {
2171  return false;
2172  }
2173  for (const NBEdge* const t : getEdges()) {
2174  const NBNode* const other = t->getToNode() == this ? t->getFromNode() : t->getToNode();
2175  for (const NBEdge* const k : other->getEdges()) {
2176  if (k->getFromNode()->isDistrict() || k->getToNode()->isDistrict()) {
2177  return true;
2178  }
2179  }
2180  }
2181  return false;
2182 }
2183 
2184 
2185 bool
2187  return myType == NODETYPE_DISTRICT;
2188 }
2189 
2190 
2191 int
2193 #ifdef DEBUG_PED_STRUCTURES
2195 #endif
2196  int numGuessed = 0;
2197  if (myCrossings.size() > 0 || myDiscardAllCrossings) {
2198  // user supplied crossings, do not guess
2199  return numGuessed;
2200  }
2201  if (gDebugFlag1) {
2202  std::cout << "guess crossings for " << getID() << "\n";
2203  }
2205  // check for pedestrial lanes going clockwise around the node
2206  std::vector<std::pair<NBEdge*, bool> > normalizedLanes;
2207  for (EdgeVector::const_iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
2208  NBEdge* edge = *it;
2209  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
2210  if (edge->getFromNode() == this) {
2211  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
2212  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
2213  }
2214  } else {
2215  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
2216  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
2217  }
2218  }
2219  }
2220  // do we even have a pedestrian lane?
2221  int firstSidewalk = -1;
2222  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
2223  if (normalizedLanes[i].second) {
2224  firstSidewalk = i;
2225  break;
2226  }
2227  }
2228  int hadCandidates = 0;
2229  std::vector<int> connectedCandidates; // number of crossings that were built for each connected candidate
2230  if (firstSidewalk != -1) {
2231  // rotate lanes to ensure that the first one allows pedestrians
2232  std::vector<std::pair<NBEdge*, bool> > tmp;
2233  copy(normalizedLanes.begin() + firstSidewalk, normalizedLanes.end(), std::back_inserter(tmp));
2234  copy(normalizedLanes.begin(), normalizedLanes.begin() + firstSidewalk, std::back_inserter(tmp));
2235  normalizedLanes = tmp;
2236  // find candidates
2237  EdgeVector candidates;
2238  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
2239  NBEdge* edge = normalizedLanes[i].first;
2240  const bool allowsPed = normalizedLanes[i].second;
2241  if (gDebugFlag1) {
2242  std::cout << " cands=" << toString(candidates) << " edge=" << edge->getID() << " allowsPed=" << allowsPed << "\n";
2243  }
2244  if (!allowsPed && (candidates.size() == 0 || candidates.back() != edge)) {
2245  candidates.push_back(edge);
2246  } else if (allowsPed) {
2247  if (candidates.size() > 0) {
2248  if (hadCandidates > 0 || forbidsPedestriansAfter(normalizedLanes, i)) {
2249  hadCandidates++;
2250  const int n = checkCrossing(candidates);
2251  numGuessed += n;
2252  if (n > 0) {
2253  connectedCandidates.push_back(n);
2254  }
2255  }
2256  candidates.clear();
2257  }
2258  }
2259  }
2260  if (hadCandidates > 0 && candidates.size() > 0) {
2261  // avoid wrapping around to the same sidewalk
2262  hadCandidates++;
2263  const int n = checkCrossing(candidates);
2264  numGuessed += n;
2265  if (n > 0) {
2266  connectedCandidates.push_back(n);
2267  }
2268  }
2269  }
2270  // Avoid duplicate crossing between the same pair of walkingareas
2271  if (gDebugFlag1) {
2272  std::cout << " hadCandidates=" << hadCandidates << " connectedCandidates=" << toString(connectedCandidates) << "\n";
2273  }
2274  if (hadCandidates == 2 && connectedCandidates.size() == 2) {
2275  // One or both of them might be split: remove the one with less splits
2276  if (connectedCandidates.back() <= connectedCandidates.front()) {
2277  numGuessed -= connectedCandidates.back();
2278  myCrossings.erase(myCrossings.end() - connectedCandidates.back(), myCrossings.end());
2279  } else {
2280  numGuessed -= connectedCandidates.front();
2281  myCrossings.erase(myCrossings.begin(), myCrossings.begin() + connectedCandidates.front());
2282  }
2283  }
2285  if (gDebugFlag1) {
2286  std::cout << "guessedCrossings:\n";
2287  for (auto crossing : myCrossings) {
2288  std::cout << " edges=" << toString(crossing->edges) << "\n";
2289  }
2290  }
2291  return numGuessed;
2292 }
2293 
2294 
2295 int
2297  if (gDebugFlag1) {
2298  std::cout << "checkCrossing candidates=" << toString(candidates) << "\n";
2299  }
2300  if (candidates.size() == 0) {
2301  if (gDebugFlag1) {
2302  std::cout << "no crossing added (numCandidates=" << candidates.size() << ")\n";
2303  }
2304  return 0;
2305  } else {
2306  // check whether the edges may be part of a common crossing due to having similar angle
2307  double prevAngle = -100000; // dummy
2308  for (int i = 0; i < (int)candidates.size(); ++i) {
2309  NBEdge* edge = candidates[i];
2310  double angle = edge->getCrossingAngle(this);
2311  // edges should be sorted by angle but this only holds true approximately
2312  if (i > 0 && fabs(NBHelpers::relAngle(angle, prevAngle)) > EXTEND_CROSSING_ANGLE_THRESHOLD) {
2313  if (gDebugFlag1) {
2314  std::cout << "no crossing added (found angle difference of " << fabs(NBHelpers::relAngle(angle, prevAngle)) << " at i=" << i << "\n";
2315  }
2316  return 0;
2317  }
2318  if (!isTLControlled() && myType != NODETYPE_RAIL_CROSSING && edge->getSpeed() > OptionsCont::getOptions().getFloat("crossings.guess.speed-threshold")) {
2319  if (gDebugFlag1) {
2320  std::cout << "no crossing added (uncontrolled, edge with speed > " << edge->getSpeed() << ")\n";
2321  }
2322  return 0;
2323  }
2324  prevAngle = angle;
2325  }
2326  if (candidates.size() == 1 || getType() == NODETYPE_RAIL_CROSSING) {
2328  if (gDebugFlag1) {
2329  std::cout << "adding crossing: " << toString(candidates) << "\n";
2330  }
2331  return 1;
2332  } else {
2333  // check for intermediate walking areas
2334  double prevAngle = -100000; // dummy
2335  for (EdgeVector::iterator it = candidates.begin(); it != candidates.end(); ++it) {
2336  double angle = (*it)->getCrossingAngle(this);
2337  if (it != candidates.begin()) {
2338  NBEdge* prev = *(it - 1);
2339  NBEdge* curr = *it;
2340  Position prevPos, currPos;
2341  int laneI;
2342  // compute distance between candiate edges
2343  double intermediateWidth = 0;
2344  if (prev->getToNode() == this) {
2345  laneI = prev->getNumLanes() - 1;
2346  prevPos = prev->getLanes()[laneI].shape[-1];
2347  } else {
2348  laneI = 0;
2349  prevPos = prev->getLanes()[laneI].shape[0];
2350  }
2351  intermediateWidth -= 0.5 * prev->getLaneWidth(laneI);
2352  if (curr->getFromNode() == this) {
2353  laneI = curr->getNumLanes() - 1;
2354  currPos = curr->getLanes()[laneI].shape[0];
2355  } else {
2356  laneI = 0;
2357  currPos = curr->getLanes()[laneI].shape[-1];
2358  }
2359  intermediateWidth -= 0.5 * curr->getLaneWidth(laneI);
2360  intermediateWidth += currPos.distanceTo2D(prevPos);
2361  if (gDebugFlag1) {
2362  std::cout
2363  << " prevAngle=" << prevAngle
2364  << " angle=" << angle
2365  << " intermediateWidth=" << intermediateWidth
2366  << "\n";
2367  }
2368  if (fabs(NBHelpers::relAngle(prevAngle, angle)) > SPLIT_CROSSING_ANGLE_THRESHOLD
2369  || (intermediateWidth > SPLIT_CROSSING_WIDTH_THRESHOLD)) {
2370  return checkCrossing(EdgeVector(candidates.begin(), it))
2371  + checkCrossing(EdgeVector(it, candidates.end()));
2372  }
2373  }
2374  prevAngle = angle;
2375  }
2377  if (gDebugFlag1) {
2378  std::cout << "adding crossing: " << toString(candidates) << "\n";
2379  }
2380  return 1;
2381  }
2382  }
2383 }
2384 
2385 
2386 bool
2388  // sort edge vector
2389  std::sort(edges.begin(), edges.end());
2390  // iterate over crossing to find a crossing with the same edges
2391  for (auto crossing : myCrossings) {
2392  // sort edges of crossing before compare
2393  EdgeVector edgesOfCrossing = crossing->edges;
2394  std::sort(edgesOfCrossing.begin(), edgesOfCrossing.end());
2395  if (edgesOfCrossing == edges) {
2396  return true;
2397  }
2398  }
2399  return false;
2400 }
2401 
2402 
2403 bool
2404 NBNode::forbidsPedestriansAfter(std::vector<std::pair<NBEdge*, bool> > normalizedLanes, int startIndex) {
2405  for (int i = startIndex; i < (int)normalizedLanes.size(); ++i) {
2406  if (!normalizedLanes[i].second) {
2407  return true;
2408  }
2409  }
2410  return false;
2411 }
2412 
2413 
2414 void
2416  buildCrossings();
2417  buildWalkingAreas(OptionsCont::getOptions().getInt("junctions.corner-detail"));
2418  // ensure that all crossings are properly connected
2419  for (auto crossing : myCrossings) {
2420  if (crossing->prevWalkingArea == "" || crossing->nextWalkingArea == "" || !crossing->valid) {
2421  if (crossing->valid) {
2422  WRITE_WARNINGF("Discarding invalid crossing '%' at junction '%' with edges [%] (no walkingarea found).",
2423  crossing->id, getID(), toString(crossing->edges));
2424  }
2425  for (WalkingArea& wa : myWalkingAreas) {
2426  std::vector<std::string>::iterator it_nc = std::find(wa.nextCrossings.begin(), wa.nextCrossings.end(), crossing->id);
2427  if (it_nc != wa.nextCrossings.end()) {
2428  wa.nextCrossings.erase(it_nc);
2429  }
2430  }
2431  crossing->valid = false;
2432  crossing->prevWalkingArea = "";
2433  crossing->nextWalkingArea = "";
2434  }
2435  }
2436 }
2437 
2438 std::vector<NBNode::Crossing*>
2440  std::vector<Crossing*> result;
2441  for (Crossing* const c : myCrossings) {
2442  if (c->valid) {
2443  result.push_back(c);
2444  }
2445  }
2446  //if (myCrossings.size() > 0) {
2447  // std::cout << "valid crossings at " << getID() << "\n";
2448  // for (std::vector<NBNode::Crossing*>::const_iterator it = result.begin(); it != result.end(); ++it) {
2449  // std::cout << " " << toString((*it)->edges) << "\n";
2450  // }
2451  //}
2452  return result;
2453 }
2454 
2455 
2456 void
2458  for (auto c : myCrossings) {
2459  delete c;
2460  }
2461  myCrossings.clear();
2462  // also discard all further crossings
2463  if (rejectAll) {
2464  myDiscardAllCrossings = true;
2465  }
2466 }
2467 
2468 
2469 void
2471  myWalkingAreas.clear();
2472 }
2473 
2474 
2475 void
2477  // myDisplacementError is computed during this operation. reset first
2478  myDisplacementError = 0;
2479  // build inner edges for vehicle movements across the junction
2480  int noInternalNoSplits = 0;
2481  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
2482  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
2483  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
2484  if ((*k).toEdge == nullptr) {
2485  continue;
2486  }
2487  noInternalNoSplits++;
2488  }
2489  }
2490  int lno = 0;
2491  int splitNo = 0;
2492  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
2493  (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
2494  }
2495 }
2496 
2497 
2498 int
2500 #ifdef DEBUG_PED_STRUCTURES
2502 #endif
2503  if (gDebugFlag1) {
2504  std::cout << "build crossings for " << getID() << ":\n";
2505  }
2506  if (myDiscardAllCrossings) {
2507  myCrossings.clear();
2508  }
2509  int index = 0;
2510  const double defaultWidth = OptionsCont::getOptions().getFloat("default.crossing-width");
2511  for (auto c : myCrossings) {
2512  c->valid = true;
2513  if (!isTLControlled()) {
2514  c->tlID = ""; // reset for Netedit, set via setCrossingTLIndices()
2515  }
2516  c->id = ":" + getID() + "_c" + toString(index++);
2517  c->width = (c->customWidth == NBEdge::UNSPECIFIED_WIDTH) ? defaultWidth : c->customWidth;
2518  // reset fields, so repeated computation (Netedit) will sucessfully perform the checks
2519  // in buildWalkingAreas (split crossings) and buildInnerEdges (sanity check)
2520  c->nextWalkingArea = "";
2521  c->prevWalkingArea = "";
2522  EdgeVector& edges = c->edges;
2523  if (gDebugFlag1) {
2524  std::cout << " crossing=" << c->id << " edges=" << toString(edges);
2525  }
2526  // sorting the edges in the right way is imperative. We want to sort
2527  // them by getAngleAtNodeToCenter() but need to be extra carefull to avoid wrapping around 0 somewhere in between
2528  std::sort(edges.begin(), edges.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
2529  if (gDebugFlag1) {
2530  std::cout << " sortedEdges=" << toString(edges) << "\n";
2531  };
2532  // rotate the edges so that the largest relative angle difference comes at the end
2533  double maxAngleDiff = 0;
2534  int maxAngleDiffIndex = 0; // index before maxDist
2535  for (int i = 0; i < (int) edges.size(); i++) {
2536  double diff = NBHelpers::relAngle(edges[i]->getAngleAtNodeToCenter(this),
2537  edges[(i + 1) % edges.size()]->getAngleAtNodeToCenter(this));
2538  if (diff < 0) {
2539  diff += 360;
2540  }
2541  if (gDebugFlag1) {
2542  std::cout << " i=" << i << " a1=" << edges[i]->getAngleAtNodeToCenter(this) << " a2=" << edges[(i + 1) % edges.size()]->getAngleAtNodeToCenter(this) << " diff=" << diff << "\n";
2543  }
2544  if (diff > maxAngleDiff) {
2545  maxAngleDiff = diff;
2546  maxAngleDiffIndex = i;
2547  }
2548  }
2549  if (maxAngleDiff > 2 && maxAngleDiff < 360 - 2) {
2550  // if the angle differences is too small, we better not rotate
2551  std::rotate(edges.begin(), edges.begin() + (maxAngleDiffIndex + 1) % edges.size(), edges.end());
2552  if (gDebugFlag1) {
2553  std::cout << " rotatedEdges=" << toString(edges);
2554  }
2555  }
2556  // reverse to get them in CCW order (walking direction around the node)
2557  std::reverse(edges.begin(), edges.end());
2558  if (gDebugFlag1) {
2559  std::cout << " finalEdges=" << toString(edges) << "\n";
2560  }
2561  // compute shape
2562  c->shape.clear();
2563  const int begDir = (edges.front()->getFromNode() == this ? FORWARD : BACKWARD);
2564  const int endDir = (edges.back()->getToNode() == this ? FORWARD : BACKWARD);
2565  if (edges.front()->getFirstNonPedestrianLaneIndex(begDir) < 0
2566  || edges.back()->getFirstNonPedestrianLaneIndex(endDir) < 0) {
2567  // invalid crossing
2568  WRITE_WARNINGF("Discarding invalid crossing '%' at junction '%' with edges [%] (no vehicle lanes to cross).", c->id, getID(), toString(c->edges));
2569  c->valid = false;
2570  } else if (c->customShape.size() != 0) {
2571  c->shape = c->customShape;
2572  } else {
2573  NBEdge::Lane crossingBeg = edges.front()->getFirstNonPedestrianLane(begDir);
2574  NBEdge::Lane crossingEnd = edges.back()->getFirstNonPedestrianLane(endDir);
2575  crossingBeg.width = (crossingBeg.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingBeg.width);
2576  crossingEnd.width = (crossingEnd.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingEnd.width);
2577  crossingBeg.shape.move2side(begDir * crossingBeg.width / 2);
2578  crossingEnd.shape.move2side(endDir * crossingEnd.width / 2);
2579  crossingBeg.shape.extrapolate(c->width / 2);
2580  crossingEnd.shape.extrapolate(c->width / 2);
2581  // check if after all changes shape are NAN (in these case, discard)
2582  if (crossingBeg.shape.isNAN() || crossingEnd.shape.isNAN()) {
2583  WRITE_WARNINGF("Discarding invalid crossing '%' at junction '%' with edges [%] (invalid shape).", c->id, getID(), toString(c->edges));
2584  c->valid = false;
2585  } else {
2586  c->shape.push_back(crossingBeg.shape[begDir == FORWARD ? 0 : -1]);
2587  c->shape.push_back(crossingEnd.shape[endDir == FORWARD ? -1 : 0]);
2588  }
2589  }
2590  }
2591  return index;
2592 }
2593 
2594 
2595 void
2596 NBNode::buildWalkingAreas(int cornerDetail) {
2597 #ifdef DEBUG_PED_STRUCTURES
2599 #endif
2600  int index = 0;
2601  myWalkingAreas.clear();
2602  if (gDebugFlag1) {
2603  std::cout << "build walkingAreas for " << getID() << ":\n";
2604  }
2605  if (myAllEdges.size() == 0) {
2606  return;
2607  }
2609  // shapes are all pointing away from the intersection
2610  std::vector<std::pair<NBEdge*, NBEdge::Lane> > normalizedLanes;
2611  for (EdgeVector::const_iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
2612  NBEdge* edge = *it;
2613  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
2614  if (edge->getFromNode() == this) {
2615  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
2616  NBEdge::Lane l = *it_l;
2617  l.shape = l.shape.getSubpartByIndex(0, 2);
2619  normalizedLanes.push_back(std::make_pair(edge, l));
2620  }
2621  } else {
2622  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
2623  NBEdge::Lane l = *it_l;
2624  l.shape = l.shape.reverse();
2625  l.shape = l.shape.getSubpartByIndex(0, 2);
2627  normalizedLanes.push_back(std::make_pair(edge, l));
2628  }
2629  }
2630  }
2631  //if (gDebugFlag1) std::cout << " normalizedLanes=" << normalizedLanes.size() << "\n";
2632  // collect [start,count[ indices in normalizedLanes that belong to a walkingArea
2633  std::vector<std::pair<int, int> > waIndices;
2634  int start = -1;
2635  NBEdge* prevEdge = normalizedLanes.back().first;
2636  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
2637  NBEdge* edge = normalizedLanes[i].first;
2638  NBEdge::Lane& l = normalizedLanes[i].second;
2639  if (start == -1) {
2640  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
2641  start = i;
2642  }
2643  } else {
2644  if ((l.permissions & SVC_PEDESTRIAN) == 0 || crossingBetween(edge, prevEdge)) {
2645  waIndices.push_back(std::make_pair(start, i - start));
2646  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
2647  start = i;
2648  } else {
2649  start = -1;
2650  }
2651 
2652  }
2653  }
2654  if (gDebugFlag1) std::cout << " i=" << i << " edge=" << edge->getID() << " start=" << start << " ped=" << ((l.permissions & SVC_PEDESTRIAN) != 0)
2655  << " waI=" << waIndices.size() << " crossingBetween=" << crossingBetween(edge, prevEdge) << "\n";
2656  prevEdge = edge;
2657  }
2658  // deal with wrap-around issues
2659  if (start != - 1) {
2660  const int waNumLanes = (int)normalizedLanes.size() - start;
2661  if (waIndices.size() == 0) {
2662  waIndices.push_back(std::make_pair(start, waNumLanes));
2663  if (gDebugFlag1) {
2664  std::cout << " single wa, end at wrap-around\n";
2665  }
2666  } else {
2667  if (waIndices.front().first == 0) {
2668  NBEdge* edge = normalizedLanes.front().first;
2669  NBEdge* prevEdge = normalizedLanes.back().first;
2670  if (crossingBetween(edge, prevEdge)) {
2671  // do not wrap-around if there is a crossing in between
2672  waIndices.push_back(std::make_pair(start, waNumLanes));
2673  if (gDebugFlag1) {
2674  std::cout << " do not wrap around, turn-around in between\n";
2675  }
2676  } else {
2677  // first walkingArea wraps around
2678  waIndices.front().first = start;
2679  waIndices.front().second = waNumLanes + waIndices.front().second;
2680  if (gDebugFlag1) {
2681  std::cout << " wrapping around\n";
2682  }
2683  }
2684  } else {
2685  // last walkingArea ends at the wrap-around
2686  waIndices.push_back(std::make_pair(start, waNumLanes));
2687  if (gDebugFlag1) {
2688  std::cout << " end at wrap-around\n";
2689  }
2690  }
2691  }
2692  }
2693  if (gDebugFlag1) {
2694  std::cout << " normalizedLanes=" << normalizedLanes.size() << " waIndices:\n";
2695  for (int i = 0; i < (int)waIndices.size(); ++i) {
2696  std::cout << " " << waIndices[i].first << ", " << waIndices[i].second << "\n";
2697  }
2698  }
2699  // build walking areas connected to a sidewalk
2700  for (int i = 0; i < (int)waIndices.size(); ++i) {
2701  const bool buildExtensions = waIndices[i].second != (int)normalizedLanes.size();
2702  const int start = waIndices[i].first;
2703  const int prev = start > 0 ? start - 1 : (int)normalizedLanes.size() - 1;
2704  const int count = waIndices[i].second;
2705  const int end = (start + count) % normalizedLanes.size();
2706 
2707  WalkingArea wa(":" + getID() + "_w" + toString(index++), 1);
2708  if (gDebugFlag1) {
2709  std::cout << "build walkingArea " << wa.id << " start=" << start << " end=" << end << " count=" << count << " prev=" << prev << ":\n";
2710  }
2711  double endCrossingWidth = 0;
2712  double startCrossingWidth = 0;
2713  PositionVector endCrossingShape;
2714  PositionVector startCrossingShape;
2715  // check for connected crossings
2716  bool connectsCrossing = false;
2717  std::vector<Position> connectedPoints;
2718  for (auto c : getCrossings()) {
2719  if (gDebugFlag1) {
2720  std::cout << " crossing=" << c->id << " sortedEdges=" << toString(c->edges) << "\n";
2721  }
2722  if (c->edges.back() == normalizedLanes[end].first
2723  && (normalizedLanes[end].second.permissions & SVC_PEDESTRIAN) == 0) {
2724  // crossing ends
2725  if (c->nextWalkingArea != "") {
2726  WRITE_WARNINGF("Invalid pedestrian topology at junction '%'; crossing '%' targets '%' and '%'.",
2727  getID(), c->id, c->nextWalkingArea, wa.id);
2728  c->valid = false;
2729  }
2730  c->nextWalkingArea = wa.id;
2731  if ((int)c->edges.size() < wa.minPrevCrossingEdges) {
2732  // if there are multiple crossings, use the shape of the one that crosses fewer edges
2733  endCrossingWidth = c->width;
2734  endCrossingShape = c->shape;
2735  wa.width = MAX2(wa.width, endCrossingWidth);
2736  connectsCrossing = true;
2737  connectedPoints.push_back(c->shape[-1]);
2738  wa.minPrevCrossingEdges = (int)c->edges.size();
2739  }
2740  if (gDebugFlag1) {
2741  std::cout << " crossing " << c->id << " ends\n";
2742  }
2743  }
2744  if (c->edges.front() == normalizedLanes[prev].first
2745  && (normalizedLanes[prev].second.permissions & SVC_PEDESTRIAN) == 0) {
2746  // crossing starts
2747  if (c->prevWalkingArea != "") {
2748  WRITE_WARNINGF("Invalid pedestrian topology at junction '%'; crossing '%' is targeted by '%' and '%'.",
2749  getID(), c->id, c->prevWalkingArea, wa.id);
2750  c->valid = false;
2751  }
2752  c->prevWalkingArea = wa.id;
2753  wa.nextCrossings.push_back(c->id);
2754  if ((int)c->edges.size() < wa.minNextCrossingEdges) {
2755  // if there are multiple crossings, use the shape of the one that crosses fewer edges
2756  startCrossingWidth = c->width;
2757  startCrossingShape = c->shape;
2758  wa.width = MAX2(wa.width, startCrossingWidth);
2759  connectsCrossing = true;
2760  connectedPoints.push_back(c->shape[0]);
2761  wa.minNextCrossingEdges = (int)c->edges.size();
2762  }
2763  if (gDebugFlag1) {
2764  std::cout << " crossing " << c->id << " starts\n";
2765  }
2766  }
2767  if (gDebugFlag1) std::cout << " check connections to crossing " << c->id
2768  << " cFront=" << c->edges.front()->getID() << " cBack=" << c->edges.back()->getID()
2769  << " wEnd=" << normalizedLanes[end].first->getID() << " wStart=" << normalizedLanes[start].first->getID()
2770  << " wStartPrev=" << normalizedLanes[prev].first->getID()
2771  << "\n";
2772  }
2773  if (count < 2 && !connectsCrossing) {
2774  // not relevant for walking
2775  if (gDebugFlag1) {
2776  std::cout << " not relevant for walking: count=" << count << " connectsCrossing=" << connectsCrossing << "\n";
2777  }
2778  continue;
2779  }
2780  // build shape and connections
2781  std::set<NBEdge*, ComparatorIdLess> connected;
2782  for (int j = 0; j < count; ++j) {
2783  const int nlI = (start + j) % normalizedLanes.size();
2784  NBEdge* edge = normalizedLanes[nlI].first;
2785  NBEdge::Lane l = normalizedLanes[nlI].second;
2786  wa.width = MAX2(wa.width, l.width);
2787  if (connected.count(edge) == 0) {
2788  if (edge->getFromNode() == this) {
2789  wa.nextSidewalks.push_back(edge->getSidewalkID());
2790  connectedPoints.push_back(edge->getLaneShape(0)[0]);
2791  } else {
2792  wa.prevSidewalks.push_back(edge->getSidewalkID());
2793  connectedPoints.push_back(edge->getLaneShape(0)[-1]);
2794  }
2795  connected.insert(edge);
2796  }
2797  l.shape.move2side(-l.width / 2);
2798  wa.shape.push_back(l.shape[0]);
2799  l.shape.move2side(l.width);
2800  wa.shape.push_back(l.shape[0]);
2801  }
2802  if (buildExtensions) {
2803  // extension at starting crossing
2804  if (startCrossingShape.size() > 0) {
2805  if (gDebugFlag1) {
2806  std::cout << " extension at startCrossing shape=" << startCrossingShape << "\n";
2807  }
2808  startCrossingShape.move2side(startCrossingWidth / 2);
2809  wa.shape.push_front_noDoublePos(startCrossingShape[0]); // right corner
2810  startCrossingShape.move2side(-startCrossingWidth);
2811  wa.shape.push_front_noDoublePos(startCrossingShape[0]); // left corner goes first
2812  }
2813  // extension at ending crossing
2814  if (endCrossingShape.size() > 0) {
2815  if (gDebugFlag1) {
2816  std::cout << " extension at endCrossing shape=" << endCrossingShape << "\n";
2817  }
2818  endCrossingShape.move2side(endCrossingWidth / 2);
2819  wa.shape.push_back_noDoublePos(endCrossingShape[-1]);
2820  endCrossingShape.move2side(-endCrossingWidth);
2821  wa.shape.push_back_noDoublePos(endCrossingShape[-1]);
2822  }
2823  }
2824  if (connected.size() == 2 && !connectsCrossing && wa.nextSidewalks.size() == 1 && wa.prevSidewalks.size() == 1
2825  && normalizedLanes.size() == 2) {
2826  // do not build a walkingArea since a normal connection exists
2827  NBEdge* e1 = *connected.begin();
2828  NBEdge* e2 = *(++connected.begin());
2829  if (e1->hasConnectionTo(e2, 0, 0) || e2->hasConnectionTo(e1, 0, 0)) {
2830  if (gDebugFlag1) {
2831  std::cout << " not building a walkingarea since normal connections exist\n";
2832  }
2833  continue;
2834  }
2835  }
2836  // build smooth inner curve (optional)
2837  if (cornerDetail > 0) {
2838  int smoothEnd = end;
2839  int smoothPrev = prev;
2840  // extend to green verge
2841  if (endCrossingWidth > 0 && normalizedLanes[smoothEnd].second.permissions == 0) {
2842  smoothEnd = (smoothEnd + 1) % normalizedLanes.size();
2843  }
2844  if (startCrossingWidth > 0 && normalizedLanes[smoothPrev].second.permissions == 0) {
2845  if (smoothPrev == 0) {
2846  smoothPrev = (int)normalizedLanes.size() - 1;
2847  } else {
2848  smoothPrev--;
2849  }
2850  }
2851  PositionVector begShape = normalizedLanes[smoothEnd].second.shape;
2852  begShape = begShape.reverse();
2853  //begShape.extrapolate(endCrossingWidth);
2854  begShape.move2side(normalizedLanes[smoothEnd].second.width / 2);
2855  PositionVector endShape = normalizedLanes[smoothPrev].second.shape;
2856  endShape.move2side(normalizedLanes[smoothPrev].second.width / 2);
2857  //endShape.extrapolate(startCrossingWidth);
2858  PositionVector curve;
2859  if ((normalizedLanes[smoothEnd].first->getPermissions() & normalizedLanes[smoothPrev].first->getPermissions() &
2860  ~(SVC_PEDESTRIAN | SVC_RAIL_CLASSES)) != 0) {
2861  curve = computeSmoothShape(begShape, endShape, cornerDetail + 2, false, 25, 25);
2862  } else {
2863  const double extend = MIN2(10.0, begShape.back().distanceTo2D(endShape.front()) / 2);
2864  curve = computeSmoothShape(begShape, endShape, cornerDetail + 2, false, extend, extend, nullptr, FOUR_CONTROL_POINTS);
2865  }
2866  if (gDebugFlag1) std::cout
2867  << " end=" << smoothEnd << " prev=" << smoothPrev
2868  << " endCrossingWidth=" << endCrossingWidth << " startCrossingWidth=" << startCrossingWidth
2869  << " begShape=" << begShape << " endShape=" << endShape << " smooth curve=" << curve << "\n";
2870  if (curve.size() > 2) {
2871  curve.erase(curve.begin());
2872  curve.pop_back();
2873  if (endCrossingWidth > 0) {
2874  wa.shape.pop_back();
2875  }
2876  if (startCrossingWidth > 0) {
2877  wa.shape.erase(wa.shape.begin());
2878  }
2879  wa.shape.append(curve, 0);
2880  }
2881  }
2882  // apply custom shapes
2883  if (myWalkingAreaCustomShapes.size() > 0) {
2884  for (auto wacs : myWalkingAreaCustomShapes) {
2885  // every edge in wasc.edges must be part of connected
2886  if (wacs.shape.size() != 0 && includes(connected, wacs.edges)) {
2887  wa.shape = wacs.shape;
2888  wa.hasCustomShape = true;
2889  }
2890  }
2891  }
2892  // determine length (average of all possible connections)
2893  double lengthSum = 0;
2894  int combinations = 0;
2895  for (std::vector<Position>::const_iterator it1 = connectedPoints.begin(); it1 != connectedPoints.end(); ++it1) {
2896  for (std::vector<Position>::const_iterator it2 = connectedPoints.begin(); it2 != connectedPoints.end(); ++it2) {
2897  const Position& p1 = *it1;
2898  const Position& p2 = *it2;
2899  if (p1 != p2) {
2900  lengthSum += p1.distanceTo2D(p2);
2901  combinations += 1;
2902  }
2903  }
2904  }
2905  if (gDebugFlag1) {
2906  std::cout << " combinations=" << combinations << " connectedPoints=" << connectedPoints << "\n";
2907  }
2908  wa.length = POSITION_EPS;
2909  if (combinations > 0) {
2910  wa.length = MAX2(POSITION_EPS, lengthSum / combinations);
2911  }
2912  myWalkingAreas.push_back(wa);
2913  }
2914  // build walkingAreas between split crossings
2915  std::vector<Crossing*> validCrossings = getCrossings();
2916  for (std::vector<Crossing*>::iterator it = validCrossings.begin(); it != validCrossings.end(); ++it) {
2917  Crossing& prev = **it;
2918  Crossing& next = (it != validCrossings.begin() ? **(it - 1) :** (validCrossings.end() - 1));
2919  if (gDebugFlag1) {
2920  std::cout << " checkIntermediate: prev=" << prev.id << " next=" << next.id << " prev.nextWA=" << prev.nextWalkingArea << "\n";
2921  }
2922  if (prev.nextWalkingArea == "") {
2923  if (next.prevWalkingArea != "" || &prev == &next) {
2924  WRITE_WARNINGF("Invalid pedestrian topology: crossing '%' across [%] has no target.", prev.id, toString(prev.edges));
2925  prev.valid = false;
2926  continue;
2927  }
2928  WalkingArea wa(":" + getID() + "_w" + toString(index++), prev.width);
2929  prev.nextWalkingArea = wa.id;
2930  wa.nextCrossings.push_back(next.id);
2931  next.prevWalkingArea = wa.id;
2932  // back of previous crossing
2933  PositionVector tmp = prev.shape;
2934  tmp.move2side(-prev.width / 2);
2935  wa.shape.push_back(tmp[-1]);
2936  tmp.move2side(prev.width);
2937  wa.shape.push_back(tmp[-1]);
2938  // front of next crossing
2939  tmp = next.shape;
2940  tmp.move2side(prev.width / 2);
2941  wa.shape.push_back(tmp[0]);
2942  tmp.move2side(-prev.width);
2943  wa.shape.push_back(tmp[0]);
2944  // apply custom shapes
2945  if (myWalkingAreaCustomShapes.size() > 0) {
2946  std::set<NBEdge*, ComparatorIdLess> crossed(prev.edges.begin(), prev.edges.end());
2947  crossed.insert(next.edges.begin(), next.edges.end());
2948  for (auto wacs : myWalkingAreaCustomShapes) {
2949  // every edge in wacs.edges must be part of crossed
2950  if (wacs.shape.size() != 0 && wacs.edges.size() > 1 && includes(crossed, wacs.edges)) {
2951  wa.shape = wacs.shape;
2952  wa.hasCustomShape = true;
2953  }
2954  }
2955  }
2956  // length (special case)
2957  wa.length = MAX2(POSITION_EPS, prev.shape.back().distanceTo2D(next.shape.front()));
2958  myWalkingAreas.push_back(wa);
2959  if (gDebugFlag1) {
2960  std::cout << " build wa=" << wa.id << "\n";
2961  }
2962  }
2963  }
2964 }
2965 
2966 bool
2967 NBNode::includes(const std::set<NBEdge*, ComparatorIdLess>& super,
2968  const std::set<const NBEdge*, ComparatorIdLess>& sub) {
2969  // for some reason std::include does not work reliably
2970  for (const NBEdge* e : sub) {
2971  if (super.count(const_cast<NBEdge*>(e)) == 0) {
2972  return false;
2973  }
2974  }
2975  return true;
2976 }
2977 
2978 
2979 bool
2980 NBNode::crossingBetween(const NBEdge* e1, const NBEdge* e2) const {
2981  if (e1 == e2) {
2982  return false;
2983  }
2984  if (myAllEdges.size() > 3) {
2985  // pedestrian scramble
2986  return false;
2987  }
2988  for (auto c : getCrossings()) {
2989  const EdgeVector& edges = c->edges;
2990  EdgeVector::const_iterator it1 = std::find(edges.begin(), edges.end(), e1);
2991  EdgeVector::const_iterator it2 = std::find(edges.begin(), edges.end(), e2);
2992  if (it1 != edges.end() && it2 != edges.end()) {
2993  return true;
2994  }
2995  }
2996  return false;
2997 }
2998 
2999 
3000 EdgeVector
3001 NBNode::edgesBetween(const NBEdge* e1, const NBEdge* e2) const {
3002  EdgeVector result;
3003  EdgeVector::const_iterator it = std::find(myAllEdges.begin(), myAllEdges.end(), e1);
3004  assert(it != myAllEdges.end());
3006  EdgeVector::const_iterator it_end = std::find(myAllEdges.begin(), myAllEdges.end(), e2);
3007  assert(it_end != myAllEdges.end());
3008  while (it != it_end) {
3009  result.push_back(*it);
3011  }
3012  return result;
3013 }
3014 
3015 
3016 void
3019  wacs.edges.insert(edges.begin(), edges.end());
3020  wacs.shape = shape;
3021  myWalkingAreaCustomShapes.push_back(wacs);
3022 }
3023 
3024 
3025 bool
3028 }
3029 
3030 bool
3031 NBNode::geometryLike(const EdgeVector& incoming, const EdgeVector& outgoing) const {
3032  if (incoming.size() == 1 && outgoing.size() == 1) {
3033  return true;
3034  }
3035  if (incoming.size() == 2 && outgoing.size() == 2) {
3036  // check whether the incoming and outgoing edges are pairwise (near) parallel and
3037  // thus the only cross-connections could be turn-arounds
3038  NBEdge* in0 = incoming[0];
3039  NBEdge* in1 = incoming[1];
3040  NBEdge* out0 = outgoing[0];
3041  NBEdge* out1 = outgoing[1];
3042  if ((in0->isTurningDirectionAt(out0) || in0->isTurningDirectionAt(out1))
3043  && (in1->isTurningDirectionAt(out0) || in1->isTurningDirectionAt(out1))) {
3044  return true;
3045  }
3046  for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
3047  NBEdge* inEdge = *it;
3048  double angle0 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out0->getAngleAtNode(this)));
3049  double angle1 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out1->getAngleAtNode(this)));
3050  if (MAX2(angle0, angle1) <= 160) {
3051  // neither of the outgoing edges is parallel to inEdge
3052  return false;
3053  }
3054  }
3055  return true;
3056  }
3057  return false;
3058 }
3059 
3060 void
3064  }
3065 }
3066 
3067 
3069 NBNode::addCrossing(EdgeVector edges, double width, bool priority, int tlIndex, int tlIndex2,
3070  const PositionVector& customShape, bool fromSumoNet) {
3071  Crossing* c = new Crossing(this, edges, width, priority, tlIndex, tlIndex2, customShape);
3072  myCrossings.push_back(c);
3073  if (fromSumoNet) {
3075  }
3076  return c;
3077 }
3078 
3079 
3080 void
3082  EdgeSet edgeSet(edges.begin(), edges.end());
3083  for (std::vector<Crossing*>::iterator it = myCrossings.begin(); it != myCrossings.end();) {
3084  EdgeSet edgeSet2((*it)->edges.begin(), (*it)->edges.end());
3085  if (edgeSet == edgeSet2) {
3086  delete *it;
3087  it = myCrossings.erase(it);
3088  } else {
3089  ++it;
3090  }
3091  }
3092 }
3093 
3094 
3096 NBNode::getCrossing(const std::string& id) const {
3097  for (auto c : myCrossings) {
3098  if (c->id == id) {
3099  return c;
3100  }
3101  }
3102  throw ProcessError("Request for unknown crossing '" + id + "'");
3103 }
3104 
3105 
3107 NBNode::getCrossing(const EdgeVector& edges, bool hardFail) const {
3108  EdgeSet edgeSet(edges.begin(), edges.end());
3109  for (auto it : myCrossings) {
3110  EdgeSet edgeSet2(it->edges.begin(), it->edges.end());
3111  if (edgeSet == edgeSet2) {
3112  return it;
3113  }
3114  }
3115  if (!hardFail) {
3116  return nullptr;
3117  } else {
3118  throw ProcessError("Request for unknown crossing for the given Edges");
3119  }
3120 }
3121 
3122 
3123 bool
3124 NBNode::setCrossingTLIndices(const std::string& tlID, int startIndex) {
3125  bool usedCustom = false;
3126  for (auto c : getCrossings()) {
3127  c->tlLinkIndex = startIndex++;
3128  c->tlID = tlID;
3129  if (c->customTLIndex != -1) {
3130  usedCustom |= (c->tlLinkIndex != c->customTLIndex);
3131  c->tlLinkIndex = c->customTLIndex;
3132  }
3133  c->tlLinkIndex2 = c->customTLIndex2;
3134  }
3135  return usedCustom;
3136 }
3137 
3138 
3139 int
3141  if (myRequest == nullptr) {
3142  // could be an uncontrolled type
3143  int result = 0;
3144  for (const NBEdge* const edge : myIncomingEdges) {
3145  result += (int)edge->getConnections().size();
3146  }
3147  return result;
3148  } else {
3149  return myRequest->getSizes().second;
3150  }
3151 }
3152 
3153 
3154 int
3155 NBNode::getConnectionIndex(const NBEdge* from, const NBEdge::Connection& con) const {
3156  int result = 0;
3157  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
3158  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
3159  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
3160  const NBEdge::Connection& cand = *k;
3161  if (*i == from
3162  && cand.fromLane == con.fromLane
3163  && cand.toLane == con.toLane
3164  && cand.toEdge == con.toEdge) {
3165  return result;
3166  };
3167  result++;
3168  }
3169  }
3170  return -1;
3171 }
3172 
3173 Position
3175  /* Conceptually, the center point would be identical with myPosition.
3176  * However, if the shape is influenced by custom geometry endpoints of the adjoining edges,
3177  * myPosition may fall outside the shape. In this case it is better to use
3178  * the center of the shape
3179  **/
3180  PositionVector tmp = myPoly;
3181  tmp.closePolygon();
3182  //std::cout << getID() << " around=" << tmp.around(myPosition) << " dist=" << tmp.distance2D(myPosition) << "\n";
3183  if (tmp.size() < 3 || tmp.around(myPosition) || tmp.distance2D(myPosition) < POSITION_EPS) {
3184  return myPosition;
3185  } else {
3186  return myPoly.getPolygonCenter();
3187  }
3188 }
3189 
3190 
3191 EdgeVector
3193  EdgeVector result = myAllEdges;
3194  if (gDebugFlag1) {
3195  std::cout << " angles:\n";
3196  for (EdgeVector::const_iterator it = result.begin(); it != result.end(); ++it) {
3197  std::cout << " edge=" << (*it)->getID() << " edgeAngle=" << (*it)->getAngleAtNode(this) << " angleToShape=" << (*it)->getAngleAtNodeToCenter(this) << "\n";
3198  }
3199  std::cout << " allEdges before: " << toString(result) << "\n";
3200  }
3201  sort(result.begin(), result.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
3202  // let the first edge in myAllEdges remain the first
3203  if (gDebugFlag1) {
3204  std::cout << " allEdges sorted: " << toString(result) << "\n";
3205  }
3206  rotate(result.begin(), std::find(result.begin(), result.end(), *myAllEdges.begin()), result.end());
3207  if (gDebugFlag1) {
3208  std::cout << " allEdges rotated: " << toString(result) << "\n";
3209  }
3210  return result;
3211 }
3212 
3213 
3214 std::string
3215 NBNode::getNodeIDFromInternalLane(const std::string id) {
3216  // this relies on the fact that internal ids always have the form
3217  // :<nodeID>_<part1>_<part2>
3218  // i.e. :C_3_0, :C_c1_0 :C_w0_0
3219  assert(id[0] == ':');
3220  std::string::size_type sep_index = id.rfind('_');
3221  if (sep_index == std::string::npos) {
3222  WRITE_ERROR("Invalid lane id '" + id + "' (missing '_').");
3223  return "";
3224  }
3225  sep_index = id.substr(0, sep_index).rfind('_');
3226  if (sep_index == std::string::npos) {
3227  WRITE_ERROR("Invalid lane id '" + id + "' (missing '_').");
3228  return "";
3229  }
3230  return id.substr(1, sep_index - 1);
3231 }
3232 
3233 
3234 void
3236  // simple case: edges with LANESPREAD_CENTER and a (possible) turndirection at the same node
3237  for (EdgeVector::iterator it = myIncomingEdges.begin(); it != myIncomingEdges.end(); it++) {
3238  NBEdge* edge = *it;
3239  NBEdge* turnDest = edge->getTurnDestination(true);
3240  if (turnDest != nullptr) {
3241  edge->shiftPositionAtNode(this, turnDest);
3242  turnDest->shiftPositionAtNode(this, edge);
3243  }
3244  }
3245  // @todo: edges in the same direction with sharp angles starting/ending at the same position
3246 }
3247 
3248 
3249 bool
3251  return type == NODETYPE_TRAFFIC_LIGHT
3254 }
3255 
3256 
3257 bool
3258 NBNode::rightOnRedConflict(int index, int foeIndex) const {
3260  for (std::set<NBTrafficLightDefinition*>::const_iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
3261  if ((*i)->rightOnRedConflict(index, foeIndex)) {
3262  return true;
3263  }
3264  }
3265  }
3266  return false;
3267 }
3268 
3269 
3270 void
3271 NBNode::sortEdges(bool useNodeShape) {
3272  if (myAllEdges.size() == 0) {
3273  return;
3274  }
3275  EdgeVector allEdgesOriginal = myAllEdges;
3276  EdgeVector& allEdges = myAllEdges;
3277  EdgeVector& incoming = myIncomingEdges;
3278  EdgeVector& outgoing = myOutgoingEdges;
3279 
3280  // sort the edges by angle (this is the canonical sorting)
3281  std::sort(allEdges.begin(), allEdges.end(), NBNodesEdgesSorter::edge_by_junction_angle_sorter(this));
3282  std::sort(incoming.begin(), incoming.end(), NBNodesEdgesSorter::edge_by_junction_angle_sorter(this));
3283  std::sort(outgoing.begin(), outgoing.end(), NBNodesEdgesSorter::edge_by_junction_angle_sorter(this));
3284  std::vector<NBEdge*>::iterator j;
3285  for (j = allEdges.begin(); j != allEdges.end() - 1 && j != allEdges.end(); ++j) {
3286  NBNodesEdgesSorter::swapWhenReversed(this, j, j + 1);
3287  }
3288  if (allEdges.size() > 1 && j != allEdges.end()) {
3289  NBNodesEdgesSorter::swapWhenReversed(this, allEdges.end() - 1, allEdges.begin());
3290  }
3291 
3292  // sort again using additional geometry information
3293  NBEdge* firstOfAll = allEdges.front();
3294  NBEdge* firstOfIncoming = incoming.size() > 0 ? incoming.front() : 0;
3295  NBEdge* firstOfOutgoing = outgoing.size() > 0 ? outgoing.front() : 0;
3296  // sort by the angle between the node shape center and the point where the edge meets the node shape
3297  sort(allEdges.begin(), allEdges.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
3298  sort(incoming.begin(), incoming.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
3299  sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
3300  // let the first edge remain the first
3301  rotate(allEdges.begin(), std::find(allEdges.begin(), allEdges.end(), firstOfAll), allEdges.end());
3302  if (firstOfIncoming != nullptr) {
3303  rotate(incoming.begin(), std::find(incoming.begin(), incoming.end(), firstOfIncoming), incoming.end());
3304  }
3305  if (firstOfOutgoing != nullptr) {
3306  rotate(outgoing.begin(), std::find(outgoing.begin(), outgoing.end(), firstOfOutgoing), outgoing.end());
3307  }
3308 #ifdef DEBUG_EDGE_SORTING
3309  if (DEBUGCOND) {
3310  std::cout << "sortedEdges:\n";
3311  for (NBEdge* e : allEdges) {
3312  std::cout << " " << e->getID()
3313  << " angleToCenter=" << e->getAngleAtNodeToCenter(this)
3314  << " junctionAngle=" << e->getAngleAtNode(this) << "\n";
3315  }
3316  }
3317 #endif
3318 
3319  // fixing some pathological all edges orderings
3320  // if every of the edges a,b,c has a turning edge a',b',c' the all edges ordering should be a,a',b,b',c,c'
3321  if (incoming.size() == outgoing.size() && incoming.front() == allEdges.front()) {
3322  std::vector<NBEdge*>::const_iterator in, out;
3323  std::vector<NBEdge*> allTmp;
3324  for (in = incoming.begin(), out = outgoing.begin(); in != incoming.end(); ++in, ++out) {
3325  if ((*in)->isTurningDirectionAt(*out)) {
3326  allTmp.push_back(*in);
3327  allTmp.push_back(*out);
3328  } else {
3329  break;
3330  }
3331  }
3332  if (allTmp.size() == allEdges.size()) {
3333  allEdges = allTmp;
3334  }
3335  }
3336  // sort the crossings
3337  std::sort(myCrossings.begin(), myCrossings.end(), NBNodesEdgesSorter::crossing_by_junction_angle_sorter(this, allEdges));
3338  //if (crossings.size() > 0) {
3339  // std::cout << " crossings at " << getID() << "\n";
3340  // for (std::vector<NBNode::Crossing*>::iterator it = crossings.begin(); it != crossings.end(); ++it) {
3341  // std::cout << " " << toString((*it)->edges) << "\n";
3342  // }
3343  //}
3344 
3345  if (useNodeShape && myAllEdges != allEdgesOriginal) {
3346  // sorting order changed after node shape was computed.
3347  computeNodeShape(-1);
3348  for (NBEdge* e : myAllEdges) {
3349  e->computeEdgeShape();
3350  }
3351  }
3352 }
3353 
3354 std::vector<std::pair<Position, std::string> >
3356  // using a set would be nicer but we want to have some slack in position identification
3357  std::vector<std::pair<Position, std::string> >result;
3358  for (NBEdge* e : myAllEdges) {
3359  Position pos = this == e->getFromNode() ? e->getGeometry().front() : e->getGeometry().back();
3360  const std::string origID = e->getParameter(this == e->getFromNode() ? "origFrom" : "origTo");
3361  bool unique = true;
3362  for (const auto& pair : result) {
3363  if (pos.almostSame(pair.first) || (origID != "" && pair.second == origID)) {
3364  unique = false;
3365  break;
3366  }
3367  }
3368  if (unique) {
3369  result.push_back(std::make_pair(pos, origID));
3370  }
3371  }
3372  return result;
3373 }
3374 
3375 
3376 /****************************************************************************/
NBNode::ApproachingDivider::~ApproachingDivider
~ApproachingDivider()
Destructor.
Definition: NBNode.cpp:128
NBRequest::getSizes
std::pair< int, int > getSizes() const
returns the number of the junction's lanes and the number of the junction's links in respect.
Definition: NBRequest.cpp:493
NBEdge::Connection::tlID
std::string tlID
The id of the traffic light that controls this connection.
Definition: NBEdge.h:218
NBNode::getResponse
const std::string getResponse(int linkIndex) const
Definition: NBNode.cpp:978
NODETYPE_PRIORITY
Definition: SUMOXMLDefinitions.h:1061
UNUSED_PARAMETER
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:31
NBNode::FORWARD
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:204
NBNode::WalkingArea::minPrevCrossingEdges
int minPrevCrossingEdges
minimum number of edges crossed by incoming crossings
Definition: NBNode.h:195
SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:156
NBNode::hasOutgoing
bool hasOutgoing(const NBEdge *const e) const
Returns whether the given edge starts at this node.
Definition: NBNode.cpp:1537
NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED
Definition: SUMOXMLDefinitions.h:1058
ToString.h
NBRequest::mustBrakeForCrossing
static bool mustBrakeForCrossing(const NBNode *node, const NBEdge *const from, const NBEdge *const to, const NBNode::Crossing &crossing)
Returns the information whether the described flow must brake for the given crossing.
Definition: NBRequest.cpp:985
NBNode::getEdgesThatApproach
void getEdgesThatApproach(NBEdge *currentOutgoing, EdgeVector &approaching)
returns a list of edges which are connected to the given outgoing edge
Definition: NBNode.cpp:1367
NBEdge::Connection::toEdge
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:212
NBNode::foes
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:1820
NODETYPE_ZIPPER
Definition: SUMOXMLDefinitions.h:1065
NBEdge::ROUNDABOUT
Definition: NBEdge.h:348
LINKSTATE_EQUAL
This is an uncontrolled, right-before-left link.
Definition: SUMOXMLDefinitions.h:1159
MIN2
T MIN2(T a, T b)
Definition: StdDefs.h:73
NBNode::myIsBentPriority
bool myIsBentPriority
Definition: NBNode.h:875
PositionVector::getPolygonCenter
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
Definition: PositionVector.cpp:400
NBEdge::isConnectedTo
bool isConnectedTo(const NBEdge *e) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition: NBEdge.cpp:1149
PositionVector::getSubpartByIndex
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
Definition: PositionVector.cpp:789
NBNode::addOutgoingEdge
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:461
NBNode::getLinkState
LinkState getLinkState(const NBEdge *incoming, NBEdge *outgoing, int fromLane, int toLane, bool mayDefinitelyPass, const std::string &tlID) const
get link state
Definition: NBNode.cpp:2011
NBEdge::Connection::haveVia
bool haveVia
check if Connection have a Via
Definition: NBEdge.h:257
NBNode::WalkingArea::shape
PositionVector shape
The polygonal shape.
Definition: NBNode.h:183
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:275
NBContHelper::opposite_finder
Definition: NBContHelper.h:375
Parameterised
An upper class for objects with additional parameters.
Definition: Parameterised.h:42
NBNode::computeLogic2
void computeLogic2(bool checkLaneFoes)
compute right-of-way logic for all lane-to-lane connections
Definition: NBNode.cpp:950
NBNode::replaceOutgoing
void replaceOutgoing(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurences of the first edge within the list of outgoing by the second Connections are remap...
Definition: NBNode.cpp:1389
SPLIT_CROSSING_ANGLE_THRESHOLD
#define SPLIT_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:64
NBRequest::mustBrake
bool mustBrake(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
Definition: NBRequest.cpp:1001
NBNode::ApproachingDivider::ApproachingDivider
ApproachingDivider(const EdgeVector &approaching, NBEdge *currentOutgoing)
Constructor.
Definition: NBNode.cpp:96
NBNode::checkIsRemovableReporting
bool checkIsRemovableReporting(std::string &reason) const
check if node is removable and return reason if not
Definition: NBNode.cpp:2050
Named
Base class for objects which have an id.
Definition: Named.h:56
NBEdgeCont
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:60
LINKSTATE_TL_OFF_BLINKING
The link is controlled by a tls which is off and blinks, has to brake.
Definition: SUMOXMLDefinitions.h:1151
GeomHelper::angleDiff
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:180
NBNode::myTrafficLights
std::set< NBTrafficLightDefinition * > myTrafficLights
traffic lights of node
Definition: NBNode.h:849
NBContHelper::edge_similar_direction_sorter
Definition: NBContHelper.h:217
NBTrafficLightLogicCont
A container for traffic light definitions and built programs.
Definition: NBTrafficLightLogicCont.h:57
NBNode::mustBrakeForCrossing
bool mustBrakeForCrossing(const NBEdge *const from, const NBEdge *const to, const Crossing &crossing) const
Returns the information whether the described flow must brake for the given crossing.
Definition: NBNode.cpp:1692
OutputDevice
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:63
NBEdgeCont::erase
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:380
NBEdge::getStep
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:580
NBNode::myType
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:831
NBNode::includes
static bool includes(const std::set< NBEdge *, ComparatorIdLess > &super, const std::set< const NBEdge *, ComparatorIdLess > &sub)
returns whether sub is a subset of super
Definition: NBNode.cpp:2967
NBNode::isLeftMover
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:1791
NBEdge::shiftPositionAtNode
void shiftPositionAtNode(NBNode *node, NBEdge *opposite)
shift geometry at the given node to avoid overlap
Definition: NBEdge.cpp:3647
NBEdge::addLane2LaneConnections
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:1012
LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
Definition: SUMOXMLDefinitions.h:1153
Position::z
double z() const
Returns the z-position.
Definition: Position.h:66
NBNode::myBlockedConnections
NBConnectionProhibits myBlockedConnections
The container for connection block dependencies.
Definition: NBNode.h:834
NBNodesEdgesSorter::swapWhenReversed
static void swapWhenReversed(const NBNode *const n, const std::vector< NBEdge * >::iterator &i1, const std::vector< NBEdge * >::iterator &i2)
Assures correct order for same-angle opposite-direction edges.
Definition: NBAlgorithms.cpp:144
Position::INVALID
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:284
OptionsCont.h
NBRequest::getResponse
const std::string & getResponse(int linkIndex) const
Definition: NBRequest.cpp:382
NBNode::getConnectionTo
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:2158
NBNode::bezierControlPoints
static PositionVector bezierControlPoints(const PositionVector &begShape, const PositionVector &endShape, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, bool &ok, NBNode *recordError=0, double straightThresh=DEG2RAD(5), int shapeFlag=0)
get bezier control points
Definition: NBNode.cpp:533
NBRequest
Definition: NBRequest.h:58
PositionVector::getSubpart
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
Definition: PositionVector.cpp:706
PositionVector::smoothedZFront
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
Definition: PositionVector.cpp:1582
MsgHandler.h
NBDistrict::replaceOutgoing
void replaceOutgoing(const EdgeVector &which, NBEdge *const by)
Replaces outgoing edges from the vector (source) by the given edge.
Definition: NBDistrict.cpp:133
SUMOXMLDefinitions
class for maintaining associations between enums and xml-strings
Definition: SUMOXMLDefinitions.h:1349
NBNode::forbidsPedestriansAfter
bool forbidsPedestriansAfter(std::vector< std::pair< NBEdge *, bool > > normalizedLanes, int startIndex)
return whether there is a non-sidewalk lane after the given index;
Definition: NBNode.cpp:2404
EdgeVector
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
NBNode::WalkingArea::hasCustomShape
bool hasCustomShape
whether this walkingArea has a custom shape
Definition: NBNode.h:191
NBNode::Crossing::shape
PositionVector shape
The crossing's shape.
Definition: NBNode.h:139
LINKDIR_PARTRIGHT
The link is a partial right direction.
Definition: SUMOXMLDefinitions.h:1190
NBEdge::isTurningDirectionAt
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2756
NBNode::computeSmoothShape
PositionVector computeSmoothShape(const PositionVector &begShape, const PositionVector &endShape, int numPoints, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, NBNode *recordError=0, int shapeFlag=0) const
Compute a smooth curve between the given geometries.
Definition: NBNode.cpp:506
NBNode::getOutgoingEdges
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:260
NBEdge::getCrossingAngle
double getCrossingAngle(NBNode *node)
return the angle for computing pedestrian crossings at the given node
Definition: NBEdge.cpp:3504
NBNode::myRequest
NBRequest * myRequest
Node requests.
Definition: NBNode.h:846
NBEdge::isBidiRail
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:691
NBRequest.h
NBConnection::getFrom
NBEdge * getFrom() const
returns the from-edge (start of the connection)
Definition: NBConnection.cpp:89
NBEdge::replaceInConnections
void replaceInConnections(NBEdge *which, NBEdge *by, int laneOff)
replace in current connections of edge
Definition: NBEdge.cpp:1348
NBNode::checkCrossing
int checkCrossing(EdgeVector candidates)
Definition: NBNode.cpp:2296
NBEdgeCont.h
GeoConvHelper.h
NBHelpers::normRelAngle
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:59
NBConnection::getTo
NBEdge * getTo() const
returns the to-edge (end of the connection)
Definition: NBConnection.cpp:95
LINKDIR_TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
Definition: SUMOXMLDefinitions.h:1182
NBOwnTLDef
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:46
NODETYPE_UNKNOWN
Definition: SUMOXMLDefinitions.h:1055
SVC_BICYCLE
vehicle is a bicycle
Definition: SUMOVehicleClass.h:179
NBTrafficLightDefinition.h
OptionsCont::getOptions
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:57
NBNode::getType
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:272
NBNode::addWalkingAreaShape
void addWalkingAreaShape(EdgeVector edges, const PositionVector &shape)
add custom shape for walkingArea
Definition: NBNode.cpp:3017
NBEdge::getPriority
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:484
NBNode::Crossing::Crossing
Crossing(const NBNode *_node, const EdgeVector &_edges, double _width, bool _priority, int _customTLIndex, int _customTLIndex2, const PositionVector &_customShape)
constructor
Definition: NBNode.cpp:234
PositionVector::isNAN
bool isNAN() const
check if PositionVector is NAN
Definition: PositionVector.cpp:1331
SUMO_const_laneWidth
const double SUMO_const_laneWidth
Definition: StdDefs.h:49
NBNode::Crossing::id
std::string id
the (edge)-id of this crossing
Definition: NBNode.h:145
NBEdge::getSpecialLane
int getSpecialLane(SVCPermissions permissions) const
return index of the first lane that allows the given permissions
Definition: NBEdge.cpp:3467
NBNode::removeCrossing
void removeCrossing(const EdgeVector &edges)
remove a pedestrian crossing from this node (identified by its edges)
Definition: NBNode.cpp:3081
RAD2DEG
#define RAD2DEG(x)
Definition: GeomHelper.h:38
PositionVector::extrapolate
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
Definition: PositionVector.cpp:1042
NBNode::getNodeIDFromInternalLane
static std::string getNodeIDFromInternalLane(const std::string id)
returns the node id for internal lanes, crossings and walkingareas
Definition: NBNode.cpp:3215
NBNode::buildCrossings
int buildCrossings()
build pedestrian crossings
Definition: NBNode.cpp:2499
PositionVector::length
double length() const
Returns the length.
Definition: PositionVector.cpp:484
WRITE_WARNINGF
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:276
NBTrafficLightDefinition::getOffset
SUMOTime getOffset()
Returns the offset.
Definition: NBTrafficLightDefinition.h:324
NBNode::rightOnRedConflict
bool rightOnRedConflict(int index, int foeIndex) const
whether the given index must yield to the foeIndex while turing right on a red light
Definition: NBNode.cpp:3258
NBEdge::getPermissions
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3404
LinkDirection
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
Definition: SUMOXMLDefinitions.h:1176
NBNode::ApproachingDivider::myAvailableLanes
std::vector< int > myAvailableLanes
The available lanes to which connections shall be built.
Definition: NBNode.h:117
NBNode::WalkingAreaCustomShape
Definition: NBNode.h:198
NBNode::isConstantWidthTransition
bool isConstantWidthTransition() const
detects whether a given junction splits or merges lanes while keeping constant road width
Definition: NBNode.cpp:780
NBEdge::Connection::tlLinkIndex
int tlLinkIndex
The index of this connection within the controlling traffic light.
Definition: NBEdge.h:221
NBNode::WalkingArea
A definition of a pedestrian walking area.
Definition: NBNode.h:170
LINKSTATE_MAJOR
This is an uncontrolled, major link, may pass.
Definition: SUMOXMLDefinitions.h:1155
NBRequest::buildBitfieldLogic
void buildBitfieldLogic()
builds the bitset-representation of the logic
Definition: NBRequest.cpp:146
PositionVector
A list of positions.
Definition: PositionVector.h:45
NBNode::ApproachingDivider::execute
void execute(const int src, const int dest)
the bresenham-callback
Definition: NBNode.cpp:132
NBNode::addSortedLinkFoes
void addSortedLinkFoes(const NBConnection &mayDrive, const NBConnection &mustStop)
add shorted link FOES
Definition: NBNode.cpp:1561
NBDistrictCont
A container for districts.
Definition: NBDistrictCont.h:52
LINKDIR_NODIR
The link has no direction (is a dead end link)
Definition: SUMOXMLDefinitions.h:1192
NBEdge::remapConnections
void remapConnections(const EdgeVector &incoming)
Remaps the connection in a way that allows the removal of it.
Definition: NBEdge.cpp:1250
NBNode::writeLogic
bool writeLogic(OutputDevice &into) const
writes the XML-representation of the logic as a bitset-logic XML representation
Definition: NBNode.cpp:958
NBNode::computeInternalLaneShape
PositionVector computeInternalLaneShape(NBEdge *fromE, const NBEdge::Connection &con, int numPoints, NBNode *recordError=0, int shapeFlag=0) const
Compute the shape for an internal lane.
Definition: NBNode.cpp:698
NBRequest::foes
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: NBRequest.cpp:512
NBDistrict.h
NBHelpers::relAngle
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition: NBHelpers.cpp:46
NBNode::turnFoes
bool turnFoes(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *from2, const NBEdge *to2, int fromLane2, bool lefthand=false) const
return whether the given laneToLane connection originate from the same edge and are in conflict due t...
Definition: NBNode.cpp:1745
NBEdge::Connection::fromLane
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:209
PositionVector::angleAt2D
double angleAt2D(int pos) const
get angle in certain position of position vector
Definition: PositionVector.cpp:1221
NBEdge
The representation of a single edge during network building.
Definition: NBEdge.h:91
NBNode::needsCont
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:837
NBNodeShapeComputer::getRadius
double getRadius() const
get computed radius for node
Definition: NBNodeShapeComputer.h:56
NBNode::replaceInConnectionProhibitions
void replaceInConnectionProhibitions(NBEdge *which, NBEdge *by, int whichLaneOff, int byLaneOff)
replace incoming connections prohibitions
Definition: NBNode.cpp:1458
LINKDIR_RIGHT
The link is a (hard) right direction.
Definition: SUMOXMLDefinitions.h:1186
NBEdge::getFirstNonPedestrianLaneIndex
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:3451
NBNode::addIncomingEdge
void addIncomingEdge(NBEdge *edge)
adds an incoming edge
Definition: NBNode.cpp:451
MAX2
T MAX2(T a, T b)
Definition: StdDefs.h:79
NBNode::ApproachingDivider::myApproaching
const EdgeVector & myApproaching
The list of edges that approach the current edge.
Definition: NBNode.h:111
PositionVector::add
void add(double xoff, double yoff, double zoff)
Definition: PositionVector.cpp:617
NBEdge::Connection::toLane
int toLane
The lane the connections yields in.
Definition: NBEdge.h:215
Position::norm2d
void norm2d()
Definition: Position.h:166
NBNode::getPosition
const Position & getPosition() const
Definition: NBNode.h:247
NBNode::checkIsRemovable
bool checkIsRemovable() const
check if node is removable
Definition: NBNode.cpp:2044
LINKDIR_TURN
The link is a 180 degree turn.
Definition: SUMOXMLDefinitions.h:1180
NBNode::getEdgesToJoin
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
Definition: NBNode.cpp:2117
PositionVector::nearest_offset_to_point2D
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
Definition: PositionVector.cpp:817
Position::almostSame
bool almostSame(const Position &p2, double maxDiv=POSITION_EPS) const
check if two position is almost the sme as other
Definition: Position.h:228
LinkState
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
Definition: SUMOXMLDefinitions.h:1137
NODETYPE_ALLWAY_STOP
Definition: SUMOXMLDefinitions.h:1064
NBNode::getNextCompatibleOutgoing
NBEdge * getNextCompatibleOutgoing(const NBEdge *incoming, SVCPermissions vehPerm, EdgeVector::const_iterator start, bool clockwise) const
Definition: NBNode.cpp:1908
NBNode::myAllEdges
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition: NBNode.h:819
NODETYPE_RAIL_SIGNAL
Definition: SUMOXMLDefinitions.h:1059
Bresenham::compute
static void compute(BresenhamCallBack *callBack, const int val1, const int val2)
Definition: Bresenham.cpp:33
NBNode::computeLanes2Lanes
void computeLanes2Lanes()
computes the connections of lanes to edges
Definition: NBNode.cpp:1027
NBNode::getPossiblySplittedOutgoing
NBEdge * getPossiblySplittedOutgoing(const std::string &edgeid)
get possibly splitted outgoing edge
Definition: NBNode.cpp:1591
LINKDIR_STRAIGHT
The link is a straight direction.
Definition: SUMOXMLDefinitions.h:1178
NBEdge::getToNode
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:498
NBNode::isTLControlled
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:313
NBEdge::setConnection
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1029
NBNode::WalkingAreaCustomShape::edges
std::set< const NBEdge *, ComparatorIdLess > edges
Definition: NBNode.h:199
NBTrafficLightDefinition::getType
TrafficLightType getType() const
get the algorithm type (static etc..)
Definition: NBTrafficLightDefinition.h:330
PositionVector::push_back_noDoublePos
void push_back_noDoublePos(const Position &p)
insert in back a non double position
Definition: PositionVector.cpp:1295
NBNode::getOppositeIncoming
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition: NBNode.cpp:1543
isForbidden
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
Definition: SUMOVehicleClass.cpp:375
NBNode::reshiftPosition
void reshiftPosition(double xoff, double yoff)
Applies an offset to the node.
Definition: NBNode.cpp:329
NBNode::myCrossingsLoadedFromSumoNet
int myCrossingsLoadedFromSumoNet
number of crossings loaded from a sumo net
Definition: NBNode.h:867
NBNode::discardAllCrossings
void discardAllCrossings(bool rejectAll)
discard all current (and optionally future) crossings
Definition: NBNode.cpp:2457
NBEdge::getLaneWidth
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:587
NBNode::Crossing::prevWalkingArea
std::string prevWalkingArea
the lane-id of the previous walkingArea
Definition: NBNode.h:147
SVCPermissions
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
Definition: SUMOVehicleClass.h:218
NBNode::invalidateIncomingConnections
void invalidateIncomingConnections()
invalidate incoming connections
Definition: NBNode.cpp:1662
NBNode::computeLogic
void computeLogic(const NBEdgeCont &ec)
computes the node's type, logic and traffic light
Definition: NBNode.cpp:911
NODETYPE_PRIORITY_STOP
Definition: SUMOXMLDefinitions.h:1062
SVC_RAIL_CLASSES
classes which drive on tracks
Definition: SUMOVehicleClass.h:204
NODETYPE_TRAFFIC_LIGHT_NOJUNCTION
Definition: SUMOXMLDefinitions.h:1057
NBNode::WalkingArea::nextSidewalks
std::vector< std::string > nextSidewalks
the lane-id of the next sidewalk lane or ""
Definition: NBNode.h:187
NBNode::displaceShapeAtWidthChange
void displaceShapeAtWidthChange(const NBEdge *from, const NBEdge::Connection &con, PositionVector &fromShape, PositionVector &toShape) const
displace lane shapes to account for change in lane width at this node
Definition: NBNode.cpp:788
PositionVector::around
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
Definition: PositionVector.cpp:74
NBEdge::Connection::getDescription
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:87
NBNode::WalkingAreaCustomShape::shape
PositionVector shape
Definition: NBNode.h:200
SumoXMLNodeType
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
Definition: SUMOXMLDefinitions.h:1054
Position::set
void set(double x, double y)
set positions x and y
Definition: Position.h:86
NBEdge::EdgeBuildingStep::LANES2LANES_DONE
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
NBNode::getConnectionIndex
int getConnectionIndex(const NBEdge *from, const NBEdge::Connection &con) const
return the index of the given connection
Definition: NBNode.cpp:3155
NBNode::getEndPoints
std::vector< std::pair< Position, std::string > > getEndPoints() const
return list of unique endpoint coordinates of all edges at this node
Definition: NBNode.cpp:3355
NBNode::shiftTLConnectionLaneIndex
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset, int threshold=-1)
patches loaded signal plans by modifying lane indices above threshold by the given offset
Definition: NBNode.cpp:410
NBNode::mirrorX
void mirrorX()
mirror coordinates along the x-axis
Definition: NBNode.cpp:342
EdgeSet
std::set< NBEdge * > EdgeSet
container for unique edges
Definition: NBCont.h:49
NBNode::setCrossingTLIndices
bool setCrossingTLIndices(const std::string &tlID, int startIndex)
Definition: NBNode.cpp:3124
NBTypeCont.h
NBNode::myFringeType
FringeType myFringeType
fringe type of this node
Definition: NBNode.h:861
PositionVector::closePolygon
void closePolygon()
ensures that the last position equals the first
Definition: PositionVector.cpp:1231
NBNode::removeTrafficLight
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:371
NBNode::getDirection
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
Definition: NBNode.cpp:1933
NBEdge::isInsideTLS
bool isInsideTLS() const
Returns whether this edge was marked as being within an intersection.
Definition: NBEdge.h:1041
NBNode::myKeepClear
bool myKeepClear
whether the junction area must be kept clear
Definition: NBNode.h:855
NBTrafficLightLogicCont::remapRemoved
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurences of the removed edge in incoming/outgoing edges of all definitions.
Definition: NBTrafficLightLogicCont.cpp:210
LINKSTATE_ZIPPER
This is an uncontrolled, zipper-merge link.
Definition: SUMOXMLDefinitions.h:1165
NBEdge::getNumLanes
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:477
NBNode::setRoundabout
void setRoundabout()
update the type of this node as a roundabout
Definition: NBNode.cpp:3061
NBNode::numNormalConnections
int numNormalConnections() const
return the number of lane-to-lane connections at this junction (excluding crossings)
Definition: NBNode.cpp:3140
OutputDevice.h
NBEdge::L2L_COMPUTED
The connection was computed.
Definition: NBEdge.h:131
NBNode::myDisplacementError
double myDisplacementError
geometry error after computation of internal lane shapes
Definition: NBNode.h:870
ProcessError
Definition: UtilExceptions.h:39
NBContHelper::nextCCW
static void nextCCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
Definition: NBContHelper.cpp:48
getVehicleClassNames
const std::string & getVehicleClassNames(SVCPermissions permissions, bool expand)
Returns the ids of the given classes, divided using a ' '.
Definition: SUMOVehicleClass.cpp:168
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:363
NBRequest::getFoes
const std::string & getFoes(int linkIndex) const
Definition: NBRequest.cpp:374
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:38
NBNode::removeTrafficLights
void removeTrafficLights()
Removes all references to traffic lights that control this tls.
Definition: NBNode.cpp:378
NBTrafficLightDefinition::getNodes
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
Definition: NBTrafficLightDefinition.h:172
NBNode::addTrafficLight
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:361
Position::x
double x() const
Returns the x-position.
Definition: Position.h:56
NBNode::rightTurnConflict
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:1698
NBNode::myHaveCustomPoly
bool myHaveCustomPoly
whether this nodes shape was set by the user
Definition: NBNode.h:843
PositionVector::append
void append(const PositionVector &v, double sameThreshold=2.0)
Definition: PositionVector.cpp:696
NBEdge::getTotalWidth
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:3276
UtilExceptions.h
Position::sub
void sub(double dx, double dy)
Substracts the given position from this one.
Definition: Position.h:146
NBHelpers.h
NBNode::invalidateOutgoingConnections
void invalidateOutgoingConnections()
invalidate outgoing connections
Definition: NBNode.cpp:1670
OptionsCont
A storage for options typed value containers)
Definition: OptionsCont.h:89
NBEdge::startShapeAt
static PositionVector startShapeAt(const PositionVector &laneShape, const NBNode *startNode, PositionVector nodeShape)
Definition: NBEdge.cpp:819
NBContHelper.h
NBNode::getEdges
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:265
NBEdge::getLaneStruct
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1287
NBEdge::Lane::width
double width
This lane's width.
Definition: NBEdge.h:166
LINKDIR_LEFT
The link is a (hard) left direction.
Definition: SUMOXMLDefinitions.h:1184
NBNode::setCustomShape
void setCustomShape(const PositionVector &shape)
set the junction shape
Definition: NBNode.cpp:2146
NBConnection
Definition: NBConnection.h:43
NBEdge::Connection::getID
const std::string & getID() const
Definition: NBEdge.h:289
LINKSTATE_MINOR
This is an uncontrolled, minor link, has to brake.
Definition: SUMOXMLDefinitions.h:1157
NBNode::SCURVE_IGNORE
static const int SCURVE_IGNORE
Definition: NBNode.h:215
PositionVector::length2D
double length2D() const
Returns the length.
Definition: PositionVector.cpp:497
NBNode::WalkingArea::prevSidewalks
std::vector< std::string > prevSidewalks
the lane-id of the previous sidewalk lane or ""
Definition: NBNode.h:189
Position::mul
void mul(double val)
Multiplies both positions with the given value.
Definition: Position.h:106
NBConnection::replaceFrom
bool replaceFrom(NBEdge *which, NBEdge *by)
replaces the from-edge by the one given
Definition: NBConnection.cpp:101
NBEdge::L2L_VALIDATED
The connection was computed and validated.
Definition: NBEdge.h:135
NODETYPE_RAIL_CROSSING
Definition: SUMOXMLDefinitions.h:1060
NODETYPE_RIGHT_BEFORE_LEFT
Definition: SUMOXMLDefinitions.h:1063
NBNode::WalkingArea::minNextCrossingEdges
int minNextCrossingEdges
minimum number of edges crossed by nextCrossings
Definition: NBNode.h:193
NBNode::getCrossings
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.cpp:2439
NBEdge::getEndAngle
double getEndAngle() const
Returns the angle at the end of the edge (relative to the node shape center) The angle is computed in...
Definition: NBEdge.h:516
NBNode::myDiscardAllCrossings
bool myDiscardAllCrossings
whether to discard all pedestrian crossings
Definition: NBNode.h:864
NBNode::removeEdge
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1604
NBNodeShapeComputer::compute
PositionVector compute()
Computes the shape of the assigned junction.
Definition: NBNodeShapeComputer.cpp:59
SPLIT_CROSSING_WIDTH_THRESHOLD
#define SPLIT_CROSSING_WIDTH_THRESHOLD
Definition: NBNode.cpp:63
NODETYPE_DEAD_END
Definition: SUMOXMLDefinitions.h:1069
NODETYPE_DISTRICT
Definition: SUMOXMLDefinitions.h:1066
MIN_WEAVE_LENGTH
#define MIN_WEAVE_LENGTH
Definition: NBNode.cpp:67
DEG2RAD
#define DEG2RAD(x)
Definition: GeomHelper.h:37
NBEdge::getLanes
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:656
NBRequest::forbids
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: NBRequest.cpp:531
NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter
Definition: NBContHelper.h:395
PositionVector::getOrthogonal
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0) const
return orthogonal through p (extending this vector if necessary)
Definition: PositionVector.cpp:1543
NBNode::ApproachingDivider::numAvailableLanes
int numAvailableLanes() const
@ get number of avaliable lanes
Definition: NBNode.h:99
PositionVector::distance2D
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
Definition: PositionVector.cpp:1259
NBNode::myDistrict
NBDistrict * myDistrict
The district the node is the centre of.
Definition: NBNode.h:837
NBEdge::getLoadedLength
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:554
Position::angleTo2D
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position
Definition: Position.h:253
NBNode::myOutgoingEdges
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:816
Position::distanceTo2D
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:243
NBEdge::getIncomingEdges
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1211
NBContHelper::relative_outgoing_edge_sorter
Definition: NBContHelper.h:76
StringUtils
Some static methods for string processing.
Definition: StringUtils.h:39
GeomHelper::getCWAngleDiff
static double getCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle clockwise.
Definition: GeomHelper.cpp:164
NBNode::myCrossings
std::vector< Crossing * > myCrossings
Vector of crossings.
Definition: NBNode.h:822
OptionsCont::getFloat
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
Definition: OptionsCont.cpp:208
NBNode::myTypeWasGuessed
bool myTypeWasGuessed
whether the node type was guessed rather than loaded
Definition: NBNode.h:878
NBEdge::getEndOffset
double getEndOffset() const
Returns the offset to the destination node.
Definition: NBEdge.h:612
NBEdge::getLaneShape
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:879
NBConnectionProhibits
std::map< NBConnection, NBConnectionVector > NBConnectionProhibits
Definition of a container for connection block dependencies Includes a list of all connections which ...
Definition: NBConnectionDefs.h:39
NBNode::avoidOverlap
void avoidOverlap()
fix overlap
Definition: NBNode.cpp:3235
NBNodeCont.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:47
StringUtils.h
NBNode::discardWalkingareas
void discardWalkingareas()
discard previously built walkingareas (required for repeated computation by netedit)
Definition: NBNode.cpp:2470
NBNode::getShape
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:2140
NBNode::addCrossing
NBNode::Crossing * addCrossing(EdgeVector edges, double width, bool priority, int tlIndex=-1, int tlIndex2=-1, const PositionVector &customShape=PositionVector::EMPTY, bool fromSumoNet=false)
add a pedestrian crossing to this node
Definition: NBNode.cpp:3069
NBNode::Crossing::width
double width
This crossing's width.
Definition: NBNode.h:143
Position::y
double y() const
Returns the y-position.
Definition: Position.h:61
NBNode::crossingBetween
bool crossingBetween(const NBEdge *e1, const NBEdge *e2) const
return true if the given edges are connected by a crossing
Definition: NBNode.cpp:2980
NBNode::myPosition
Position myPosition
The position the node lies at.
Definition: NBNode.h:810
NBNode::~NBNode
~NBNode()
Destructor.
Definition: NBNode.cpp:297
M_PI
#define M_PI
Definition: odrSpiral.cpp:40
PositionVector::positionAtOffset2D
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
Definition: PositionVector.cpp:273
NBRequest::writeLogic
void writeLogic(OutputDevice &into) const
Definition: NBRequest.cpp:390
NBNode::removeJoinedTrafficLights
void removeJoinedTrafficLights()
remove all traffic light definitions that are part of a joined tls
Definition: NBNode.cpp:896
NBEdge::getJunctionPriority
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1816
NBNode::remapRemoved
void remapRemoved(NBTrafficLightLogicCont &tc, NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
remap removed
Definition: NBNode.cpp:1827
NBNode::buildWalkingAreas
void buildWalkingAreas(int cornerDetail)
build pedestrian walking areas and set connections from/to walkingAreas
Definition: NBNode.cpp:2596
PositionVector::reverse
PositionVector reverse() const
reverse position vector
Definition: PositionVector.cpp:1086
NBEdge::getSpeed
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:571
NBNode::geometryLike
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3026
NBNode::mustBrake
bool mustBrake(const NBEdge *const from, const NBEdge *const to, int fromLane, int toLane, bool includePedCrossings) const
Returns the information whether the described flow must let any other flow pass.
Definition: NBNode.cpp:1678
InvalidArgument
Definition: UtilExceptions.h:56
DEBUGCOND
#define DEBUGCOND
Definition: NBNode.cpp:75
NBNode::forbids
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:1810
NBEdge::Lane
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:142
NBNode::AVOID_INTERSECTING_LEFT_TURNS
static const int AVOID_INTERSECTING_LEFT_TURNS
Definition: NBNode.h:214
SUMOXMLDefinitions::isValidNetID
static bool isValidNetID(const std::string &value)
whether the given string is a valid id for a network element
Definition: SUMOXMLDefinitions.cpp:967
NBNode::WalkingArea::width
double width
This lane's width.
Definition: NBNode.h:179
NBTrafficLightLogicCont::removeFully
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
Definition: NBTrafficLightLogicCont.cpp:97
SUMO_MAX_CONNECTIONS
#define SUMO_MAX_CONNECTIONS
the maximum number of connections across an intersection
Definition: StdDefs.h:42
NBEdge::getStartAngle
double getStartAngle() const
Returns the angle at the start of the edge (relative to the node shape center) The angle is computed ...
Definition: NBEdge.h:507
NBNode::myWalkingAreas
std::vector< WalkingArea > myWalkingAreas
Vector of walking areas.
Definition: NBNode.h:825
NBNode::getIncomingEdges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:255
NBNode::NBNode
NBNode(const std::string &id, const Position &position, SumoXMLNodeType type)
Constructor.
Definition: NBNode.cpp:252
NBConnection::replaceTo
bool replaceTo(NBEdge *which, NBEdge *by)
replaces the to-edge by the one given
Definition: NBConnection.cpp:135
NBNode::UNSPECIFIED_RADIUS
static const double UNSPECIFIED_RADIUS
unspecified lane width
Definition: NBNode.h:208
NBConnectionVector
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
Definition: NBConnectionDefs.h:34
NBEdge::Lane::permissions
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:153
NBNode::isLongEnough
static bool isLongEnough(NBEdge *out, double minLength)
check if is long enough
Definition: NBNode.cpp:1350
NBNode::isTrafficLight
static bool isTrafficLight(SumoXMLNodeType type)
return whether the given type is a traffic light
Definition: NBNode.cpp:3250
NBNode::FOUR_CONTROL_POINTS
static const int FOUR_CONTROL_POINTS
Definition: NBNode.h:213
NBEdge::getConnectionLanes
std::vector< int > getConnectionLanes(NBEdge *currentOutgoing, bool withBikes=true) const
Returns the list of lanes that may be used to reach the given edge.
Definition: NBEdge.cpp:1224
NBNode::isSimpleContinuation
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition: NBNode.cpp:471
NBEdge::UNSPECIFIED_WIDTH
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:315
NBEdge::Connection::customShape
PositionVector customShape
custom shape for connection
Definition: NBEdge.h:242
NBNode::removeDoubleEdges
void removeDoubleEdges()
remove duble edges
Definition: NBNode.cpp:1493
NBTrafficLightDefinition::addNode
virtual void addNode(NBNode *node)
Adds a node to the traffic light logic.
Definition: NBTrafficLightDefinition.cpp:414
NBNode::myRadius
double myRadius
the turning radius (for all corners) at this node in m.
Definition: NBNode.h:852
NBNode::sortEdges
void sortEdges(bool useNodeShape)
sort all edge containers for this node
Definition: NBNode.cpp:3271
NBNode::Crossing::edges
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:137
NBNodeTypeComputer::isRailwayNode
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
Definition: NBAlgorithms.cpp:282
NBNode::ApproachingDivider::myIsBikeEdge
bool myIsBikeEdge
whether the outgoing edge is exclusively used by bikes
Definition: NBNode.h:120
NBRequest::computeLogic
void computeLogic(const bool checkLaneFoes)
writes the XML-representation of the logic as a bitset-logic XML representation
Definition: NBRequest.cpp:412
NBNode::AVOID_WIDE_LEFT_TURN
static const int AVOID_WIDE_LEFT_TURN
Definition: NBNode.h:212
NBNode::getCrossing
Crossing * getCrossing(const std::string &id) const
return the crossing with the given id
Definition: NBNode.cpp:3096
NBTrafficLightDefinition::removeNode
virtual void removeNode(NBNode *node)
Removes the given node from the list of controlled nodes.
Definition: NBTrafficLightDefinition.cpp:424
NBNode::WalkingArea::length
double length
This lane's width.
Definition: NBNode.h:181
NBNode::getEmptyDir
Position getEmptyDir() const
Returns something like the most unused direction Should only be used to add source or sink nodes.
Definition: NBNode.cpp:1634
NBNode::myIncomingEdges
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition: NBNode.h:813
NBNode::hasIncoming
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1531
NBNode::guessCrossings
int guessCrossings()
guess pedestrian crossings and return how many were guessed
Definition: NBNode.cpp:2192
LINKSTATE_ALLWAY_STOP
This is an uncontrolled, all-way stop link.
Definition: SUMOXMLDefinitions.h:1163
NBContHelper::edge_opposite_direction_sorter
Class to sort edges by their angle in relation to the given edge.
Definition: NBContHelper.h:140
NBContHelper::nextCW
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
Definition: NBContHelper.cpp:39
NBEdge::getSidewalkID
std::string getSidewalkID()
get the lane id for the canonical sidewalk lane
Definition: NBEdge.cpp:3529
config.h
NBEdge::getConnectedEdges
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1199
NBNode::getEdgesSortedByAngleAtNodeCenter
EdgeVector getEdgesSortedByAngleAtNodeCenter() const
returns the list of all edges sorted clockwise by getAngleAtNodeToCenter
Definition: NBNode.cpp:3192
Position::add
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:126
GeomHelper.h
NBEdge::getPermissionVariants
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:3491
NBNodesEdgesSorter::edge_by_junction_angle_sorter
Sorts incoming and outgoing edges clockwise around the given node.
Definition: NBAlgorithms.h:158
gDebugFlag1
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:32
EXTEND_CROSSING_ANGLE_THRESHOLD
#define EXTEND_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:61
PositionVector::bezier
PositionVector bezier(int numPoints)
return a bezier interpolation
Definition: PositionVector.cpp:1682
NBNode::tlsContConflict
bool tlsContConflict(const NBEdge *from, const NBEdge::Connection &c, const NBEdge *foeFrom, const NBEdge::Connection &foe) const
whether the connection must yield if the foe remains on the intersection after its phase ends
Definition: NBNode.cpp:886
StdDefs.h
NBNode::Crossing::nextWalkingArea
std::string nextWalkingArea
the lane-id of the next walkingArea
Definition: NBNode.h:149
FRINGE_TYPE_DEFAULT
Definition: SUMOXMLDefinitions.h:1113
NBNode::myPoly
PositionVector myPoly
the (outer) shape of the junction
Definition: NBNode.h:840
NBNode::invalidateTLS
void invalidateTLS(NBTrafficLightLogicCont &tlCont, bool removedConnections, bool addedConnections)
causes the traffic light to be computed anew
Definition: NBNode.cpp:387
NBEdge::Lane::endOffset
double endOffset
This lane's offset to the intersection begin.
Definition: NBEdge.h:159
NBNode::BACKWARD
static const int BACKWARD
Definition: NBNode.h:205
NBEdge::Lane::shape
PositionVector shape
The lane's shape.
Definition: NBEdge.h:147
NBNode::myWalkingAreaCustomShapes
std::vector< WalkingAreaCustomShape > myWalkingAreaCustomShapes
Vector of custom walking areas shapes.
Definition: NBNode.h:828
NBNode
Represents a single node (junction) during network building.
Definition: NBNode.h:67
NBOwnTLDef.h
NBTrafficLightLogicCont.h
NBLoadedSUMOTLDef.h
NBNode::ApproachingDivider
Computes lane-2-lane connections.
Definition: NBNode.h:87
NBAlgorithms.h
NBEdge::hasConnectionTo
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:1143
NBNode::removeSelfLoops
int removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes edges which are both incoming and outgoing into this node.
Definition: NBNode.cpp:418
NBNode::getPossiblySplittedIncoming
NBEdge * getPossiblySplittedIncoming(const std::string &edgeid)
get possibly splitted incoming edge
Definition: NBNode.cpp:1578
NBNode::Crossing
A definition of a pedestrian crossing.
Definition: NBNode.h:131
NBNode::AVOID_WIDE_RIGHT_TURN
static const int AVOID_WIDE_RIGHT_TURN
flags for controlling shape generation
Definition: NBNode.h:211
NBEdge::Connection
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:189
Named::myID
std::string myID
The name of the object.
Definition: Named.h:133
NBNode::getCenter
Position getCenter() const
Returns a position that is guaranteed to lie within the node shape.
Definition: NBNode.cpp:3174
NBTrafficLightLogicCont::insert
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
Definition: NBTrafficLightLogicCont.cpp:73
NBNode.h
DEBUGCOND2
#define DEBUGCOND2(obj)
Definition: NBNode.cpp:76
PositionVector::mirrorX
void mirrorX()
Definition: PositionVector.cpp:655
NBNode::myRightOfWay
RightOfWay myRightOfWay
how to compute right of way for this node
Definition: NBNode.h:858
LINKDIR_PARTLEFT
The link is a partial left direction.
Definition: SUMOXMLDefinitions.h:1188
NBNode::buildInnerEdges
void buildInnerEdges()
build internal lanes, pedestrian crossings and walking areas
Definition: NBNode.cpp:2476
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:76
NBEdge::getAngleAtNode
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1836
POSITION_EPS
#define POSITION_EPS
Definition: config.h:172
NBEdge::getNodeBorder
const PositionVector & getNodeBorder(const NBNode *node)
Definition: NBEdge.cpp:669
NBDistrict::replaceIncoming
void replaceIncoming(const EdgeVector &which, NBEdge *const by)
Replaces incoming edges from the vector (sinks) by the given edge.
Definition: NBDistrict.cpp:101
WRITE_ERROR
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:283
NBNode::ApproachingDivider::spread
std::deque< int > * spread(const std::vector< int > &approachingLanes, int dest) const
the method that spreads the wished number of lanes from the the lane given by the bresenham-call to b...
Definition: NBNode.cpp:165
NBDistrict
A class representing a single district.
Definition: NBDistrict.h:64
NBEdge::getFromNode
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:491
NBNode::WalkingArea::id
std::string id
the (edge)-id of this walkingArea
Definition: NBNode.h:177
NBNode::Crossing::valid
bool valid
whether this crossing is valid (and can be written to the net.xml). This is needed for netedit becaus...
Definition: NBNode.h:163
NBNodesEdgesSorter::crossing_by_junction_angle_sorter
Sorts crossings by minimum clockwise clockwise edge angle. Use the ordering found in myAllEdges of th...
Definition: NBAlgorithms.h:112
NBNode::getFoes
const std::string getFoes(int linkIndex) const
Definition: NBNode.cpp:968
NBNode::buildCrossingsAndWalkingAreas
void buildCrossingsAndWalkingAreas()
build crossings, and walkingareas. Also removes invalid loaded crossings if wished
Definition: NBNode.cpp:2415
PositionVector::extrapolate2D
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
Definition: PositionVector.cpp:1064
NBNode::WalkingArea::nextCrossings
std::vector< std::string > nextCrossings
the lane-id of the next crossing(s)
Definition: NBNode.h:185
NBNode::ApproachingDivider::myCurrentOutgoing
NBEdge * myCurrentOutgoing
The approached current edge.
Definition: NBNode.h:114
NBNode::isDistrict
bool isDistrict() const
check if node is a district
Definition: NBNode.cpp:2186
PositionVector::move2side
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount
Definition: PositionVector.cpp:1103
NBNodeShapeComputer.h
NBNode::checkCrossingDuplicated
bool checkCrossingDuplicated(EdgeVector edges)
return true if there already exist a crossing with the same edges as the input
Definition: NBNode.cpp:2387
PositionVector::push_front_noDoublePos
void push_front_noDoublePos(const Position &p)
insert in front a non double position
Definition: PositionVector.cpp:1303
NBNode::reinit
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:303
NBEdge::EdgeBuildingStep::LANES2LANES_USER
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
NBTrafficLightDefinition
The base class for traffic light logic definitions.
Definition: NBTrafficLightDefinition.h:67
NBEdge::EdgeBuildingStep::LANES2EDGES
Lanes to edges - relationships are computed/loaded.
NBNode::edgesBetween
EdgeVector edgesBetween(const NBEdge *e1, const NBEdge *e2) const
return all edges that lie clockwise between the given edges
Definition: NBNode.cpp:3001
GeomHelper::getCCWAngleDiff
static double getCCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle counter-clockwise.
Definition: GeomHelper.cpp:154
NBNode::computeNodeShape
void computeNodeShape(double mismatchThreshold)
Compute the junction shape for this node.
Definition: NBNode.cpp:988
NBNode::replaceIncoming
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurences of the first edge within the list of incoming by the second Connections are remap...
Definition: NBNode.cpp:1425
NBNodeShapeComputer
This class computes shapes of junctions.
Definition: NBNodeShapeComputer.h:44
NODETYPE_NOJUNCTION
Definition: SUMOXMLDefinitions.h:1067
LINKSTATE_STOP
This is an uncontrolled, minor link, has to stop.
Definition: SUMOXMLDefinitions.h:1161
NBEdge::getTurnDestination
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3084
NBEdge::getID
const std::string & getID() const
Definition: NBEdge.h:1380
NBNode::isNearDistrict
bool isNearDistrict() const
@chech if node is near district
Definition: NBNode.cpp:2169
NODETYPE_TRAFFIC_LIGHT
Definition: SUMOXMLDefinitions.h:1056