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