SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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-2015 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/Line.h>
47 #include <utils/geom/GeomHelper.h>
48 #include <utils/geom/bezier.h>
50 #include <utils/common/StdDefs.h>
51 #include <utils/common/ToString.h>
54 #include <iomanip>
55 #include "NBNode.h"
56 #include "NBAlgorithms.h"
57 #include "NBNodeCont.h"
58 #include "NBNodeShapeComputer.h"
59 #include "NBEdgeCont.h"
60 #include "NBTypeCont.h"
61 #include "NBHelpers.h"
62 #include "NBDistrict.h"
63 #include "NBContHelper.h"
64 #include "NBRequest.h"
65 #include "NBOwnTLDef.h"
68 
69 #ifdef CHECK_MEMORY_LEAKS
70 #include <foreign/nvwa/debug_new.h>
71 #endif // CHECK_MEMORY_LEAKS
72 
73 // allow to extend a crossing across multiple edges
74 #define EXTEND_CROSSING_ANGLE_THRESHOLD 35.0 // degrees
75 // create intermediate walking areas if either of the following thresholds is exceeded
76 #define SPLIT_CROSSING_WIDTH_THRESHOLD 1.5 // meters
77 #define SPLIT_CROSSING_ANGLE_THRESHOLD 5 // degrees
78 // do not build uncontrolled crossings across edges with a speed above the threshold
79 #define UNCONTROLLED_CROSSING_SPEED_THRESHOLD 13.89 // meters/second
80 
81 #define DEBUGID "C"
82 
83 // ===========================================================================
84 // static members
85 // ===========================================================================
86 const int NBNode::MAX_CONNECTIONS(64);
87 const int NBNode::FORWARD(1);
88 const int NBNode::BACKWARD(-1);
92 
93 // ===========================================================================
94 // method definitions
95 // ===========================================================================
96 /* -------------------------------------------------------------------------
97  * NBNode::ApproachingDivider-methods
98  * ----------------------------------------------------------------------- */
100  EdgeVector* approaching, NBEdge* currentOutgoing, const bool buildCrossingsAndWalkingAreas) :
101  myApproaching(approaching), myCurrentOutgoing(currentOutgoing) {
102  // check whether origin lanes have been given
103  assert(myApproaching != 0);
104  // collect lanes which are expliclity targeted
105  std::set<int> approachedLanes;
106  for (EdgeVector::iterator it = myApproaching->begin(); it != myApproaching->end(); ++it) {
107  const std::vector<NBEdge::Connection> conns = (*it)->getConnections();
108  for (std::vector<NBEdge::Connection>::const_iterator it_con = conns.begin(); it_con != conns.end(); ++it_con) {
109  if ((*it_con).toEdge == myCurrentOutgoing) {
110  approachedLanes.insert((*it_con).toLane);
111  }
112  }
113  }
114  // compute the indices of lanes that should be targeted (excluding pedestrian
115  // lanes that will be connected from walkingAreas and forbidden lanes)
116  // if the lane is targeted by an explicitly set connection we need
117  // to make it available anyway
118  for (int i = 0; i < (int)currentOutgoing->getNumLanes(); ++i) {
119  if (((buildCrossingsAndWalkingAreas && currentOutgoing->getPermissions(i) == SVC_PEDESTRIAN)
120  || isForbidden(currentOutgoing->getPermissions(i)))
121  && approachedLanes.count(i) == 0) {
122  continue;
123  }
124  myAvailableLanes.push_back((unsigned int)i);
125  }
126 }
127 
128 
130 
131 
132 void
133 NBNode::ApproachingDivider::execute(const unsigned int src, const unsigned int dest) {
134  assert(myApproaching->size() > src);
135  // get the origin edge
136  NBEdge* incomingEdge = (*myApproaching)[src];
137  if (incomingEdge->getStep() == NBEdge::LANES2LANES_DONE || incomingEdge->getStep() == NBEdge::LANES2LANES_USER) {
138  return;
139  }
140  std::vector<int> approachingLanes =
141  incomingEdge->getConnectionLanes(myCurrentOutgoing);
142  assert(approachingLanes.size() != 0);
143  std::deque<int>* approachedLanes = spread(approachingLanes, dest);
144  assert(approachedLanes->size() <= myAvailableLanes.size());
145  // set lanes
146  for (unsigned int i = 0; i < approachedLanes->size(); i++) {
147  assert(approachedLanes->size() > i);
148  assert(approachingLanes.size() > i);
149  unsigned int approached = myAvailableLanes[(*approachedLanes)[i]];
150  //std::cout << "setting connection from " << incomingEdge->getID() << "_" << approachingLanes[i] << " to " << myCurrentOutgoing->getID() << "_" << approached << "\n";
151  incomingEdge->setConnection((unsigned int) approachingLanes[i], myCurrentOutgoing,
152  approached, NBEdge::L2L_COMPUTED);
153  }
154  delete approachedLanes;
155 }
156 
157 
158 std::deque<int>*
159 NBNode::ApproachingDivider::spread(const std::vector<int>& approachingLanes,
160  int dest) const {
161  std::deque<int>* ret = new std::deque<int>();
162  unsigned int noLanes = (unsigned int) approachingLanes.size();
163  // when only one lane is approached, we check, whether the SUMOReal-value
164  // is assigned more to the left or right lane
165  if (noLanes == 1) {
166  ret->push_back(dest);
167  return ret;
168  }
169 
170  unsigned int noOutgoingLanes = (unsigned int)myAvailableLanes.size();
171  //
172  ret->push_back(dest);
173  unsigned int noSet = 1;
174  int roffset = 1;
175  int loffset = 1;
176  while (noSet < noLanes) {
177  // It may be possible, that there are not enough lanes the source
178  // lanes may be divided on
179  // In this case, they remain unset
180  // !!! this is only a hack. It is possible, that this yields in
181  // uncommon divisions
182  if (noOutgoingLanes == noSet) {
183  return ret;
184  }
185 
186  // as due to the conversion of SUMOReal->uint the numbers will be lower
187  // than they should be, we try to append to the left side first
188  //
189  // check whether the left boundary of the approached street has
190  // been overridden; if so, move all lanes to the right
191  if (dest + loffset >= static_cast<int>(noOutgoingLanes)) {
192  loffset -= 1;
193  roffset += 1;
194  for (unsigned int i = 0; i < ret->size(); i++) {
195  (*ret)[i] = (*ret)[i] - 1;
196  }
197  }
198  // append the next lane to the left of all edges
199  // increase the position (destination edge)
200  ret->push_back(dest + loffset);
201  noSet++;
202  loffset += 1;
203 
204  // as above
205  if (noOutgoingLanes == noSet) {
206  return ret;
207  }
208 
209  // now we try to append the next lane to the right side, when needed
210  if (noSet < noLanes) {
211  // check whether the right boundary of the approached street has
212  // been overridden; if so, move all lanes to the right
213  if (dest < roffset) {
214  loffset += 1;
215  roffset -= 1;
216  for (unsigned int i = 0; i < ret->size(); i++) {
217  (*ret)[i] = (*ret)[i] + 1;
218  }
219  }
220  ret->push_front(dest - roffset);
221  noSet++;
222  roffset += 1;
223  }
224  }
225  return ret;
226 }
227 
228 
229 /* -------------------------------------------------------------------------
230  * NBNode-methods
231  * ----------------------------------------------------------------------- */
232 NBNode::NBNode(const std::string& id, const Position& position,
233  SumoXMLNodeType type) :
234  Named(StringUtils::convertUmlaute(id)),
235  myPosition(position),
236  myType(type),
237  myDistrict(0),
238  myHaveCustomPoly(false),
239  myRequest(0),
241 { }
242 
243 
244 NBNode::NBNode(const std::string& id, const Position& position, NBDistrict* district) :
245  Named(StringUtils::convertUmlaute(id)),
246  myPosition(position),
247  myType(district == 0 ? NODETYPE_UNKNOWN : NODETYPE_DISTRICT),
248  myDistrict(district),
249  myHaveCustomPoly(false),
250  myRequest(0),
251  myRadius(UNSPECIFIED_RADIUS)
252 { }
253 
254 
256  delete myRequest;
257 }
258 
259 
260 void
262  bool updateEdgeGeometries) {
263  myPosition = position;
264  // patch type
265  myType = type;
268  }
269  if (updateEdgeGeometries) {
270  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
271  PositionVector geom = (*i)->getGeometry();
272  geom[-1] = myPosition;
273  (*i)->setGeometry(geom);
274  }
275  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
276  PositionVector geom = (*i)->getGeometry();
277  geom[0] = myPosition;
278  (*i)->setGeometry(geom);
279  }
280  }
281 }
282 
283 
284 
285 // ----------- Applying offset
286 void
288  myPosition.add(xoff, yoff, 0);
289  myPoly.add(xoff, yoff, 0);
290 }
291 
292 
293 // ----------- Methods for dealing with assigned traffic lights
294 void
296  myTrafficLights.insert(tlDef);
299  }
300 }
301 
302 
303 void
305  tlDef->removeNode(this);
306  myTrafficLights.erase(tlDef);
307 }
308 
309 
310 void
312  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
313  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
314  removeTrafficLight(*i);
315  }
316 }
317 
318 
319 bool
321  if (!isTLControlled()) {
322  return false;
323  }
324  for (std::set<NBTrafficLightDefinition*>::const_iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
325  if ((*i)->getID().find("joined") == 0) {
326  return true;
327  }
328  }
329  return false;
330 }
331 
332 
333 void
335  if (isTLControlled()) {
336  std::set<NBTrafficLightDefinition*> oldDefs(myTrafficLights);
337  for (std::set<NBTrafficLightDefinition*>::iterator it = oldDefs.begin(); it != oldDefs.end(); ++it) {
338  NBTrafficLightDefinition* orig = *it;
339  if (dynamic_cast<NBOwnTLDef*>(orig) == 0) {
340  NBTrafficLightDefinition* newDef = new NBOwnTLDef(orig->getID(), orig->getOffset(), orig->getType());
341  const std::vector<NBNode*>& nodes = orig->getNodes();
342  while (!nodes.empty()) {
343  nodes.front()->removeTrafficLight(orig);
344  newDef->addNode(nodes.front());
345  }
346  tlCont.removeFully(orig->getID());
347  tlCont.insert(newDef);
348  }
349  }
350  }
351 }
352 
353 
354 void
356  for (std::set<NBTrafficLightDefinition*>::iterator it = myTrafficLights.begin(); it != myTrafficLights.end(); ++it) {
357  (*it)->shiftTLConnectionLaneIndex(edge, offset);
358  }
359 }
360 
361 // ----------- Prunning the input
362 unsigned int
364  unsigned int ret = 0;
365  unsigned int pos = 0;
366  EdgeVector::const_iterator j = myIncomingEdges.begin();
367  while (j != myIncomingEdges.end()) {
368  // skip edges which are only incoming and not outgoing
369  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), *j) == myOutgoingEdges.end()) {
370  ++j;
371  ++pos;
372  continue;
373  }
374  // an edge with both its origin and destination being the current
375  // node should be removed
376  NBEdge* dummy = *j;
377  WRITE_WARNING(" Removing self-looping edge '" + dummy->getID() + "'");
378  // get the list of incoming edges connected to the self-loop
379  EdgeVector incomingConnected;
380  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
381  if ((*i)->isConnectedTo(dummy) && *i != dummy) {
382  incomingConnected.push_back(*i);
383  }
384  }
385  // get the list of outgoing edges connected to the self-loop
386  EdgeVector outgoingConnected;
387  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
388  if (dummy->isConnectedTo(*i) && *i != dummy) {
389  outgoingConnected.push_back(*i);
390  }
391  }
392  // let the self-loop remap its connections
393  dummy->remapConnections(incomingConnected);
394  remapRemoved(tc, dummy, incomingConnected, outgoingConnected);
395  // delete the self-loop
396  ec.erase(dc, dummy);
397  j = myIncomingEdges.begin() + pos;
398  ++ret;
399  }
400  return ret;
401 }
402 
403 
404 // -----------
405 void
407  assert(edge != 0);
408  if (find(myIncomingEdges.begin(), myIncomingEdges.end(), edge) == myIncomingEdges.end()) {
409  myIncomingEdges.push_back(edge);
410  myAllEdges.push_back(edge);
411  }
412 }
413 
414 
415 void
417  assert(edge != 0);
418  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge) == myOutgoingEdges.end()) {
419  myOutgoingEdges.push_back(edge);
420  myAllEdges.push_back(edge);
421  }
422 }
423 
424 
425 bool
427  // one in, one out->continuation
428  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
429  // both must have the same number of lanes
430  return (*(myIncomingEdges.begin()))->getNumLanes() == (*(myOutgoingEdges.begin()))->getNumLanes();
431  }
432  // two in and two out and both in reverse direction
433  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
434  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
435  NBEdge* in = *i;
436  EdgeVector::const_iterator opposite = find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(), NBContHelper::opposite_finder(in));
437  // must have an opposite edge
438  if (opposite == myOutgoingEdges.end()) {
439  return false;
440  }
441  // both must have the same number of lanes
443  if (in->getNumLanes() != (*opposite)->getNumLanes()) {
444  return false;
445  }
446  }
447  return true;
448  }
449  // nope
450  return false;
451 }
452 
453 
456  const PositionVector& endShape,
457  int numPoints,
458  bool isTurnaround,
459  SUMOReal extrapolateBeg,
460  SUMOReal extrapolateEnd) const {
461 
462  const Position beg = begShape.back();
463  const Position end = endShape.front();
464  PositionVector ret;
465  PositionVector init;
466  unsigned int noInitialPoints = 0;
467  bool noSpline = false;
468  if (beg.distanceTo(end) <= POSITION_EPS) {
469  noSpline = true;
470  } else {
471  if (isTurnaround) {
472  // turnarounds:
473  // - end of incoming lane
474  // - position between incoming/outgoing end/begin shifted by the distance orthogonally
475  // - begin of outgoing lane
476  noInitialPoints = 3;
477  init.push_back(beg);
478  Line straightConn(begShape[-1], endShape[0]);
479  Position straightCenter = straightConn.getPositionAtDistance((SUMOReal) straightConn.length() / (SUMOReal) 2.);
480  Position center = straightCenter;//.add(straightCenter);
481  Line cross(straightConn);
482  cross.sub(cross.p1().x(), cross.p1().y());
483  cross.rotateAtP1(M_PI / 2);
484  center.sub(cross.p2());
485  init.push_back(center);
486  init.push_back(end);
487  } else {
488  const SUMOReal angle = fabs(begShape.getEndLine().atan2Angle() - endShape.getBegLine().atan2Angle());
489  if (angle < M_PI / 4. || angle > 7. / 4.*M_PI) {
490  // very low angle: almost straight
491  noInitialPoints = 4;
492  init.push_back(beg);
493  Line begL = begShape.getEndLine();
494  begL.extrapolateSecondBy(100);
495  Line endL = endShape.getBegLine();
496  endL.extrapolateFirstBy(100);
497  SUMOReal distance = beg.distanceTo(end);
498  if (distance > 10) {
499  {
500  SUMOReal off1 = begShape.getEndLine().length() + extrapolateBeg;
501  off1 = MIN2(off1, (SUMOReal)(begShape.getEndLine().length() + distance / 2.));
502  Position tmp = begL.getPositionAtDistance(off1);
503  init.push_back(tmp);
504  }
505  {
506  SUMOReal off1 = (SUMOReal) 100. - extrapolateEnd;
507  off1 = MAX2(off1, (SUMOReal)(100. - distance / 2.));
508  Position tmp = endL.getPositionAtDistance(off1);
509  init.push_back(tmp);
510  }
511  } else {
512  noSpline = true;
513  }
514  init.push_back(end);
515  } else {
516  // turning
517  // - end of incoming lane
518  // - intersection of the extrapolated lanes
519  // - begin of outgoing lane
520  // attention: if there is no intersection, use a straight line
521  noInitialPoints = 3;
522  init.push_back(beg);
523  Line begL = begShape.getEndLine();
524  Line endL = endShape.getBegLine();
525  bool check = !begL.p1().almostSame(begL.p2()) && !endL.p1().almostSame(endL.p2());
526  if (check) {
527  begL.extrapolateSecondBy(100);
528  endL.extrapolateFirstBy(100);
529  } else {
530  WRITE_WARNING("Could not use edge geometry for internal lane, node '" + getID() + "'.");
531  }
532  if (!check || !begL.intersects(endL)) {
533  noSpline = true;
534  } else {
535  init.push_back(begL.intersectsAt(endL));
536  }
537  init.push_back(end);
538  }
539  }
540  }
541  //
542  if (noSpline) {
543  ret.push_back(begShape.back());
544  ret.push_back(endShape.front());
545  } else {
546  SUMOReal* def = new SUMOReal[1 + noInitialPoints * 3];
547  for (int i = 0; i < (int) init.size(); ++i) {
548  // starts at index 1
549  def[i * 3 + 1] = init[i].x();
550  def[i * 3 + 2] = 0;
551  def[i * 3 + 3] = init[i].y();
552  }
553  SUMOReal* ret_buf = new SUMOReal[numPoints * 3 + 1];
554  bezier(noInitialPoints, def, numPoints, ret_buf);
555  delete[] def;
556  Position prev;
557  for (int i = 0; i < (int) numPoints; i++) {
558  Position current(ret_buf[i * 3 + 1], ret_buf[i * 3 + 3], myPosition.z());
559  if (prev != current && !ISNAN(current.x()) && !ISNAN(current.y())) {
560  ret.push_back(current);
561  }
562  prev = current;
563  }
564  delete[] ret_buf;
565  }
566  return ret;
567 }
568 
569 
571 NBNode::computeInternalLaneShape(NBEdge* fromE, const NBEdge::Connection& con, int numPoints) const {
572  if (con.fromLane >= (int) fromE->getNumLanes()) {
573  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(con.fromLane) + "->" + con.toEdge->getID() + "_" + toString(con.toLane) + "' starts at a non-existant lane.");
574  }
575  if (con.toLane >= (int) con.toEdge->getNumLanes()) {
576  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(con.fromLane) + "->" + con.toEdge->getID() + "_" + toString(con.toLane) + "' targets a non-existant lane.");
577  }
578  PositionVector ret;
579  if (myCustomLaneShapes.size() > 0 && con.id != "") {
580  // this is the second pass (ids and shapes are already set
581  assert(con.shape.size() > 0);
582  CustomShapeMap::const_iterator it = myCustomLaneShapes.find(con.getInternalLaneID());
583  if (it != myCustomLaneShapes.end()) {
584  ret = it->second;
585  } else {
586  ret = con.shape;
587  }
588  it = myCustomLaneShapes.find(con.viaID + "_0");
589  if (it != myCustomLaneShapes.end()) {
590  ret.append(it->second);
591  } else {
592  ret.append(con.viaShape);
593  }
594  return ret;
595  }
596 
597  ret = computeSmoothShape(fromE->getLaneShape(con.fromLane), con.toEdge->getLaneShape(con.toLane),
598  numPoints, fromE->getTurnDestination() == con.toEdge,
599  (SUMOReal) 5. * (SUMOReal) fromE->getNumLanes(),
600  (SUMOReal) 5. * (SUMOReal) con.toEdge->getNumLanes());
601  const NBEdge::Lane& lane = fromE->getLaneStruct(con.fromLane);
602  if (lane.endOffset > 0) {
603  PositionVector beg = lane.shape.getSubpart(lane.shape.length() - lane.endOffset, lane.shape.length());;
604  beg.append(ret);
605  ret = beg;
606  }
607  return ret;
608 }
609 
610 
611 bool
612 NBNode::needsCont(const NBEdge* fromE, const NBEdge* otherFromE,
613  const NBEdge::Connection& c, const NBEdge::Connection& otherC) const {
614  const NBEdge* toE = c.toEdge;
615  const NBEdge* otherToE = otherC.toEdge;
616 
618  return false;
619  }
620  LinkDirection d1 = getDirection(fromE, toE);
621  const bool thisRight = (d1 == LINKDIR_RIGHT || d1 == LINKDIR_PARTRIGHT);
622  const bool rightTurnConflict = (thisRight &&
623  myRequest->rightTurnConflict(fromE, toE, c.fromLane, otherFromE, otherToE, otherC.fromLane));
624  if (thisRight && !rightTurnConflict) {
625  return false;
626  }
627  if (!(foes(otherFromE, otherToE, fromE, toE) || myRequest == 0 || rightTurnConflict)) {
628  // if they do not cross, no waiting place is needed
629  return false;
630  }
631  LinkDirection d2 = getDirection(otherFromE, otherToE);
632  if (d2 == LINKDIR_TURN) {
633  return false;
634  }
635  const bool thisLeft = (d1 == LINKDIR_LEFT || d1 == LINKDIR_TURN);
636  const bool otherLeft = (d2 == LINKDIR_LEFT || d2 == LINKDIR_TURN);
637  const bool bothLeft = thisLeft && otherLeft;
638  if (fromE == otherFromE && !thisRight) {
639  // ignore same edge links except for right-turns
640  return false;
641  }
642  if (thisRight && d2 != LINKDIR_STRAIGHT) {
643  return false;
644  }
645  if (c.tlID != "" && !bothLeft) {
646  assert(myTrafficLights.size() > 0);
647  return (*myTrafficLights.begin())->needsCont(fromE, toE, otherFromE, otherToE);
648  }
649  if (fromE->getJunctionPriority(this) > 0 && otherFromE->getJunctionPriority(this) > 0) {
650  return mustBrake(fromE, toE, c.fromLane, false);
651  }
652  return false;
653 }
654 
655 
656 void
658  delete myRequest; // possibly recomputation step
659  myRequest = 0;
660  if (myIncomingEdges.size() == 0 || myOutgoingEdges.size() == 0) {
661  // no logic if nothing happens here
663  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
665  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
666  (*i)->setParticipantsInformation();
667  (*i)->setTLControllingInformation(ec);
668  }
669  return;
670  }
671  // check whether the node was set to be unregulated by the user
672  if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", getID())
673  || (oc.getBool("keep-nodes-unregulated.district-nodes") && (isNearDistrict() || isDistrict()))) {
675  return;
676  }
677  // compute the logic if necessary or split the junction
679  // build the request
681  // check whether it is not too large
682  unsigned int numConnections = numNormalConnections();
683  if (numConnections >= MAX_CONNECTIONS) {
684  // yep -> make it untcontrolled, warn
685  WRITE_WARNING("Junction '" + getID() + "' is too complicated (#links>64); will be set to unregulated.");
686  delete myRequest;
687  myRequest = 0;
689  } else if (numConnections == 0) {
690  delete myRequest;
691  myRequest = 0;
693  } else {
695  }
696  }
697 }
698 
699 
700 bool
701 NBNode::writeLogic(OutputDevice& into, const bool checkLaneFoes) const {
702  if (myRequest) {
703  myRequest->writeLogic(myID, into, checkLaneFoes);
704  return true;
705  }
706  return false;
707 }
708 
709 
710 void
711 NBNode::computeNodeShape(bool leftHand, SUMOReal mismatchThreshold) {
712  if (myHaveCustomPoly) {
713  return;
714  }
715  if (myIncomingEdges.size() == 0 && myOutgoingEdges.size() == 0) {
716  // may be an intermediate step during network editing
717  myPoly.clear();
719  return;
720  }
721  try {
722  NBNodeShapeComputer computer(*this);
723  myPoly = computer.compute(leftHand);
724  if (myPoly.size() > 0) {
725  PositionVector tmp = myPoly;
726  tmp.push_back_noDoublePos(tmp[0]); // need closed shape
727  if (mismatchThreshold >= 0
728  && !tmp.around(myPosition)
729  && tmp.distance(myPosition) > mismatchThreshold) {
730  WRITE_WARNING("Junction shape for '" + myID + "' has distance " + toString(tmp.distance(myPosition)) + " to its given position");
731  }
732  }
733  } catch (InvalidArgument&) {
734  WRITE_WARNING("For node '" + getID() + "': could not compute shape.");
735  // make sure our shape is not empty because our XML schema forbids empty attributes
736  myPoly.clear();
738  }
739 }
740 
741 
742 void
743 NBNode::computeLanes2Lanes(const bool buildCrossingsAndWalkingAreas) {
744  // special case a):
745  // one in, one out, the outgoing has one lane more
746  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1
747  && myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES
748  && myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[0]->getNumLanes() - 1
749  && myIncomingEdges[0] != myOutgoingEdges[0]
750  && myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0])) {
751 
752  NBEdge* incoming = myIncomingEdges[0];
753  NBEdge* outgoing = myOutgoingEdges[0];
754  // check if it's not the turnaround
755  if (incoming->getTurnDestination() == outgoing) {
756  // will be added later or not...
757  return;
758  }
759  for (int i = 0; i < (int) incoming->getNumLanes(); ++i) {
760  incoming->setConnection(i, outgoing, i + 1, NBEdge::L2L_COMPUTED);
761  }
762  incoming->setConnection(0, outgoing, 0, NBEdge::L2L_COMPUTED);
763  return;
764  }
765  // special case b):
766  // two in, one out, the outgoing has the same number of lanes as the sum of the incoming
767  // --> highway on-ramp
768  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 1) {
769  NBEdge* out = myOutgoingEdges[0];
770  NBEdge* in1 = myIncomingEdges[0];
771  NBEdge* in2 = myIncomingEdges[1];
772  if (in1->getNumLanes() + in2->getNumLanes() == out->getNumLanes()
773  && (in1->getStep() <= NBEdge::LANES2EDGES)
774  && (in2->getStep() <= NBEdge::LANES2EDGES)
775  && in1 != out
776  && in2 != out
777  && in1->isConnectedTo(out)
778  && in2->isConnectedTo(out)) {
779  // for internal: check which one is the rightmost
780  SUMOReal a1 = in1->getAngleAtNode(this);
781  SUMOReal a2 = in2->getAngleAtNode(this);
784  if (ccw > cw) {
785  std::swap(in1, in2);
786  }
787  const int outOffset = MAX2(0, out->getFirstNonPedestrianLaneIndex(FORWARD, true));
788  const int in1Offset = MAX2(0, in1->getFirstNonPedestrianLaneIndex(FORWARD, true));
789  const int in2Offset = MAX2(0, in2->getFirstNonPedestrianLaneIndex(FORWARD, true));
790  in1->addLane2LaneConnections(in1Offset, out, outOffset, in1->getNumLanes() - in1Offset, NBEdge::L2L_VALIDATED, true, true);
791  in2->addLane2LaneConnections(in2Offset, out, in1->getNumLanes() + outOffset - in1Offset, in2->getNumLanes() - in2Offset, NBEdge::L2L_VALIDATED, true, true);
792  return;
793  }
794  }
795  // special case c):
796  // one in, two out, the incoming has the same number of lanes as the sum of the outgoing
797  // --> highway off-ramp
798  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 2) {
799  NBEdge* in = myIncomingEdges[0];
800  NBEdge* out1 = myOutgoingEdges[0];
801  NBEdge* out2 = myOutgoingEdges[1];
802  if (in->getNumLanes() == out2->getNumLanes() + out1->getNumLanes()
803  && (in->getStep() <= NBEdge::LANES2EDGES)
804  && in != out1
805  && in != out2
806  && in->isConnectedTo(out1)
807  && in->isConnectedTo(out2)) {
808  // for internal: check which one is the rightmost
809  if (NBContHelper::relative_outgoing_edge_sorter(in)(out2, out1)) {
810  std::swap(out1, out2);
811  }
812  const int inOffset = MAX2(0, in->getFirstNonPedestrianLaneIndex(FORWARD, true));
813  const int out1Offset = MAX2(0, out1->getFirstNonPedestrianLaneIndex(FORWARD, true));
814  const int out2Offset = MAX2(0, out2->getFirstNonPedestrianLaneIndex(FORWARD, true));
815  in->addLane2LaneConnections(inOffset, out1, out1Offset, out1->getNumLanes() - out1Offset, NBEdge::L2L_VALIDATED, true, true);
816  in->addLane2LaneConnections(out1->getNumLanes() + inOffset - out1Offset, out2, out2Offset, out2->getNumLanes() - out2Offset, NBEdge::L2L_VALIDATED, false, true);
817  return;
818  }
819  }
820 
821  // go through this node's outgoing edges
822  // for every outgoing edge, compute the distribution of the node's
823  // incoming edges on this edge when approaching this edge
824  // the incoming edges' steps will then also be marked as LANE2LANE_RECHECK...
825  EdgeVector::reverse_iterator i;
826  for (i = myOutgoingEdges.rbegin(); i != myOutgoingEdges.rend(); i++) {
827  NBEdge* currentOutgoing = *i;
828  // get the information about edges that do approach this edge
829  EdgeVector* approaching = getEdgesThatApproach(currentOutgoing);
830  const unsigned int numApproaching = (unsigned int)approaching->size();
831  if (numApproaching != 0) {
832  ApproachingDivider divider(approaching, currentOutgoing, buildCrossingsAndWalkingAreas);
833  Bresenham::compute(&divider, numApproaching, divider.numAvailableLanes());
834  }
835  delete approaching;
836  }
837  // ... but we may have the case that there are no outgoing edges
838  // In this case, we have to mark the incoming edges as being in state
839  // LANE2LANE( not RECHECK) by hand
840  if (myOutgoingEdges.size() == 0) {
841  for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
842  (*i)->markAsInLane2LaneState();
843  }
844  }
845 
846  // DEBUG
847  //std::cout << "connections at " << getID() << "\n";
848  //for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
849  // const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
850  // for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
851  // std::cout << " " << (*i)->getID() << "_" << (*k).fromLane << " -> " << (*k).toEdge->getID() << "_" << (*k).toLane << "\n";
852  // }
853  //}
854 }
855 
856 
857 EdgeVector*
859  // get the position of the node to get the approaching nodes of
860  EdgeVector::const_iterator i = find(myAllEdges.begin(),
861  myAllEdges.end(), currentOutgoing);
862  // get the first possible approaching edge
864  // go through the list of edges clockwise and add the edges
865  EdgeVector* approaching = new EdgeVector();
866  for (; *i != currentOutgoing;) {
867  // check only incoming edges
868  if ((*i)->getToNode() == this && (*i)->getTurnDestination() != currentOutgoing) {
869  std::vector<int> connLanes = (*i)->getConnectionLanes(currentOutgoing);
870  if (connLanes.size() != 0) {
871  approaching->push_back(*i);
872  }
873  }
875  }
876  return approaching;
877 }
878 
879 
880 void
881 NBNode::replaceOutgoing(NBEdge* which, NBEdge* by, unsigned int laneOff) {
882  // replace the edge in the list of outgoing nodes
883  EdgeVector::iterator i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), which);
884  if (i != myOutgoingEdges.end()) {
885  (*i) = by;
886  i = find(myAllEdges.begin(), myAllEdges.end(), which);
887  (*i) = by;
888  }
889  // replace the edge in connections of incoming edges
890  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); ++i) {
891  (*i)->replaceInConnections(which, by, laneOff);
892  }
893  // replace within the connetion prohibition dependencies
894  replaceInConnectionProhibitions(which, by, 0, laneOff);
895 }
896 
897 
898 void
900  // replace edges
901  unsigned int laneOff = 0;
902  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
903  replaceOutgoing(*i, by, laneOff);
904  laneOff += (*i)->getNumLanes();
905  }
906  // removed SUMOReal occurences
908  // check whether this node belongs to a district and the edges
909  // must here be also remapped
910  if (myDistrict != 0) {
911  myDistrict->replaceOutgoing(which, by);
912  }
913 }
914 
915 
916 void
917 NBNode::replaceIncoming(NBEdge* which, NBEdge* by, unsigned int laneOff) {
918  // replace the edge in the list of incoming nodes
919  EdgeVector::iterator i = find(myIncomingEdges.begin(), myIncomingEdges.end(), which);
920  if (i != myIncomingEdges.end()) {
921  (*i) = by;
922  i = find(myAllEdges.begin(), myAllEdges.end(), which);
923  (*i) = by;
924  }
925  // replace within the connetion prohibition dependencies
926  replaceInConnectionProhibitions(which, by, laneOff, 0);
927 }
928 
929 
930 void
932  // replace edges
933  unsigned int laneOff = 0;
934  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
935  replaceIncoming(*i, by, laneOff);
936  laneOff += (*i)->getNumLanes();
937  }
938  // removed SUMOReal occurences
940  // check whether this node belongs to a district and the edges
941  // must here be also remapped
942  if (myDistrict != 0) {
943  myDistrict->replaceIncoming(which, by);
944  }
945 }
946 
947 
948 
949 void
951  unsigned int whichLaneOff, unsigned int byLaneOff) {
952  // replace in keys
953  NBConnectionProhibits::iterator j = myBlockedConnections.begin();
954  while (j != myBlockedConnections.end()) {
955  bool changed = false;
956  NBConnection c = (*j).first;
957  if (c.replaceFrom(which, whichLaneOff, by, byLaneOff)) {
958  changed = true;
959  }
960  if (c.replaceTo(which, whichLaneOff, by, byLaneOff)) {
961  changed = true;
962  }
963  if (changed) {
964  myBlockedConnections[c] = (*j).second;
965  myBlockedConnections.erase(j);
966  j = myBlockedConnections.begin();
967  } else {
968  j++;
969  }
970  }
971  // replace in values
972  for (j = myBlockedConnections.begin(); j != myBlockedConnections.end(); j++) {
973  NBConnectionVector& prohibiting = (*j).second;
974  for (NBConnectionVector::iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
975  NBConnection& sprohibiting = *k;
976  sprohibiting.replaceFrom(which, whichLaneOff, by, byLaneOff);
977  sprohibiting.replaceTo(which, whichLaneOff, by, byLaneOff);
978  }
979  }
980 }
981 
982 
983 
984 void
986  unsigned int i, j;
987  // check incoming
988  for (i = 0; myIncomingEdges.size() > 0 && i < myIncomingEdges.size() - 1; i++) {
989  j = i + 1;
990  while (j < myIncomingEdges.size()) {
991  if (myIncomingEdges[i] == myIncomingEdges[j]) {
992  myIncomingEdges.erase(myIncomingEdges.begin() + j);
993  } else {
994  j++;
995  }
996  }
997  }
998  // check outgoing
999  for (i = 0; myOutgoingEdges.size() > 0 && i < myOutgoingEdges.size() - 1; i++) {
1000  j = i + 1;
1001  while (j < myOutgoingEdges.size()) {
1002  if (myOutgoingEdges[i] == myOutgoingEdges[j]) {
1003  myOutgoingEdges.erase(myOutgoingEdges.begin() + j);
1004  } else {
1005  j++;
1006  }
1007  }
1008  }
1009  // check all
1010  for (i = 0; myAllEdges.size() > 0 && i < myAllEdges.size() - 1; i++) {
1011  j = i + 1;
1012  while (j < myAllEdges.size()) {
1013  if (myAllEdges[i] == myAllEdges[j]) {
1014  myAllEdges.erase(myAllEdges.begin() + j);
1015  } else {
1016  j++;
1017  }
1018  }
1019  }
1020 }
1021 
1022 
1023 bool
1024 NBNode::hasIncoming(const NBEdge* const e) const {
1025  return find(myIncomingEdges.begin(), myIncomingEdges.end(), e) != myIncomingEdges.end();
1026 }
1027 
1028 
1029 bool
1030 NBNode::hasOutgoing(const NBEdge* const e) const {
1031  return find(myOutgoingEdges.begin(), myOutgoingEdges.end(), e) != myOutgoingEdges.end();
1032 }
1033 
1034 
1035 NBEdge*
1037  EdgeVector edges = myIncomingEdges;
1038  if (find(edges.begin(), edges.end(), e) != edges.end()) {
1039  edges.erase(find(edges.begin(), edges.end(), e));
1040  }
1041  if (edges.size() == 0) {
1042  return 0;
1043  }
1044  if (e->getToNode() == this) {
1045  sort(edges.begin(), edges.end(), NBContHelper::edge_opposite_direction_sorter(e, this));
1046  } else {
1047  sort(edges.begin(), edges.end(), NBContHelper::edge_similar_direction_sorter(e));
1048  }
1049  return edges[0];
1050 }
1051 
1052 
1053 void
1055  const NBConnection& mustStop) {
1056  if (mayDrive.getFrom() == 0 ||
1057  mayDrive.getTo() == 0 ||
1058  mustStop.getFrom() == 0 ||
1059  mustStop.getTo() == 0) {
1060 
1061  WRITE_WARNING("Something went wrong during the building of a connection...");
1062  return; // !!! mark to recompute connections
1063  }
1064  NBConnectionVector conn = myBlockedConnections[mustStop];
1065  conn.push_back(mayDrive);
1066  myBlockedConnections[mustStop] = conn;
1067 }
1068 
1069 
1070 NBEdge*
1071 NBNode::getPossiblySplittedIncoming(const std::string& edgeid) {
1072  unsigned int size = (unsigned int) edgeid.length();
1073  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1074  std::string id = (*i)->getID();
1075  if (id.substr(0, size) == edgeid) {
1076  return *i;
1077  }
1078  }
1079  return 0;
1080 }
1081 
1082 
1083 NBEdge*
1084 NBNode::getPossiblySplittedOutgoing(const std::string& edgeid) {
1085  unsigned int size = (unsigned int) edgeid.length();
1086  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1087  std::string id = (*i)->getID();
1088  if (id.substr(0, size) == edgeid) {
1089  return *i;
1090  }
1091  }
1092  return 0;
1093 }
1094 
1095 
1096 void
1097 NBNode::removeEdge(NBEdge* edge, bool removeFromConnections) {
1098  EdgeVector::iterator i = find(myAllEdges.begin(), myAllEdges.end(), edge);
1099  if (i != myAllEdges.end()) {
1100  myAllEdges.erase(i);
1101  i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge);
1102  if (i != myOutgoingEdges.end()) {
1103  myOutgoingEdges.erase(i);
1104  } else {
1105  i = find(myIncomingEdges.begin(), myIncomingEdges.end(), edge);
1106  if (i != myIncomingEdges.end()) {
1107  myIncomingEdges.erase(i);
1108  } else {
1109  // edge must have been either incoming or outgoing
1110  assert(false);
1111  }
1112  }
1113  if (removeFromConnections) {
1114  for (i = myAllEdges.begin(); i != myAllEdges.end(); ++i) {
1115  (*i)->removeFromConnections(edge);
1116  }
1117  }
1118  }
1119 }
1120 
1121 
1122 Position
1124  Position pos(0, 0);
1125  EdgeVector::const_iterator i;
1126  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1127  NBNode* conn = (*i)->getFromNode();
1128  Position toAdd = conn->getPosition();
1129  toAdd.sub(myPosition);
1130  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1131  pos.add(toAdd);
1132  }
1133  for (i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1134  NBNode* conn = (*i)->getToNode();
1135  Position toAdd = conn->getPosition();
1136  toAdd.sub(myPosition);
1137  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1138  pos.add(toAdd);
1139  }
1140  pos.mul((SUMOReal) - 1.0 / (myIncomingEdges.size() + myOutgoingEdges.size()));
1141  if (pos.x() == 0 && pos.y() == 0) {
1142  pos = Position(1, 0);
1143  }
1144  pos.norm2d();
1145  return pos;
1146 }
1147 
1148 
1149 
1150 void
1152  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1153  (*i)->invalidateConnections();
1154  }
1155 }
1156 
1157 
1158 void
1160  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1161  (*i)->invalidateConnections();
1162  }
1163 }
1164 
1165 
1166 bool
1167 NBNode::mustBrake(const NBEdge* const from, const NBEdge* const to, int fromLane, bool includePedCrossings) const {
1168  // unregulated->does not need to brake
1169  if (myRequest == 0) {
1170  return false;
1171  }
1172  // vehicles which do not have a following lane must always decelerate to the end
1173  if (to == 0) {
1174  return true;
1175  }
1176  // check whether any other connection on this node prohibits this connection
1177  return myRequest->mustBrake(from, to, fromLane, includePedCrossings);
1178 }
1179 
1180 bool
1181 NBNode::mustBrakeForCrossing(const NBEdge* const from, const NBEdge* const to, const NBNode::Crossing& crossing) const {
1182  return myRequest->mustBrakeForCrossing(from, to, crossing);
1183 }
1184 
1185 
1186 bool
1187 NBNode::rightTurnConflict(const NBEdge* from, const NBEdge* to, int fromLane,
1188  const NBEdge* prohibitorFrom, const NBEdge* prohibitorTo, int prohibitorFromLane) const {
1189  return myRequest->rightTurnConflict(from, to, fromLane, prohibitorFrom, prohibitorTo, prohibitorFromLane);
1190 }
1191 
1192 
1193 bool
1194 NBNode::isLeftMover(const NBEdge* const from, const NBEdge* const to) const {
1195  // when the junction has only one incoming edge, there are no
1196  // problems caused by left blockings
1197  if (myIncomingEdges.size() == 1 || myOutgoingEdges.size() == 1) {
1198  return false;
1199  }
1200  SUMOReal fromAngle = from->getAngleAtNode(this);
1201  SUMOReal toAngle = to->getAngleAtNode(this);
1202  SUMOReal cw = GeomHelper::getCWAngleDiff(fromAngle, toAngle);
1203  SUMOReal ccw = GeomHelper::getCCWAngleDiff(fromAngle, toAngle);
1204  std::vector<NBEdge*>::const_iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), from);
1205  do {
1207  } while ((!hasOutgoing(*i) || from->isTurningDirectionAt(*i)) && *i != from);
1208  return cw < ccw && (*i) == to && myOutgoingEdges.size() > 2;
1209 }
1210 
1211 
1212 bool
1213 NBNode::forbids(const NBEdge* const possProhibitorFrom, const NBEdge* const possProhibitorTo,
1214  const NBEdge* const possProhibitedFrom, const NBEdge* const possProhibitedTo,
1215  bool regardNonSignalisedLowerPriority) const {
1216  return myRequest != 0 && myRequest->forbids(possProhibitorFrom, possProhibitorTo,
1217  possProhibitedFrom, possProhibitedTo,
1218  regardNonSignalisedLowerPriority);
1219 }
1220 
1221 
1222 bool
1223 NBNode::foes(const NBEdge* const from1, const NBEdge* const to1,
1224  const NBEdge* const from2, const NBEdge* const to2) const {
1225  return myRequest != 0 && myRequest->foes(from1, to1, from2, to2);
1226 }
1227 
1228 
1229 void
1231  NBEdge* removed, const EdgeVector& incoming,
1232  const EdgeVector& outgoing) {
1233  assert(find(incoming.begin(), incoming.end(), removed) == incoming.end());
1234  bool changed = true;
1235  while (changed) {
1236  changed = false;
1237  NBConnectionProhibits blockedConnectionsTmp = myBlockedConnections;
1238  NBConnectionProhibits blockedConnectionsNew;
1239  // remap in connections
1240  for (NBConnectionProhibits::iterator i = blockedConnectionsTmp.begin(); i != blockedConnectionsTmp.end(); i++) {
1241  const NBConnection& blocker = (*i).first;
1242  const NBConnectionVector& blocked = (*i).second;
1243  // check the blocked connections first
1244  // check whether any of the blocked must be changed
1245  bool blockedChanged = false;
1246  NBConnectionVector newBlocked;
1247  NBConnectionVector::const_iterator j;
1248  for (j = blocked.begin(); j != blocked.end(); j++) {
1249  const NBConnection& sblocked = *j;
1250  if (sblocked.getFrom() == removed || sblocked.getTo() == removed) {
1251  blockedChanged = true;
1252  }
1253  }
1254  // adapt changes if so
1255  for (j = blocked.begin(); blockedChanged && j != blocked.end(); j++) {
1256  const NBConnection& sblocked = *j;
1257  if (sblocked.getFrom() == removed && sblocked.getTo() == removed) {
1258  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1259  !!! newBlocked.push_back(NBConnection(*k, *k));
1260  }*/
1261  } else if (sblocked.getFrom() == removed) {
1262  assert(sblocked.getTo() != removed);
1263  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1264  newBlocked.push_back(NBConnection(*k, sblocked.getTo()));
1265  }
1266  } else if (sblocked.getTo() == removed) {
1267  assert(sblocked.getFrom() != removed);
1268  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1269  newBlocked.push_back(NBConnection(sblocked.getFrom(), *k));
1270  }
1271  } else {
1272  newBlocked.push_back(NBConnection(sblocked.getFrom(), sblocked.getTo()));
1273  }
1274  }
1275  if (blockedChanged) {
1276  blockedConnectionsNew[blocker] = newBlocked;
1277  changed = true;
1278  }
1279  // if the blocked were kept
1280  else {
1281  if (blocker.getFrom() == removed && blocker.getTo() == removed) {
1282  changed = true;
1283  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1284  !!! blockedConnectionsNew[NBConnection(*k, *k)] = blocked;
1285  }*/
1286  } else if (blocker.getFrom() == removed) {
1287  assert(blocker.getTo() != removed);
1288  changed = true;
1289  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1290  blockedConnectionsNew[NBConnection(*k, blocker.getTo())] = blocked;
1291  }
1292  } else if (blocker.getTo() == removed) {
1293  assert(blocker.getFrom() != removed);
1294  changed = true;
1295  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1296  blockedConnectionsNew[NBConnection(blocker.getFrom(), *k)] = blocked;
1297  }
1298  } else {
1299  blockedConnectionsNew[blocker] = blocked;
1300  }
1301  }
1302  }
1303  myBlockedConnections = blockedConnectionsNew;
1304  }
1305  // remap in traffic lights
1306  tc.remapRemoved(removed, incoming, outgoing);
1307 }
1308 
1309 
1311 NBNode::getDirection(const NBEdge* const incoming, const NBEdge* const outgoing) const {
1312  // ok, no connection at all -> dead end
1313  if (outgoing == 0) {
1314  return LINKDIR_NODIR;
1315  }
1316  // turning direction
1317  if (incoming->isTurningDirectionAt(outgoing)) {
1318  return LINKDIR_TURN;
1319  }
1320  // get the angle between incoming/outgoing at the junction
1321  SUMOReal angle =
1322  NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outgoing->getAngleAtNode(this));
1323  // ok, should be a straight connection
1324  if (abs((int) angle) + 1 < 45) {
1325  return LINKDIR_STRAIGHT;
1326  }
1327 
1328  // check for left and right, first
1329  if (angle > 0) {
1330  // check whether any other edge goes further to the right
1331  EdgeVector::const_iterator i =
1332  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1334  while ((*i) != incoming) {
1335  if ((*i)->getFromNode() == this) {
1336  return LINKDIR_PARTRIGHT;
1337  }
1339  }
1340  return LINKDIR_RIGHT;
1341  }
1342  // check whether any other edge goes further to the left
1343  EdgeVector::const_iterator i =
1344  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1346  while ((*i) != incoming) {
1347  if ((*i)->getFromNode() == this && !incoming->isTurningDirectionAt(*i)) {
1348  return LINKDIR_PARTLEFT;
1349  }
1351  }
1352  return LINKDIR_LEFT;
1353 }
1354 
1355 
1356 LinkState
1357 NBNode::getLinkState(const NBEdge* incoming, NBEdge* outgoing, int fromlane,
1358  bool mayDefinitelyPass, const std::string& tlID) const {
1359  if (tlID != "") {
1361  }
1362  if (outgoing == 0) { // always off
1364  }
1366  return LINKSTATE_EQUAL; // all the same
1367  }
1368  if (myType == NODETYPE_ALLWAY_STOP) {
1369  return LINKSTATE_ALLWAY_STOP; // all drive, first one to arrive may drive first
1370  }
1371  if ((!incoming->isInnerEdge() && mustBrake(incoming, outgoing, fromlane, true)) && !mayDefinitelyPass) {
1372  return myType == NODETYPE_PRIORITY_STOP ? LINKSTATE_STOP : LINKSTATE_MINOR; // minor road
1373  }
1374  // traffic lights are not regarded here
1375  return LINKSTATE_MAJOR;
1376 }
1377 
1378 
1379 bool
1381  // check whether this node is included in a traffic light
1382  if (myTrafficLights.size() != 0) {
1383  return false;
1384  }
1385  EdgeVector::const_iterator i;
1386  // one in, one out -> just a geometry ...
1387  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1388  // ... if types match ...
1389  if (!myIncomingEdges[0]->expandableBy(myOutgoingEdges[0])) {
1390  return false;
1391  }
1392  //
1393  return myIncomingEdges[0]->getFromNode() != myOutgoingEdges[0]->getToNode();
1394  }
1395  // two in, two out -> may be something else
1396  if (myOutgoingEdges.size() == 2 && myIncomingEdges.size() == 2) {
1397  // check whether the origin nodes of the incoming edges differ
1398  std::set<NBNode*> origSet;
1399  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1400  origSet.insert((*i)->getFromNode());
1401  }
1402  if (origSet.size() < 2) {
1403  return false;
1404  }
1405  // check whether this node is an intermediate node of
1406  // a two-directional street
1407  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1408  // try to find the opposite direction
1409  NBNode* origin = (*i)->getFromNode();
1410  // find the back direction of the current edge
1411  EdgeVector::const_iterator j =
1412  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1414  // check whether the back direction exists
1415  if (j != myOutgoingEdges.end()) {
1416  // check whether the edge from the backdirection (must be
1417  // the counter-clockwise one) may be joined with the current
1419  // check whether the types allow joining
1420  if (!(*i)->expandableBy(*j)) {
1421  return false;
1422  }
1423  } else {
1424  // ok, at least one outgoing edge is not an opposite
1425  // of an incoming one
1426  return false;
1427  }
1428  }
1429  return true;
1430  }
1431  // ok, a real node
1432  return false;
1433 }
1434 
1435 
1436 std::vector<std::pair<NBEdge*, NBEdge*> >
1438  assert(checkIsRemovable());
1439  std::vector<std::pair<NBEdge*, NBEdge*> > ret;
1440  // one in, one out-case
1441  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1442  ret.push_back(
1443  std::pair<NBEdge*, NBEdge*>(
1445  return ret;
1446  }
1447  // two in, two out-case
1448  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1449  NBNode* origin = (*i)->getFromNode();
1450  EdgeVector::const_iterator j =
1451  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1454  ret.push_back(std::pair<NBEdge*, NBEdge*>(*i, *j));
1455  }
1456  return ret;
1457 }
1458 
1459 
1460 const PositionVector&
1462  return myPoly;
1463 }
1464 
1465 
1466 void
1468  myPoly = shape;
1469  myHaveCustomPoly = (myPoly.size() > 1);
1470 }
1471 
1472 
1473 void
1474 NBNode::setCustomLaneShape(const std::string& laneID, const PositionVector& shape) {
1475  if (shape.size() > 1) {
1476  myCustomLaneShapes[laneID] = shape;
1477  } else {
1478  myCustomLaneShapes.erase(laneID);
1479  }
1480 }
1481 
1482 
1483 NBEdge*
1485  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1486  if ((*i)->getToNode() == n) {
1487  return (*i);
1488  }
1489  }
1490  return 0;
1491 }
1492 
1493 
1494 bool
1496  if (isDistrict()) {
1497  return false;
1498  }
1499  EdgeVector edges;
1500  copy(getIncomingEdges().begin(), getIncomingEdges().end(),
1501  back_inserter(edges));
1502  copy(getOutgoingEdges().begin(), getOutgoingEdges().end(),
1503  back_inserter(edges));
1504  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
1505  NBEdge* t = *j;
1506  NBNode* other = 0;
1507  if (t->getToNode() == this) {
1508  other = t->getFromNode();
1509  } else {
1510  other = t->getToNode();
1511  }
1512  EdgeVector edges2;
1513  copy(other->getIncomingEdges().begin(), other->getIncomingEdges().end(), back_inserter(edges2));
1514  copy(other->getOutgoingEdges().begin(), other->getOutgoingEdges().end(), back_inserter(edges2));
1515  for (EdgeVector::const_iterator k = edges2.begin(); k != edges2.end(); ++k) {
1516  if ((*k)->getFromNode()->isDistrict() || (*k)->getToNode()->isDistrict()) {
1517  return true;
1518  }
1519  }
1520  }
1521  return false;
1522 }
1523 
1524 
1525 bool
1527  return myType == NODETYPE_DISTRICT;
1528 }
1529 
1530 
1531 int
1533  //gDebugFlag1 = getID() == DEBUGID;
1534  int numGuessed = 0;
1535  if (myCrossings.size() > 0) {
1536  // user supplied crossings, do not guess
1537  return numGuessed;
1538  }
1539  if (gDebugFlag1) {
1540  std::cout << "guess crossings for " << getID() << "\n";
1541  }
1543  // check for pedestrial lanes going clockwise around the node
1544  std::vector<std::pair<NBEdge*, bool> > normalizedLanes;
1545  for (EdgeVector::const_iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
1546  NBEdge* edge = *it;
1547  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
1548  if (edge->getFromNode() == this) {
1549  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
1550  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
1551  }
1552  } else {
1553  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
1554  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
1555  }
1556  }
1557  }
1558  // do we even have a pedestrian lane?
1559  int firstSidewalk = -1;
1560  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1561  if (normalizedLanes[i].second) {
1562  firstSidewalk = i;
1563  break;
1564  }
1565  }
1566  if (firstSidewalk != -1) {
1567  // rotate lanes to ensure that the first one allows pedestrians
1568  std::vector<std::pair<NBEdge*, bool> > tmp;
1569  copy(normalizedLanes.begin() + firstSidewalk, normalizedLanes.end(), std::back_inserter(tmp));
1570  copy(normalizedLanes.begin(), normalizedLanes.begin() + firstSidewalk, std::back_inserter(tmp));
1571  normalizedLanes = tmp;
1572  // find candidates
1573  EdgeVector candidates;
1574  bool hadCandidates = false;
1575  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1576  NBEdge* edge = normalizedLanes[i].first;
1577  const bool allowsPed = normalizedLanes[i].second;
1578  if (gDebugFlag1) {
1579  std::cout << " cands=" << toString(candidates) << " edge=" << edge->getID() << " allowsPed=" << allowsPed << "\n";
1580  }
1581  if (!allowsPed && (candidates.size() == 0 || candidates.back() != edge)) {
1582  candidates.push_back(edge);
1583  } else if (allowsPed) {
1584  if (candidates.size() > 0) {
1585  if (hadCandidates || forbidsPedestriansAfter(normalizedLanes, i)) {
1586  hadCandidates = true;
1587  numGuessed += checkCrossing(candidates);
1588  }
1589  candidates.clear();
1590  }
1591  }
1592  }
1593  if (hadCandidates) {
1594  // avoid wrapping around to the same sidewalk
1595  numGuessed += checkCrossing(candidates);
1596  }
1597  }
1599  return numGuessed;
1600 }
1601 
1602 
1603 int
1605  if (gDebugFlag1) {
1606  std::cout << "checkCrossing candidates=" << toString(candidates) << "\n";
1607  }
1608  if (candidates.size() == 0) {
1609  if (gDebugFlag1) {
1610  std::cout << "no crossing added (numCandidates=" << candidates.size() << ")\n";
1611  }
1612  return 0;
1613  } else {
1614  // check whether the edges may be part of a common crossing due to having similar angle
1615  SUMOReal prevAngle = -100000; // dummy
1616  for (size_t i = 0; i < candidates.size(); ++i) {
1617  NBEdge* edge = candidates[i];
1618  SUMOReal angle = edge->getCrossingAngle(this);
1619  // edges should be sorted by angle but this only holds true approximately
1620  if (i > 0 && fabs(angle - prevAngle) > EXTEND_CROSSING_ANGLE_THRESHOLD) {
1621  if (gDebugFlag1) {
1622  std::cout << "no crossing added (found angle difference of " << fabs(angle - prevAngle) << " at i=" << i << "\n";
1623  }
1624  return 0;
1625  }
1627  if (gDebugFlag1) {
1628  std::cout << "no crossing added (uncontrolled, edge with speed=" << edge->getSpeed() << ")\n";
1629  }
1630  return 0;
1631  }
1632  prevAngle = angle;
1633  }
1634  if (candidates.size() == 1) {
1636  if (gDebugFlag1) {
1637  std::cout << "adding crossing: " << toString(candidates) << "\n";
1638  }
1639  return 1;
1640  } else {
1641  // check for intermediate walking areas
1642  SUMOReal prevAngle = -100000; // dummy
1643  for (EdgeVector::iterator it = candidates.begin(); it != candidates.end(); ++it) {
1644  SUMOReal angle = (*it)->getCrossingAngle(this);
1645  if (it != candidates.begin()) {
1646  NBEdge* prev = *(it - 1);
1647  NBEdge* curr = *it;
1648  Position prevPos, currPos;
1649  unsigned int laneI;
1650  // compute distance between candiate edges
1651  SUMOReal intermediateWidth = 0;
1652  if (prev->getToNode() == this) {
1653  laneI = prev->getNumLanes() - 1;
1654  prevPos = prev->getLanes()[laneI].shape[-1];
1655  } else {
1656  laneI = 0;
1657  prevPos = prev->getLanes()[laneI].shape[0];
1658  }
1659  intermediateWidth -= 0.5 * prev->getLaneWidth(laneI);
1660  if (curr->getFromNode() == this) {
1661  laneI = curr->getNumLanes() - 1;
1662  currPos = curr->getLanes()[laneI].shape[0];
1663  } else {
1664  laneI = 0;
1665  currPos = curr->getLanes()[laneI].shape[-1];
1666  }
1667  intermediateWidth -= 0.5 * curr->getLaneWidth(laneI);
1668  intermediateWidth += currPos.distanceTo2D(prevPos);
1669  if (gDebugFlag1) {
1670  std::cout
1671  << " prevAngle=" << prevAngle
1672  << " angle=" << angle
1673  << " intermediateWidth=" << intermediateWidth
1674  << "\n";
1675  }
1676  if (fabs(prevAngle - angle) > SPLIT_CROSSING_ANGLE_THRESHOLD
1677  || (intermediateWidth > SPLIT_CROSSING_WIDTH_THRESHOLD)) {
1678  return checkCrossing(EdgeVector(candidates.begin(), it))
1679  + checkCrossing(EdgeVector(it, candidates.end()));
1680  }
1681  }
1682  prevAngle = angle;
1683  }
1685  if (gDebugFlag1) {
1686  std::cout << "adding crossing: " << toString(candidates) << "\n";
1687  }
1688  return 1;
1689  }
1690  }
1691 }
1692 
1693 
1694 bool
1695 NBNode::forbidsPedestriansAfter(std::vector<std::pair<NBEdge*, bool> > normalizedLanes, int startIndex) {
1696  for (int i = startIndex; i < (int)normalizedLanes.size(); ++i) {
1697  if (!normalizedLanes[i].second) {
1698  return true;
1699  }
1700  }
1701  return false;
1702 }
1703 
1704 
1705 void
1706 NBNode::buildInnerEdges(bool buildCrossingsAndWalkingAreas) {
1707  if (buildCrossingsAndWalkingAreas) {
1708  buildCrossings();
1709  buildWalkingAreas(OptionsCont::getOptions().getInt("junctions.corner-detail"));
1710  // ensure that all crossings are properly connected
1711  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); it++) {
1712  if ((*it).prevWalkingArea == "" || (*it).nextWalkingArea == "") {
1713  // there is no way to check this apart from trying to build all
1714  // walkingAreas and there is no way to recover because the junction
1715  // logic assumes that the crossing can be built.
1716  throw ProcessError("Invalid crossing '" + (*it).id + "' at node '" + getID() + "' with edges '" + toString((*it).edges) + "'.");
1717  }
1718  }
1719  }
1720  // build inner edges for vehicle movements across the junction
1721  unsigned int noInternalNoSplits = 0;
1722  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1723  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
1724  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1725  if ((*k).toEdge == 0) {
1726  continue;
1727  }
1728  noInternalNoSplits++;
1729  }
1730  }
1731  unsigned int lno = 0;
1732  unsigned int splitNo = 0;
1733  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1734  (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
1735  }
1736  // if there are custom lane shapes we need to built twice:
1737  // first to set the ids then to build intersections with the custom geometries
1738  if (myCustomLaneShapes.size() > 0) {
1739  unsigned int lno = 0;
1740  unsigned int splitNo = 0;
1741  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1742  (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
1743  }
1744  }
1745 }
1746 
1747 
1748 unsigned int
1750  //gDebugFlag1 = getID() == DEBUGID;
1751  if (gDebugFlag1) {
1752  std::cout << "build crossings for " << getID() << ":\n";
1753  }
1754  unsigned int index = 0;
1755  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); it++) {
1756  (*it).id = ":" + getID() + "_c" + toString(index++);
1757  EdgeVector& edges = (*it).edges;
1758  if (gDebugFlag1) {
1759  std::cout << " crossing=" << (*it).id << " edges=" << toString(edges);
1760  }
1761  // sorting the edges in the right way is imperative. We want to sort
1762  // them by getAngleAtNodeToCenter() but need to be extra carefull to avoid wrapping around 0 somewhere in between
1763  std::sort(edges.begin(), edges.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
1764  if (gDebugFlag1) {
1765  std::cout << " sortedEdges=" << toString(edges) << "\n";
1766  };
1767  // rotate the edges so that the largest relative angle difference comes at the end
1768  SUMOReal maxAngleDiff = 0;
1769  int maxAngleDiffIndex = 0; // index before maxDist
1770  for (int i = 0; i < (int) edges.size(); i++) {
1771  SUMOReal diff = NBHelpers::relAngle(edges[i]->getAngleAtNodeToCenter(this),
1772  edges[(i + 1) % edges.size()]->getAngleAtNodeToCenter(this));
1773  if (diff < 0) {
1774  diff += 360;
1775  }
1776  if (gDebugFlag1) {
1777  std::cout << " i=" << i << " a1=" << edges[i]->getAngleAtNodeToCenter(this) << " a2=" << edges[(i + 1) % edges.size()]->getAngleAtNodeToCenter(this) << " diff=" << diff << "\n";
1778  }
1779  if (diff > maxAngleDiff) {
1780  maxAngleDiff = diff;
1781  maxAngleDiffIndex = i;
1782  }
1783  }
1784  if (maxAngleDiff > 2 && maxAngleDiff < 360 - 2) {
1785  // if the angle differences is too small, we better not rotate
1786  std::rotate(edges.begin(), edges.begin() + (maxAngleDiffIndex + 1) % edges.size(), edges.end());
1787  if (gDebugFlag1) {
1788  std::cout << " rotatedEdges=" << toString(edges);
1789  }
1790  }
1791  // reverse to get them in CCW order (walking direction around the node)
1792  std::reverse(edges.begin(), edges.end());
1793  if (gDebugFlag1) {
1794  std::cout << " finalEdges=" << toString(edges) << "\n";
1795  }
1796  // compute shape
1797  (*it).shape.clear();
1798  const int begDir = (edges.front()->getFromNode() == this ? FORWARD : BACKWARD);
1799  const int endDir = (edges.back()->getToNode() == this ? FORWARD : BACKWARD);
1800  NBEdge::Lane crossingBeg = edges.front()->getFirstNonPedestrianLane(begDir);
1801  NBEdge::Lane crossingEnd = edges.back()->getFirstNonPedestrianLane(endDir);
1802  crossingBeg.width = (crossingBeg.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingBeg.width);
1803  crossingEnd.width = (crossingEnd.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingEnd.width);
1804  crossingBeg.shape.move2side(begDir * crossingBeg.width / 2);
1805  crossingEnd.shape.move2side(endDir * crossingEnd.width / 2);
1806  crossingBeg.shape.extrapolate((*it).width / 2);
1807  crossingEnd.shape.extrapolate((*it).width / 2);
1808  (*it).shape.push_back(crossingBeg.shape[begDir == FORWARD ? 0 : -1]);
1809  (*it).shape.push_back(crossingEnd.shape[endDir == FORWARD ? -1 : 0]);
1810  }
1811  return index;
1812 }
1813 
1814 
1815 void
1816 NBNode::buildWalkingAreas(int cornerDetail) {
1817  //gDebugFlag1 = getID() == DEBUGID;
1818  unsigned int index = 0;
1819  myWalkingAreas.clear();
1820  if (gDebugFlag1) {
1821  std::cout << "build walkingAreas for " << getID() << ":\n";
1822  }
1823  if (myAllEdges.size() == 0) {
1824  return;
1825  }
1827  // shapes are all pointing away from the intersection
1828  std::vector<std::pair<NBEdge*, NBEdge::Lane> > normalizedLanes;
1829  for (EdgeVector::const_iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
1830  NBEdge* edge = *it;
1831  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
1832  if (edge->getFromNode() == this) {
1833  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
1834  NBEdge::Lane l = *it_l;
1835  l.shape = l.shape.getSubpartByIndex(0, 2);
1837  normalizedLanes.push_back(std::make_pair(edge, l));
1838  }
1839  } else {
1840  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
1841  NBEdge::Lane l = *it_l;
1842  l.shape = l.shape.reverse();
1843  l.shape = l.shape.getSubpartByIndex(0, 2);
1845  normalizedLanes.push_back(std::make_pair(edge, l));
1846  }
1847  }
1848  }
1849  //if (gDebugFlag1) std::cout << " normalizedLanes=" << normalizedLanes.size() << "\n";
1850  // collect [start,cound[ indices in normalizedLanes that belong to a walkingArea
1851  std::vector<std::pair<int, int> > waIndices;
1852  int start = -1;
1853  NBEdge* prevEdge = normalizedLanes.back().first;
1854  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1855  NBEdge* edge = normalizedLanes[i].first;
1856  NBEdge::Lane& l = normalizedLanes[i].second;
1857  if (start == -1) {
1858  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
1859  start = i;
1860  }
1861  } else {
1862  if ((l.permissions & SVC_PEDESTRIAN) == 0 || crossingBetween(edge, prevEdge)) {
1863  waIndices.push_back(std::make_pair(start, i - start));
1864  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
1865  start = i;
1866  } else {
1867  start = -1;
1868  }
1869 
1870  }
1871  }
1872  if (gDebugFlag1) std::cout << " i=" << i << " edge=" << edge->getID() << " start=" << start << " ped=" << ((l.permissions & SVC_PEDESTRIAN) != 0)
1873  << " waI=" << waIndices.size() << " crossingBetween=" << crossingBetween(edge, prevEdge) << "\n";
1874  prevEdge = edge;
1875  }
1876  // deal with wrap-around issues
1877  if (start != - 1) {
1878  const int waNumLanes = (int)normalizedLanes.size() - start;
1879  if (waIndices.size() == 0) {
1880  waIndices.push_back(std::make_pair(start, waNumLanes));
1881  if (gDebugFlag1) {
1882  std::cout << " single wa, end at wrap-around\n";
1883  }
1884  } else {
1885  if (waIndices.front().first == 0) {
1886  NBEdge* edge = normalizedLanes.front().first;
1887  NBEdge* prevEdge = normalizedLanes.back().first;
1888  if (crossingBetween(edge, prevEdge)) {
1889  // do not wrap-around if there is a crossing in between
1890  waIndices.push_back(std::make_pair(start, waNumLanes));
1891  if (gDebugFlag1) {
1892  std::cout << " do not wrap around, turn-around in between\n";
1893  }
1894  } else {
1895  // first walkingArea wraps around
1896  waIndices.front().first = start;
1897  waIndices.front().second = waNumLanes + waIndices.front().second;
1898  if (gDebugFlag1) {
1899  std::cout << " wrapping around\n";
1900  }
1901  }
1902  } else {
1903  // last walkingArea ends at the wrap-around
1904  waIndices.push_back(std::make_pair(start, waNumLanes));
1905  if (gDebugFlag1) {
1906  std::cout << " end at wrap-around\n";
1907  }
1908  }
1909  }
1910  }
1911  if (gDebugFlag1) {
1912  std::cout << " normalizedLanes=" << normalizedLanes.size() << " waIndices:\n";
1913  for (int i = 0; i < (int)waIndices.size(); ++i) {
1914  std::cout << " " << waIndices[i].first << ", " << waIndices[i].second << "\n";
1915  }
1916  }
1917  // build walking areas connected to a sidewalk
1918  for (int i = 0; i < (int)waIndices.size(); ++i) {
1919  const bool buildExtensions = waIndices[i].second != (int)normalizedLanes.size();
1920  const int start = waIndices[i].first;
1921  const int prev = start > 0 ? start - 1 : (int)normalizedLanes.size() - 1;
1922  const int count = waIndices[i].second;
1923  const int end = (start + count) % normalizedLanes.size();
1924 
1925  WalkingArea wa(":" + getID() + "_w" + toString(index++), 1);
1926  if (gDebugFlag1) {
1927  std::cout << "build walkingArea " << wa.id << " start=" << start << " end=" << end << " count=" << count << " prev=" << prev << ":\n";
1928  }
1929  SUMOReal endCrossingWidth = 0;
1930  SUMOReal startCrossingWidth = 0;
1931  PositionVector endCrossingShape;
1932  PositionVector startCrossingShape;
1933  // check for connected crossings
1934  bool connectsCrossing = false;
1935  std::vector<Position> connectedPoints;
1936  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
1937  if (gDebugFlag1) {
1938  std::cout << " crossing=" << (*it).id << " sortedEdges=" << toString((*it).edges) << "\n";
1939  }
1940  if ((*it).edges.back() == normalizedLanes[end].first
1941  && (normalizedLanes[end].second.permissions & SVC_PEDESTRIAN) == 0) {
1942  // crossing ends
1943  (*it).nextWalkingArea = wa.id;
1944  endCrossingWidth = (*it).width;
1945  endCrossingShape = (*it).shape;
1946  wa.width = MAX2(wa.width, endCrossingWidth);
1947  connectsCrossing = true;
1948  connectedPoints.push_back((*it).shape[-1]);
1949  if (gDebugFlag1) {
1950  std::cout << " crossing " << (*it).id << " ends\n";
1951  }
1952  }
1953  if ((*it).edges.front() == normalizedLanes[prev].first
1954  && (normalizedLanes[prev].second.permissions & SVC_PEDESTRIAN) == 0) {
1955  // crossing starts
1956  (*it).prevWalkingArea = wa.id;
1957  wa.nextCrossing = (*it).id;
1958  startCrossingWidth = (*it).width;
1959  startCrossingShape = (*it).shape;
1960  wa.width = MAX2(wa.width, startCrossingWidth);
1961  connectsCrossing = true;
1962  if (isTLControlled()) {
1963  wa.tlID = (*getControllingTLS().begin())->getID();
1964  }
1965  connectedPoints.push_back((*it).shape[0]);
1966  if (gDebugFlag1) {
1967  std::cout << " crossing " << (*it).id << " starts\n";
1968  }
1969  }
1970  if (gDebugFlag1) std::cout << " check connections to crossing " << (*it).id
1971  << " cFront=" << (*it).edges.front()->getID() << " cBack=" << (*it).edges.back()->getID()
1972  << " wEnd=" << normalizedLanes[end].first->getID() << " wStart=" << normalizedLanes[start].first->getID()
1973  << " wStartPrev=" << normalizedLanes[prev].first->getID()
1974  << "\n";
1975  }
1976  if (count < 2 && !connectsCrossing) {
1977  // not relevant for walking
1978  continue;
1979  }
1980  // build shape and connections
1981  std::set<NBEdge*> connected;
1982  for (int j = 0; j < count; ++j) {
1983  const int nlI = (start + j) % normalizedLanes.size();
1984  NBEdge* edge = normalizedLanes[nlI].first;
1985  NBEdge::Lane l = normalizedLanes[nlI].second;
1986  wa.width = MAX2(wa.width, l.width);
1987  if (connected.count(edge) == 0) {
1988  if (edge->getFromNode() == this) {
1989  wa.nextSidewalks.push_back(edge->getID());
1990  connectedPoints.push_back(edge->getLaneShape(0)[0]);
1991  } else {
1992  wa.prevSidewalks.push_back(edge->getID());
1993  connectedPoints.push_back(edge->getLaneShape(0)[-1]);
1994  }
1995  connected.insert(edge);
1996  }
1997  l.shape.move2side(-l.width / 2);
1998  wa.shape.push_back(l.shape[0]);
1999  l.shape.move2side(l.width);
2000  wa.shape.push_back(l.shape[0]);
2001  }
2002  if (buildExtensions) {
2003  // extension at starting crossing
2004  if (startCrossingShape.size() > 0) {
2005  if (gDebugFlag1) {
2006  std::cout << " extension at startCrossing shape=" << startCrossingShape << "\n";
2007  }
2008  startCrossingShape.move2side(startCrossingWidth / 2);
2009  wa.shape.push_front_noDoublePos(startCrossingShape[0]); // right corner
2010  startCrossingShape.move2side(-startCrossingWidth);
2011  wa.shape.push_front_noDoublePos(startCrossingShape[0]); // left corner goes first
2012  }
2013  // extension at ending crossing
2014  if (endCrossingShape.size() > 0) {
2015  if (gDebugFlag1) {
2016  std::cout << " extension at endCrossing shape=" << endCrossingShape << "\n";
2017  }
2018  endCrossingShape.move2side(endCrossingWidth / 2);
2019  wa.shape.push_back_noDoublePos(endCrossingShape[-1]);
2020  endCrossingShape.move2side(-endCrossingWidth);
2021  wa.shape.push_back_noDoublePos(endCrossingShape[-1]);
2022  }
2023  }
2024  if (connected.size() == 2 && !connectsCrossing && wa.nextSidewalks.size() == 1 && wa.prevSidewalks.size() == 1) {
2025  // do not build a walkingArea since a normal connection exists
2026  NBEdge* e1 = *connected.begin();
2027  NBEdge* e2 = *(++connected.begin());
2028  if (e1->hasConnectionTo(e2, 0, 0) || e2->hasConnectionTo(e1, 0, 0)) {
2029  continue;
2030  }
2031  }
2032  // build smooth inner curve (optional)
2033  if (cornerDetail > 0) {
2034  int smoothEnd = end;
2035  int smoothPrev = prev;
2036  // extend to green verge
2037  if (endCrossingWidth > 0 && normalizedLanes[smoothEnd].second.permissions == 0) {
2038  smoothEnd = (smoothEnd + 1) % normalizedLanes.size();
2039  }
2040  if (startCrossingWidth > 0 && normalizedLanes[smoothPrev].second.permissions == 0) {
2041  if (smoothPrev == 0) {
2042  smoothPrev = (int)normalizedLanes.size() - 1;
2043  } else {
2044  smoothPrev--;
2045  }
2046  }
2047  PositionVector begShape = normalizedLanes[smoothEnd].second.shape;
2048  begShape = begShape.reverse();
2049  //begShape.extrapolate(endCrossingWidth);
2050  begShape.move2side(normalizedLanes[smoothEnd].second.width / 2);
2051  PositionVector endShape = normalizedLanes[smoothPrev].second.shape;
2052  endShape.move2side(normalizedLanes[smoothPrev].second.width / 2);
2053  //endShape.extrapolate(startCrossingWidth);
2054  PositionVector curve = computeSmoothShape(begShape, endShape, cornerDetail + 2, false, 25, 25);
2055  if (gDebugFlag1) std::cout
2056  << " end=" << smoothEnd << " prev=" << smoothPrev
2057  << " endCrossingWidth=" << endCrossingWidth << " startCrossingWidth=" << startCrossingWidth
2058  << " begShape=" << begShape << " endShape=" << endShape << " smooth curve=" << curve << "\n";
2059  if (curve.size() > 2) {
2060  curve.eraseAt(0);
2061  curve.eraseAt(-1);
2062  if (endCrossingWidth > 0) {
2063  wa.shape.eraseAt(-1);
2064  }
2065  if (startCrossingWidth > 0) {
2066  wa.shape.eraseAt(0);
2067  }
2068  wa.shape.append(curve, 0);
2069  }
2070  }
2071  // determine length (average of all possible connections)
2072  SUMOReal lengthSum = 0;
2073  int combinations = 0;
2074  for (std::vector<Position>::const_iterator it1 = connectedPoints.begin(); it1 != connectedPoints.end(); ++it1) {
2075  for (std::vector<Position>::const_iterator it2 = connectedPoints.begin(); it2 != connectedPoints.end(); ++it2) {
2076  const Position& p1 = *it1;
2077  const Position& p2 = *it2;
2078  if (p1 != p2) {
2079  lengthSum += p1.distanceTo2D(p2);
2080  combinations += 1;
2081  }
2082  }
2083  }
2084  if (gDebugFlag1) {
2085  std::cout << " combinations=" << combinations << " connectedPoints=" << connectedPoints << "\n";
2086  }
2087  wa.length = POSITION_EPS;
2088  if (combinations > 0) {
2089  wa.length = MAX2(POSITION_EPS, lengthSum / combinations);
2090  }
2091  myWalkingAreas.push_back(wa);
2092  }
2093  // build walkingAreas between split crossings
2094  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2095  Crossing& prev = *it;
2096  Crossing& next = (it != myCrossings.begin() ? * (it - 1) : * (myCrossings.end() - 1));
2097  if (gDebugFlag1) {
2098  std::cout << " checkIntermediate: prev=" << prev.id << " next=" << next.id << " prev.nextWA=" << prev.nextWalkingArea << "\n";
2099  }
2100  if (prev.nextWalkingArea == "") {
2101  WalkingArea wa(":" + getID() + "_w" + toString(index++), prev.width);
2102  prev.nextWalkingArea = wa.id;
2103  wa.nextCrossing = next.id;
2104  next.prevWalkingArea = wa.id;
2105  if (isTLControlled()) {
2106  wa.tlID = (*getControllingTLS().begin())->getID();
2107  }
2108  // back of previous crossing
2109  PositionVector tmp = prev.shape;
2110  tmp.move2side(-prev.width / 2);
2111  wa.shape.push_back(tmp[-1]);
2112  tmp.move2side(prev.width);
2113  wa.shape.push_back(tmp[-1]);
2114  // front of next crossing
2115  tmp = next.shape;
2116  tmp.move2side(prev.width / 2);
2117  wa.shape.push_back(tmp[0]);
2118  tmp.move2side(-prev.width);
2119  wa.shape.push_back(tmp[0]);
2120  // length (special case)
2121  wa.length = MAX2(POSITION_EPS, prev.shape.back().distanceTo2D(next.shape.front()));
2122  myWalkingAreas.push_back(wa);
2123  if (gDebugFlag1) {
2124  std::cout << " build wa=" << wa.id << "\n";
2125  }
2126  }
2127  }
2128 }
2129 
2130 
2131 bool
2132 NBNode::crossingBetween(const NBEdge* e1, const NBEdge* e2) const {
2133  if (e1 == e2) {
2134  return false;
2135  }
2136  for (std::vector<Crossing>::const_iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2137  const EdgeVector& edges = (*it).edges;
2138  EdgeVector::const_iterator it1 = find(edges.begin(), edges.end(), e1);
2139  EdgeVector::const_iterator it2 = find(edges.begin(), edges.end(), e2);
2140  if (it1 != edges.end() && it2 != edges.end()) {
2141  return true;
2142  }
2143  }
2144  return false;
2145 }
2146 
2147 
2148 EdgeVector
2149 NBNode::edgesBetween(const NBEdge* e1, const NBEdge* e2) const {
2150  EdgeVector result;
2151  EdgeVector::const_iterator it = find(myAllEdges.begin(), myAllEdges.end(), e1);
2152  assert(it != myAllEdges.end());
2154  EdgeVector::const_iterator it_end = find(myAllEdges.begin(), myAllEdges.end(), e2);
2155  assert(it_end != myAllEdges.end());
2156  while (it != it_end) {
2157  result.push_back(*it);
2159  }
2160  return result;
2161 }
2162 
2163 
2164 bool
2166  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
2167  return true;
2168  }
2169  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
2170  // check whether the incoming and outgoing edges are pairwise (near) parallel and
2171  // thus the only cross-connections could be turn-arounds
2172  NBEdge* out0 = myOutgoingEdges[0];
2173  NBEdge* out1 = myOutgoingEdges[1];
2174  for (EdgeVector::const_iterator it = myIncomingEdges.begin(); it != myIncomingEdges.end(); ++it) {
2175  NBEdge* inEdge = *it;
2176  SUMOReal angle0 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out0->getAngleAtNode(this)));
2177  SUMOReal angle1 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out1->getAngleAtNode(this)));
2178  if (MAX2(angle0, angle1) <= 160) {
2179  // neither of the outgoing edges is parallel to inEdge
2180  return false;
2181  }
2182  }
2183  return true;
2184  }
2185  return false;
2186 }
2187 
2188 
2189 void
2193  }
2194 }
2195 
2196 
2197 void
2198 NBNode::addCrossing(EdgeVector edges, SUMOReal width, bool priority) {
2199  myCrossings.push_back(Crossing(this, edges, width, priority));
2200 }
2201 
2202 
2203 void
2205  EdgeSet edgeSet(edges.begin(), edges.end());
2206  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end();) {
2207  EdgeSet edgeSet2((*it).edges.begin(), (*it).edges.end());
2208  if (edgeSet == edgeSet2) {
2209  it = myCrossings.erase(it);
2210  } else {
2211  ++it;
2212  }
2213  }
2214 }
2215 
2216 
2217 const NBNode::Crossing&
2218 NBNode::getCrossing(const std::string& id) const {
2219  for (std::vector<Crossing>::const_iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2220  if ((*it).id == id) {
2221  return *it;
2222  }
2223  }
2224  throw ProcessError("Request for unknown crossing '" + id + "'");
2225 }
2226 
2227 
2228 void
2229 NBNode::setCrossingTLIndices(unsigned int startIndex) {
2230  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2231  (*it).tlLinkNo = startIndex++;
2232  }
2233 }
2234 
2235 
2236 int
2238  return myRequest->getSizes().second;
2239 }
2240 
2241 Position
2243  /* Conceptually, the center point would be identical with myPosition.
2244  * However, if the shape is influenced by custom geometry endpoints of the adjoining edges,
2245  * myPosition may fall outside the shape. In this case it is better to use
2246  * the center of the shape
2247  **/
2248  PositionVector tmp = myPoly;
2249  tmp.closePolygon();
2250  //std::cout << getID() << " around=" << tmp.around(myPosition) << " dist=" << tmp.distance(myPosition) << "\n";
2251  if (tmp.size() < 3 || tmp.around(myPosition) || tmp.distance(myPosition) < POSITION_EPS) {
2252  return myPosition;
2253  } else {
2254  return myPoly.getPolygonCenter();
2255  }
2256 }
2257 
2258 
2259 EdgeVector
2261  EdgeVector result = myAllEdges;
2262  if (gDebugFlag1) {
2263  std::cout << " angles:\n";
2264  for (EdgeVector::const_iterator it = result.begin(); it != result.end(); ++it) {
2265  std::cout << " edge=" << (*it)->getID() << " edgeAngle=" << (*it)->getAngleAtNode(this) << " angleToShape=" << (*it)->getAngleAtNodeToCenter(this) << "\n";
2266  }
2267  std::cout << " allEdges before: " << toString(result) << "\n";
2268  }
2269  sort(result.begin(), result.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(this));
2270  // let the first edge in myAllEdges remain the first
2271  if (gDebugFlag1) {
2272  std::cout << " allEdges sorted: " << toString(result) << "\n";
2273  }
2274  rotate(result.begin(), std::find(result.begin(), result.end(), *myAllEdges.begin()), result.end());
2275  if (gDebugFlag1) {
2276  std::cout << " allEdges rotated: " << toString(result) << "\n";
2277  }
2278  return result;
2279 }
2280 
2281 
2282 std::string
2283 NBNode::getNodeIDFromInternalLane(const std::string id) {
2284  // this relies on the fact that internal ids always have the form
2285  // :<nodeID>_<part1>_<part2>
2286  // i.e. :C_3_0, :C_c1_0 :C_w0_0
2287  assert(id[0] == ':');
2288  size_t sep_index = id.rfind('_');
2289  if (sep_index == std::string::npos) {
2290  WRITE_ERROR("Invalid lane id '" + id + "' (missing '_').");
2291  return "";
2292  }
2293  sep_index = id.substr(0, sep_index).rfind('_');
2294  if (sep_index == std::string::npos) {
2295  WRITE_ERROR("Invalid lane id '" + id + "' (missing '_').");
2296  return "";
2297  }
2298  return id.substr(1, sep_index - 1);
2299 }
2300 
2301 
2302 void
2304  // simple case: edges with LANESPREAD_CENTER and a (possible) turndirection at the same node
2305  for (EdgeVector::iterator it = myIncomingEdges.begin(); it != myIncomingEdges.end(); it++) {
2306  NBEdge* edge = *it;
2307  NBEdge* turnDest = edge->getTurnDestination(true);
2308  if (turnDest != 0) {
2309  edge->shiftPositionAtNode(this, turnDest);
2310  turnDest->shiftPositionAtNode(this, edge);
2311  }
2312  }
2313  // @todo: edges in the same direction with sharp angles starting/ending at the same position
2314 }
2315 
2316 /****************************************************************************/
2317 
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:99
std::string id
Definition: NBEdge.h:177
void sub(SUMOReal dx, SUMOReal dy)
Substracts the given position from this one.
Definition: Position.h:139
The link is a partial left direction.
const PositionVector & getLaneShape(unsigned int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:510
void replaceIncoming(NBEdge *which, NBEdge *by, unsigned int laneOff)
Replaces occurences of the first edge within the list of incoming by the second Connections are remap...
Definition: NBNode.cpp:917
const Position & p2() const
Definition: Line.cpp:95
bool hasConnectionTo(NBEdge *destEdge, unsigned int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:759
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges.
Definition: NBNode.h:251
void replaceOutgoing(const EdgeVector &which, NBEdge *const by)
Replaces outgoing edges from the vector (source) by the given edge.
Definition: NBDistrict.cpp:138
Position getEmptyDir() const
Returns something like the most unused direction Should only be used to add source or sink nodes...
Definition: NBNode.cpp:1123
static SUMOReal getCWAngleDiff(SUMOReal angle1, SUMOReal angle2)
Returns the distance of second angle from first angle clockwise.
Definition: GeomHelper.cpp:395
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:148
int toLane
The lane the connections yields in.
Definition: NBEdge.h:166
void setRoundabout()
update the type of this node as a roundabout
Definition: NBNode.cpp:2190
std::vector< Crossing > myCrossings
Vector of crossings.
Definition: NBNode.h:727
Position getCenter() const
Returns a position that is guaranteed to lie within the node shape.
Definition: NBNode.cpp:2242
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:201
SUMOReal width
This lane's width.
Definition: NBNode.h:145
static SUMOReal getCCWAngleDiff(SUMOReal angle1, SUMOReal angle2)
Returns the distance of second angle from first angle counter-clockwise.
Definition: GeomHelper.cpp:385
SUMOReal distance(const Position &p, bool perpendicular=false) const
PositionVector shape
The lane's shape.
Definition: NBEdge.h:128
const SUMOReal SUMO_const_laneWidth
Definition: StdDefs.h:46
virtual void addNode(NBNode *node)
Adds a node to the traffic light logic.
is a pedestrian
bool mustBrakeForCrossing(const NBEdge *const from, const NBEdge *const to, const NBNode::Crossing &crossing) const
Returns the information whether the described flow must brake for the given crossing.
Definition: NBRequest.cpp:747
bool isInStringVector(const std::string &optionName, const std::string &itemName)
Returns the named option is a list of string values containing the specified item.
std::string viaID
Definition: NBEdge.h:182
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:164
#define EXTEND_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:74
Sorts crossings by minimum clockwise clockwise edge angle. Use the ordering found in myAllEdges of th...
Definition: NBAlgorithms.h:119
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset)
patches loaded signal plans by modifying lane indices
Definition: NBNode.cpp:355
std::string id
the (edge)-id of this crossing
Definition: NBNode.h:147
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:119
void norm2d()
Definition: Position.h:158
bool isDistrict() const
Definition: NBNode.cpp:1526
PositionVector myPoly
the (outer) shape of the junction
Definition: NBNode.h:742
NBEdge * getOppositeIncoming(NBEdge *e) const
Definition: NBNode.cpp:1036
void execute(const unsigned int src, const unsigned int dest)
Definition: NBNode.cpp:133
SUMOReal myRadius
the turning radius (for all corners) at this node in m.
Definition: NBNode.h:752
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:733
#define M_PI
Definition: angles.h:37
A container for traffic light definitions and built programs.
SUMOReal length
This lane's width.
Definition: NBNode.h:174
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:261
SUMOReal width
This lane's width.
Definition: NBNode.h:172
static SUMOReal normRelAngle(SUMOReal angle1, SUMOReal angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:76
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:309
~NBNode()
Destructor.
Definition: NBNode.cpp:255
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:450
TrafficLightType getType() const
get the algorithm type (static etc..)
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:510
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:2218
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition: NBNode.cpp:1097
void addIncomingEdge(NBEdge *edge)
adds an incoming edge
Definition: NBNode.cpp:406
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
Line getEndLine() const
Class to sort edges by their angle in relation to the given edge.
Definition: NBContHelper.h:148
bool replaceTo(NBEdge *which, NBEdge *by)
replaces the to-edge by the one given
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:2237
void rotateAtP1(SUMOReal rot)
Definition: Line.cpp:237
ApproachingDivider(EdgeVector *approaching, NBEdge *currentOutgoing, const bool buildCrossingsAndWalkingAreas)
Constructor.
Definition: NBNode.cpp:99
void addCrossing(EdgeVector edges, SUMOReal width, bool priority)
add a pedestrian crossing to this node
Definition: NBNode.cpp:2198
bool hasOutgoing(const NBEdge *const e) const
Returns whether the given edge starts at this node.
Definition: NBNode.cpp:1030
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:2149
bool addLane2LaneConnections(unsigned int fromLane, NBEdge *dest, unsigned int toLane, unsigned int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp:671
bool mustBrake(const NBEdge *const from, const NBEdge *const to, int fromLane, bool includePedCrossings) const
Returns the information whether the described flow must let any other flow pass.
Definition: NBNode.cpp:1167
bool isJoinedTLSControlled() const
Returns whether this node is controlled by a tls that spans over more than one node.
Definition: NBNode.cpp:320
void removeDoubleEdges()
Definition: NBNode.cpp:985
T MAX2(T a, T b)
Definition: StdDefs.h:74
SUMOReal getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:449
void extrapolateFirstBy(SUMOReal length)
Definition: Line.cpp:78
PositionVector shape
The lane's shape.
Definition: NBNode.h:143
#define SPLIT_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:77
PositionVector getSubpartByIndex(int beginIndex, int count) const
void buildWalkingAreas(int cornerDetail)
Definition: NBNode.cpp:1816
static const int MAX_CONNECTIONS
maximum number of connections allowed
Definition: NBNode.h:201
bool isInnerEdge() const
Returns whether this edge was marked as being within an intersection.
Definition: NBEdge.h:874
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:853
std::string id
the (edge)-id of this walkingArea
Definition: NBNode.h:170
SUMOReal distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:229
void eraseAt(int i)
EdgeVector getEdgesSortedByAngleAtNodeCenter() const
returns the list of all edges sorted clockwise by getAngleAtNodeToCenter
Definition: NBNode.cpp:2260
bool checkIsRemovable() const
Definition: NBNode.cpp:1380
void computeLanes2Lanes(const bool buildCrossingsAndWalkingAreas)
computes the connections of lanes to edges
Definition: NBNode.cpp:743
bool around(const Position &p, SUMOReal offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point ...
bool almostSame(const Position &p2, SUMOReal maxDiv=POSITION_EPS) const
Definition: Position.h:223
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:304
void setCustomShape(const PositionVector &shape)
set the junction shape
Definition: NBNode.cpp:1467
The link is controlled by a tls which is off, not blinking, may pass.
NBConnectionProhibits myBlockedConnections
Definition: NBNode.h:736
void writeLogic(std::string key, OutputDevice &into, const bool checkLaneFoes) const
Definition: NBRequest.cpp:334
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1024
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
This is an uncontrolled, all-way stop link.
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:416
NBEdge * getFrom() const
returns the from-edge (start of the connection)
unsigned int numAvailableLanes() const
Definition: NBNode.h:118
#define abs(a)
Definition: polyfonts.c:67
The link is a (hard) left direction.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
The connection was computed and validated.
Definition: NBEdge.h:116
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:67
PositionVector reverse() const
NBRequest * myRequest
Definition: NBNode.h:747
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
CustomShapeMap myCustomLaneShapes
Definition: NBNode.h:754
The link is a straight direction.
SUMOTime getOffset()
Returns the offset.
PositionVector shape
Definition: NBEdge.h:178
NBDistrict * myDistrict
The district the node is the centre of.
Definition: NBNode.h:739
A class representing a single district.
Definition: NBDistrict.h:72
PositionVector computeInternalLaneShape(NBEdge *fromE, const NBEdge::Connection &con, int numPoints=5) const
Compute the shape for an internal lane.
Definition: NBNode.cpp:571
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges.
Definition: NBNode.h:259
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:123
const std::string & getID() const
Returns the id.
Definition: Named.h:60
bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane) const
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBRequest.cpp:645
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition: NBNode.h:724
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:132
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:612
Position getPositionAtDistance(SUMOReal offset) const
Definition: Line.cpp:101
void invalidateIncomingConnections()
Definition: NBNode.cpp:1151
bool isConnectedTo(NBEdge *e)
Returns the information whethe a connection to the given edge has been added (or computed) ...
Definition: NBEdge.cpp:765
void push_front_noDoublePos(const Position &p)
void removeCrossing(const EdgeVector &edges)
remove a pedestrian crossing from this node (identified by its edges)
Definition: NBNode.cpp:2204
const Position & getPosition() const
Returns the position of this node.
Definition: NBNode.h:239
const Position & p1() const
Definition: Line.cpp:89
bool replaceFrom(NBEdge *which, NBEdge *by)
replaces the from-edge by the one given
std::set< NBEdge * > EdgeSet
Definition: NBCont.h:51
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
Definition: NBEdge.h:103
std::string prevWalkingArea
the lane-id of the previous walkingArea
Definition: NBNode.h:149
NBEdge * getPossiblySplittedIncoming(const std::string &edgeid)
Definition: NBNode.cpp:1071
void computeNodeShape(bool leftHand, SUMOReal mismatchThreshold)
Compute the junction shape for this node.
Definition: NBNode.cpp:711
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node.
Definition: NBNode.h:323
bool isSimpleContinuation() const
Definition: NBNode.cpp:426
void buildBitfieldLogic(bool leftHanded)
Definition: NBRequest.cpp:156
int checkCrossing(EdgeVector candidates)
Definition: NBNode.cpp:1604
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:188
std::vector< unsigned int > myAvailableLanes
The available lanes to which connections shall be built.
Definition: NBNode.h:105
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:168
std::string getInternalLaneID() const
Definition: NBEdge.cpp:76
This is an uncontrolled, minor link, has to brake.
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:162
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:1181
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:763
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
unsigned int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:347
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2165
void invalidateOutgoingConnections()
Definition: NBNode.cpp:1159
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:441
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:1756
void removeTrafficLights()
Removes all references to traffic lights that control this tls.
Definition: NBNode.cpp:311
EdgeVector * getEdgesThatApproach(NBEdge *currentOutgoing)
Definition: NBNode.cpp:858
Definition: Line.h:51
std::set< NBTrafficLightDefinition * > myTrafficLights
Definition: NBNode.h:749
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:2297
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:1474
T MIN2(T a, T b)
Definition: StdDefs.h:68
void bezier(int npts, SUMOReal b[], int cpts, SUMOReal p[])
Definition: bezier.cpp:99
PositionVector computeSmoothShape(const PositionVector &begShape, const PositionVector &endShape, int numPoints, bool isTurnaround, SUMOReal extrapolateBeg, SUMOReal extrapolateEnd) const
Compute a smooth curve between the given geometries.
Definition: NBNode.cpp:455
std::string nextCrossing
the lane-id of the next crossing
Definition: NBNode.h:178
void setCrossingTLIndices(unsigned int startIndex)
set tl indices of this nodes crossing starting at the given index
Definition: NBNode.cpp:2229
The link is a (hard) right direction.
#define POSITION_EPS
Definition: config.h:189
PositionVector compute(bool leftHand)
Computes the shape of the assigned junction.
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:53
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1461
T ISNAN(T a)
Definition: StdDefs.h:109
The link is a partial right direction.
static void compute(BresenhamCallBack *callBack, const unsigned int val1, const unsigned int val2)
Definition: Bresenham.cpp:45
NBEdge * getConnectionTo(NBNode *n) const
Definition: NBNode.cpp:1484
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
SUMOReal atan2Angle() const
Definition: Line.cpp:146
virtual void removeNode(NBNode *node)
Removes the given node from the list of controlled nodes.
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition: NBNode.h:718
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:1194
Base class for objects which have an id.
Definition: Named.h:45
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
Definition: NBNode.cpp:1437
bool intersects(const Line &l) const
Definition: Line.cpp:180
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1225
void avoidOverlap()
fix overlap
Definition: NBNode.cpp:2303
NBEdge * getPossiblySplittedOutgoing(const std::string &edgeid)
Definition: NBNode.cpp:1084
unsigned int removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes edges which are both incoming and outgoing into this node.
Definition: NBNode.cpp:363
void extrapolate(SUMOReal val)
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:721
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2255
SUMOReal getCrossingAngle(NBNode *node)
return the angle for computing pedestrian crossings at the given node
Definition: NBEdge.cpp:2314
NBEdge * myCurrentOutgoing
The approached current edge.
Definition: NBNode.h:102
void push_back(const PositionVector &p)
Appends all positions from the given vector.
bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane) const
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBNode.cpp:1187
static const int BACKWARD
Definition: NBNode.h:189
std::string myID
The name of the object.
Definition: Named.h:128
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:371
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:295
void extrapolateSecondBy(SUMOReal length)
Definition: Line.cpp:84
bool isNearDistrict() const
Definition: NBNode.cpp:1495
bool myHaveCustomPoly
whether this nodes shape was set by the user
Definition: NBNode.h:745
SUMOReal length() const
Definition: Line.cpp:192
std::vector< int > getConnectionLanes(NBEdge *currentOutgoing) const
Returns the list of lanes that may be used to reach the given edge.
Definition: NBEdge.cpp:827
Position myPosition
The position the node lies at.
Definition: NBNode.h:715
std::map< NBConnection, NBConnectionVector > NBConnectionProhibits
Definition of a container for connection block dependencies Includes a list of all connections which ...
void replaceOutgoing(NBEdge *which, NBEdge *by, unsigned int laneOff)
Replaces occurences of the first edge within the list of outgoing by the second Connections are remap...
Definition: NBNode.cpp:881
PositionVector viaShape
Definition: NBEdge.h:184
~ApproachingDivider()
Destructor.
Definition: NBNode.cpp:129
std::vector< WalkingArea > myWalkingAreas
Vector of walking areas.
Definition: NBNode.h:730
LinkState getLinkState(const NBEdge *incoming, NBEdge *outgoing, int fromLane, bool mayDefinitelyPass, const std::string &tlID) const
Definition: NBNode.cpp:1357
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
unsigned int buildCrossings()
Definition: NBNode.cpp:1749
bool isLeftHanded() const
Returns whether the built edges are left-handed.
Definition: NBEdgeCont.h:463
void replaceInConnectionProhibitions(NBEdge *which, NBEdge *by, unsigned int whichLaneOff, unsigned int byLaneOff)
Definition: NBNode.cpp:950
The link is controlled by a tls which is off and blinks, has to brake.
std::vector< NBEdge * > EdgeVector
Definition: NBCont.h:41
std::string tlID
the traffic light id of the next crossing or ""
Definition: NBNode.h:180
A definition of a pedestrian walking area.
Definition: NBNode.h:162
EdgeVector * myApproaching
The list of edges that approach the current edge.
Definition: NBNode.h:99
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
A storage for options typed value containers)
Definition: OptionsCont.h:108
void sub(SUMOReal x, SUMOReal y)
Definition: Line.cpp:212
static const SUMOReal DEFAULT_CROSSING_WIDTH
default width of pedetrian crossings
Definition: NBNode.h:191
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:373
void replaceInConnections(NBEdge *which, NBEdge *by, unsigned int laneOff)
Definition: NBEdge.cpp:908
This is an uncontrolled, major link, may pass.
void mul(SUMOReal val)
Multiplies both positions with the given value.
Definition: Position.h:99
std::deque< int > * spread(const std::vector< int > &approachingLanes, int dest) const
Definition: NBNode.cpp:159
NBEdge * getTo() const
returns the to-edge (end of the connection)
Line getBegLine() const
The connection was computed.
Definition: NBEdge.h:112
bool crossingBetween(const NBEdge *e1, const NBEdge *e2) const
return true if the given edges are connected by a crossing
Definition: NBNode.cpp:2132
Represents a single node (junction) during network building.
Definition: NBNode.h:75
static const SUMOReal DEFAULT_RADIUS
the default turning radius at intersections in m
Definition: NBNode.h:194
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
Lane & getLaneStruct(unsigned int lane)
Definition: NBEdge.h:1058
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:431
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
Definition: NBEdge.h:101
SUMOReal distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:240
int guessCrossings()
guess pedestrian crossings and return how many were guessed
Definition: NBNode.cpp:1532
A definition of a pedestrian crossing.
Definition: NBNode.h:134
void move2side(SUMOReal amount)
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
void addSortedLinkFoes(const NBConnection &mayDrive, const NBConnection &mustStop)
Definition: NBNode.cpp:1054
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
#define SUMOReal
Definition: config.h:218
Computes lane-2-lane connections.
Definition: NBNode.h:96
static const SUMOReal UNSPECIFIED_RADIUS
unspecified lane width
Definition: NBNode.h:197
bool writeLogic(OutputDevice &into, const bool checkLaneFoes) const
Definition: NBNode.cpp:701
static SUMOReal relAngle(SUMOReal angle1, SUMOReal angle2)
Definition: NBHelpers.cpp:63
void push_back_noDoublePos(const Position &p)
#define SPLIT_CROSSING_WIDTH_THRESHOLD
Definition: NBNode.cpp:76
void computeLogic(const NBEdgeCont &ec, OptionsCont &oc)
computes the node's type, logic and traffic light
Definition: NBNode.cpp:657
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:431
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
void setConnection(unsigned int lane, NBEdge *destEdge, unsigned int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false)
Adds a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:688
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
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:1223
void buildInnerEdges(bool buildCrossingsAndWalkingAreas)
build internal lanes, pedestrian crossings and walking areas
Definition: NBNode.cpp:1706
void invalidateTLS(NBTrafficLightLogicCont &tlCont)
causes the traffic light to be computed anew
Definition: NBNode.cpp:334
std::string nextWalkingArea
the lane-id of the next walkingArea
Definition: NBNode.h:151
void closePolygon()
ensures that the last position equals the first
Lanes to edges - relationships are computed/loaded.
Definition: NBEdge.h:97
NBNode(const std::string &id, const Position &position, SumoXMLNodeType type)
Constructor.
Definition: NBNode.cpp:232
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:2039
Position intersectsAt(const Line &l) const
Definition: Line.cpp:174
PositionVector getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const
std::vector< std::string > prevSidewalks
the lane-id of the previous sidewalk lane or ""
Definition: NBNode.h:184
void shiftPositionAtNode(NBNode *node, NBEdge *opposite)
shift geometry at the given node to avoid overlap
Definition: NBEdge.cpp:2384
std::vector< std::string > nextSidewalks
the lane-id of the next sidewalk lane or ""
Definition: NBNode.h:182
static void nextCCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
void reshiftPosition(SUMOReal xoff, SUMOReal yoff)
Applies an offset to the node.
Definition: NBNode.cpp:287
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
SUMOReal width
This lane's width.
Definition: NBEdge.h:138
void remapRemoved(NBTrafficLightLogicCont &tc, NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Definition: NBNode.cpp:1230
std::pair< unsigned int, unsigned int > getSizes() const
returns the number of the junction's lanes and the number of the junction's links in respect...
Definition: NBRequest.cpp:412
PositionVector shape
The polygonal shape.
Definition: NBNode.h:176
#define UNCONTROLLED_CROSSING_SPEED_THRESHOLD
Definition: NBNode.cpp:79
void replaceIncoming(const EdgeVector &which, NBEdge *const by)
Replaces incoming edges from the vector (sinks) by the given edge.
Definition: NBDistrict.cpp:106
SUMOReal getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1245
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:1213
The link has no direction (is a dead end link)
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:1695
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing) const
Returns the representation of the described stream's direction.
Definition: NBNode.cpp:1311
static std::string getNodeIDFromInternalLane(const std::string id)
returns the node id for internal lanes, crossings and walkingareas
Definition: NBNode.cpp:2283
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:363