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