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