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