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
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
The link is a partial left direction.
double z() const
Returns the z-position.
Definition: Position.h:73
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:240
void replaceOutgoing(const EdgeVector &which, NBEdge *const by)
Replaces outgoing edges from the vector (source) by the given edge.
Definition: NBDistrict.cpp:141
Position getEmptyDir() const
Returns something like the most unused direction Should only be used to add source or sink nodes...
Definition: NBNode.cpp:1321
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:164
int numAvailableLanes() const
@ get number of avaliable lanes
Definition: NBNode.h:120
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
std::vector< Crossing > myCrossings
Vector of crossings.
Definition: NBNode.h:735
Position getCenter() const
Returns a position that is guaranteed to lie within the node shape.
Definition: NBNode.cpp:2622
ApproachingDivider(EdgeVector *approaching, NBEdge *currentOutgoing)
Constructor.
Definition: NBNode.cpp:94
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:250
PositionVector shape
The lane&#39;s shape.
Definition: NBEdge.h: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)
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
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
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
bool isDistrict() const
check if node is a district
Definition: NBNode.cpp:1781
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
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition: NBNode.cpp:1230
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1576
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
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:65
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point...
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:741
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn&#39;t set.
Definition: NBEdge.h:490
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
#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
int getConnectionIndex(const NBEdge *from, const NBEdge::Connection &con) const
return the index of the given connection
Definition: NBNode.cpp:2603
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:288
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
~NBNode()
Destructor.
Definition: NBNode.cpp:256
Some static methods for string processing.
Definition: StringUtils.h:45
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
Definition: NBRequest.cpp:437
TrafficLightType getType() const
get the algorithm type (static etc..)
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:570
double x() const
Returns the x-position.
Definition: Position.h:63
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.
const Crossing & getCrossing(const std::string &id) const
return the crossing with the given id
Definition: NBNode.cpp:2567
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
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
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
static double getCCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle counter-clockwise.
Definition: GeomHelper.cpp:148
Class to sort edges by their angle in relation to the given edge.
Definition: NBContHelper.h:178
bool replaceTo(NBEdge *which, NBEdge *by)
replaces the to-edge by the one given
static const double DEFAULT_CROSSING_WIDTH
default width of pedetrian crossings
Definition: NBNode.h:197
static void swapWhenReversed(const NBNode *const n, const std::vector< NBEdge * >::iterator &i1, const std::vector< NBEdge * >::iterator &i2)
Assures correct order for same-angle opposite-direction edges.
The link is a 180 degree turn.
int numNormalConnections() const
return the number of lane-to-lane connections at this junction (excluding crossings) ...
Definition: NBNode.cpp:2597
static const double UNSPECIFIED_RADIUS
unspecified lane width
Definition: NBNode.h:200
bool hasOutgoing(const NBEdge *const e) const
Returns whether the given edge starts at this node.
Definition: NBNode.cpp:1224
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:86
A container for districts.
The base class for traffic light logic definitions.
EdgeVector edgesBetween(const NBEdge *e1, const NBEdge *e2) const
return all edges that lie clockwise between the given edges
Definition: NBNode.cpp:2495
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1119
static bool isLongEnough(NBEdge *out, double minLength)
check if is long enough
Definition: NBNode.cpp:1037
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) ...
bool isJoinedTLSControlled() const
Returns whether this node is controlled by a tls that spans over more than one node.
Definition: NBNode.cpp:336
void buildBitfieldLogic()
Definition: NBRequest.cpp:152
PositionVector computeInternalLaneShape(NBEdge *fromE, const NBEdge::Connection &con, int numPoints, NBNode *recordError=0) const
Compute the shape for an internal lane.
Definition: NBNode.cpp:627
void removeDoubleEdges()
remove duble edges
Definition: NBNode.cpp:1180
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
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:507
PositionVector shape
The lane&#39;s shape.
Definition: NBNode.h:149
#define SPLIT_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:72
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
void buildWalkingAreas(int cornerDetail)
build pedestrian walking areas and set connections from/to walkingAreas
Definition: NBNode.cpp:2145
bool isInnerEdge() const
Returns whether this edge was marked as being within an intersection.
Definition: NBEdge.h:941
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 connectionsDone
Whether connection information for this lane is already completed.
Definition: NBEdge.h:157
EdgeVector getEdgesSortedByAngleAtNodeCenter() const
returns the list of all edges sorted clockwise by getAngleAtNodeToCenter
Definition: NBNode.cpp:2640
bool checkIsRemovable() const
check if node is removable
Definition: NBNode.cpp:1642
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.
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
void writeLogic(std::string key, OutputDevice &into, const bool checkLaneFoes) const
Definition: NBRequest.cpp:321
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1218
This is an uncontrolled, all-way stop link.
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:422
NBEdge * getFrom() const
returns the from-edge (start of the connection)
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
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
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
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
PositionVector reverse() const
reverse position vector
#define MIN_WEAVE_LENGTH
Definition: NBNode.cpp:75
NBRequest * myRequest
Node requests.
Definition: NBNode.h:756
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
CustomShapeMap myCustomLaneShapes
custom lane shapes
Definition: NBNode.h:768
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1107
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
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:245
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
const std::string & getID() const
Returns the id.
Definition: Named.h:66
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
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
void computeLanes2Lanes()
computes the connections of lanes to edges
Definition: NBNode.cpp:813
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void invalidateIncomingConnections()
invalidate incoming connections
Definition: NBNode.cpp: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
double area() const
Returns the area (0 for non-closed)
const Position & getPosition() const
Definition: NBNode.h:232
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
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:523
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
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
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
void setCrossingTLIndices(const std::string &tlID, int startIndex)
set tl indices of this nodes crossing starting at the given index
Definition: NBNode.cpp:2588
std::string getInternalLaneID() const
get ID of internal lane
Definition: NBEdge.cpp:80
This is an uncontrolled, minor link, has to brake.
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
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
std::pair< int, int > getSizes() const
returns the number of the junction&#39;s lanes and the number of the junction&#39;s links in respect...
Definition: NBRequest.cpp:399
A list of positions.
bool mustBrake(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
Definition: NBRequest.cpp:764
bool addLane2LaneConnections(int fromLane, NBEdge *dest, int toLane, int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp:924
static double getCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle clockwise.
Definition: GeomHelper.cpp:158
double y() const
Returns the y-position.
Definition: Position.h:68
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2511
void invalidateOutgoingConnections()
invalidate outgoing connections
Definition: NBNode.cpp:1357
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:413
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic, in MSLink and GNEInternalLane.
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:516
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2367
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
std::set< NBTrafficLightDefinition * > myTrafficLights
traffic lights of node
Definition: NBNode.h:759
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:2955
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:176
LinkState getLinkState(const NBEdge *incoming, NBEdge *outgoing, int fromLane, int toLane, bool mayDefinitelyPass, const std::string &tlID) const
get link state
Definition: NBNode.cpp:1613
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
bool rightOnRedConflict(int index, int foeIndex) const
whether the given index must yield to the foeIndex while turing right on a red light ...
Definition: NBNode.cpp:2706
bool myDiscardAllCrossings
whether to discard all pedestrian crossings
Definition: NBNode.h:771
void replaceInConnectionProhibitions(NBEdge *which, NBEdge *by, int whichLaneOff, int byLaneOff)
replace incoming connections prohibitions
Definition: NBNode.cpp:1145
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
PositionVector compute()
Computes the shape of the assigned junction.
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1716
double myRadius
the turning radius (for all corners) at this node in m.
Definition: NBNode.h:762
The link is a partial right direction.
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:1739
double width
This lane&#39;s width.
Definition: NBEdge.h:144
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
void move2side(double amount)
move position vector to side using certain ammount
virtual void removeNode(NBNode *node)
Removes the given node from the list of controlled nodes.
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition: NBNode.h:726
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
Base class for objects which have an id.
Definition: Named.h:46
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
Definition: NBNode.cpp:1693
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1556
void avoidOverlap()
fix overlap
Definition: NBNode.cpp:2683
NBEdge * getPossiblySplittedOutgoing(const std::string &edgeid)
get possibly splitted outgoing edge
Definition: NBNode.cpp:1278
int internalLaneIndex
The lane index of this internal lane within the internal edge.
Definition: NBEdge.h:241
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:729
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2913
NBEdge * myCurrentOutgoing
The approached current edge.
Definition: NBNode.h:104
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
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:434
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:310
bool isNearDistrict() const
if node is near district
Definition: NBNode.cpp:1750
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
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
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
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
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
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
bool mustBrake(const NBEdge *const from, const NBEdge *const to, int fromLane, int toLane, bool includePedCrossings) const
Returns the information whether the described flow must let any other flow pass.
Definition: NBNode.cpp:1365
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
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
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
A storage for options typed value containers)
Definition: OptionsCont.h:99
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:385
This is an uncontrolled, major link, may pass.
std::deque< int > * spread(const std::vector< int > &approachingLanes, int dest) const
the method that spreads the wished number of lanes from the the lane given by the bresenham-call to b...
Definition: NBNode.cpp:152
NBEdge * getTo() const
returns the to-edge (end of the connection)
The connection was computed.
Definition: NBEdge.h:113
bool crossingBetween(const NBEdge *e1, const NBEdge *e2) const
return true if the given edges are connected by a crossing
Definition: NBNode.cpp:2478
Represents a single node (junction) during network building.
Definition: NBNode.h:75
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
bool isSimpleContinuation(bool checkLaneNumbers=true) const
check if node is a simple continuation
Definition: NBNode.cpp:432
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
Definition: NBRequest.cpp:418
void addCrossing(EdgeVector edges, double width, bool priority, bool fromSumoNet=false)
add a pedestrian crossing to this node
Definition: NBNode.cpp: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
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
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
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
static void compute(BresenhamCallBack *callBack, const int val1, const int val2)
Definition: Bresenham.cpp:41
Computes lane-2-lane connections.
Definition: NBNode.h:98
bool writeLogic(OutputDevice &into, const bool checkLaneFoes) const
writes the XML-representation of the logic as a bitset-logic XML representation
Definition: NBNode.cpp:771
void push_back_noDoublePos(const Position &p)
insert in back a non double position
#define SPLIT_CROSSING_WIDTH_THRESHOLD
Definition: NBNode.cpp:71
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
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:174
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
#define DEBUGCOND
Definition: NBNode.cpp:78
void add(double xoff, double yoff, double zoff)
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
Definition: NBNode.cpp:1461
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
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:2972
void closePolygon()
ensures that the last position equals the first
Lanes to edges - relationships are computed/loaded.
Definition: NBEdge.h:98
NBNode(const std::string &id, const Position &position, SumoXMLNodeType type)
Constructor.
Definition: NBNode.cpp:225
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:834
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:2670
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
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:757
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
double angleAt2D(int pos) const
get angle in certain position of position vector
static void nextCCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
void reshiftPosition(double xoff, double yoff)
Applies an offset to the node.
Definition: NBNode.cpp:288
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:260
void remapRemoved(NBTrafficLightLogicCont &tc, NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
remap removed
Definition: NBNode.cpp: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
void replaceIncoming(const EdgeVector &which, NBEdge *const by)
Replaces incoming edges from the vector (sinks) by the given edge.
Definition: NBDistrict.cpp:109
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
Definition: NBNode.cpp:1451
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
static std::string getNodeIDFromInternalLane(const std::string id)
returns the node id for internal lanes, crossings and walkingareas
Definition: NBNode.cpp:2663
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:427