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