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