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