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