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
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point...
std::pair< int, int > getSizes() const
returns the number of the junction&#39;s lanes and the number of the junction&#39;s links in respect...
Definition: NBRequest.cpp:398
int getConnectionIndex(const NBEdge *from, const NBEdge::Connection &con) const
return the index of the given connection
Definition: NBNode.cpp:2698
The link is a partial left direction.
void replaceOutgoing(const EdgeVector &which, NBEdge *const by)
Replaces outgoing edges from the vector (source) by the given edge.
Definition: NBDistrict.cpp:140
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
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
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
int numNormalConnections() const
return the number of lane-to-lane connections at this junction (excluding crossings) ...
Definition: NBNode.cpp:2683
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
ApproachingDivider(EdgeVector *approaching, NBEdge *currentOutgoing)
Constructor.
Definition: NBNode.cpp:94
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)
double z() const
Returns the z-position.
Definition: Position.h:72
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
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector) ...
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h: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
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1146
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
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
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
A loaded (complete) traffic light logic.
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:66
bool isDistrict() const
check if node is a district
Definition: NBNode.cpp:1786
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:746
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:249
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
~NBNode()
Destructor.
Definition: NBNode.cpp:267
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
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
Some static methods for string processing.
Definition: StringUtils.h:44
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1591
int myCrossingsLoadedFromSumoNet
number of crossings loaded from a sumo net
Definition: NBNode.h:776
This class computes shapes of junctions.
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
Definition: NBNode.cpp:2038
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
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
double y() const
Returns the y-position.
Definition: Position.h:67
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
The representation of a single edge during network building.
Definition: NBEdge.h:70
TrafficLightType getType() const
get the algorithm type (static etc..)
static double getCCWAngleDiff(double angle1, double angle2)
Returns the distance of second angle from first angle counter-clockwise.
Definition: GeomHelper.cpp: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
The link is a 180 degree turn.
static const double UNSPECIFIED_RADIUS
unspecified lane width
Definition: NBNode.h:209
double x() const
Returns the x-position.
Definition: Position.h:62
A container for districts.
The base class for traffic light logic definitions.
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
void buildBitfieldLogic()
Definition: NBRequest.cpp:151
bool isInnerEdge() const
Returns whether this edge was marked as being within an intersection.
Definition: NBEdge.h:952
void removeDoubleEdges()
remove duble edges
Definition: NBNode.cpp:1170
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
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
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
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:2774
Crossing * getCrossing(const std::string &id) const
return the crossing with the given id
Definition: NBNode.cpp:2660
PositionVector shape
The crossing&#39;s shape.
Definition: NBNode.h:139
#define SPLIT_CROSSING_ANGLE_THRESHOLD
Definition: NBNode.cpp:72
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:569
PositionVector reverse() const
reverse position vector
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
NBEdge * getFrom() const
returns the from-edge (start of the connection)
This is an uncontrolled, right-before-left link.
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
void remapConnections(const EdgeVector &incoming)
Remaps the connection in a way that allows the removal of it.
Definition: NBEdge.cpp:1185
std::string id
the (edge)-id of this walkingArea
Definition: NBNode.h:178
#define RAD2DEG(x)
Definition: GeomHelper.h:45
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
bool connectionsDone
Whether connection information for this lane is already completed.
Definition: NBEdge.h:151
const std::string & getID() const
Returns the id.
Definition: Named.h:74
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.
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
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
This is an uncontrolled, all-way stop link.
void addOutgoingEdge(NBEdge *edge)
adds an outgoing edge
Definition: NBNode.cpp:421
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition: NBEdge.cpp:86
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h: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
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
Position getCenter() const
Returns a position that is guaranteed to lie within the node shape.
Definition: NBNode.cpp:2717
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
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:254
#define MIN_WEAVE_LENGTH
Definition: NBNode.cpp:75
NBRequest * myRequest
Node requests.
Definition: NBNode.h:761
int getFirstNonPedestrianLaneIndex(int direction, bool exclusive=false) const
return the first lane with permissions other than SVC_PEDESTRIAN and 0
Definition: NBEdge.cpp:3067
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
double area() const
Returns the area (0 for non-closed)
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
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
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:1744
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
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
void computeLanes2Lanes()
computes the connections of lanes to edges
Definition: NBNode.cpp:803
static void swapWhenReversed(const NBNode *const n, const std::vector< NBEdge *>::iterator &i1, const std::vector< NBEdge *>::iterator &i2)
Assures correct order for same-angle opposite-direction edges.
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:297
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
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
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
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
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
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
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 getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:412
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
A list of positions.
bool addLane2LaneConnections(int fromLane, NBEdge *dest, int toLane, int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp: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
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
bool crossingBetween(const NBEdge *e1, const NBEdge *e2) const
return true if the given edges are connected by a crossing
Definition: NBNode.cpp:2550
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
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
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic, in MSLink and GNEInternalLane.
void removeTrafficLights()
Removes all references to traffic lights that control this tls.
Definition: NBNode.cpp:338
EdgeVector * getEdgesThatApproach(NBEdge *currentOutgoing)
returns a list of edges which are connected to the given outgoing edge
Definition: NBNode.cpp:1043
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:2596
std::set< NBTrafficLightDefinition * > myTrafficLights
traffic lights of node
Definition: NBNode.h:764
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
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:515
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge&#39;s geometry at the given node.
Definition: NBEdge.cpp:1611
bool hasOutgoing(const NBEdge *const e) const
Returns whether the given edge starts at this node.
Definition: NBNode.cpp:1214
bool myDiscardAllCrossings
whether to discard all pedestrian crossings
Definition: NBNode.h:773
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
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
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
PositionVector compute()
Computes the shape of the assigned junction.
double myRadius
the turning radius (for all corners) at this node in m.
Definition: NBNode.h:767
The link is a partial right direction.
double width
This lane&#39;s width.
Definition: NBEdge.h:141
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::set< SVCPermissions > getPermissionVariants(int iStart, int iEnd) const
return all permission variants within the specified lane range [iStart, iEnd[
Definition: NBEdge.cpp:3098
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3025
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
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 checkIsRemovableReporting(std::string &reason) const
check if node is removable and return reason if not
Definition: NBNode.cpp:1640
Base class for objects which have an id.
Definition: Named.h:54
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1208
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
void avoidOverlap()
fix overlap
Definition: NBNode.cpp:2778
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
NBEdge * getPossiblySplittedOutgoing(const std::string &edgeid)
get possibly splitted outgoing edge
Definition: NBNode.cpp:1268
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
const PositionVector & getShape() const
retrieve the junction shape
Definition: NBNode.cpp:1726
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:506
NBEdge * getTo() const
returns the to-edge (end of the connection)
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:731
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
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 getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:522
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:126
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:321
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
Position myPosition
The position the node lies at.
Definition: NBNode.h:725
double length() const
Returns the length.
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
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:778
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:249
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:845
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
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
bool isNearDistrict() const
if node is near district
Definition: NBNode.cpp:1755
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
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
void buildInnerEdges()
build internal lanes, pedestrian crossings and walking areas
Definition: NBNode.cpp:2068
void writeLogic(std::string key, OutputDevice &into, const bool checkLaneFoes) const
Definition: NBRequest.cpp:320
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
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
A storage for options typed value containers)
Definition: OptionsCont.h:98
double angleAt2D(int pos) const
get angle in certain position of position vector
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
Definition: NBEdgeCont.cpp:384
Position getEmptyDir() const
Returns something like the most unused direction Should only be used to add source or sink nodes...
Definition: NBNode.cpp:1311
This is an uncontrolled, major link, may pass.
bool needsCont(const NBEdge *fromE, const NBEdge *otherFromE, const NBEdge::Connection &c, const NBEdge::Connection &otherC) const
whether an internal junction should be built at from and respect other
Definition: NBNode.cpp:653
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
int numAvailableLanes() const
@ get number of avaliable lanes
Definition: NBNode.h:116
EdgeVector getEdgesSortedByAngleAtNodeCenter() const
returns the list of all edges sorted clockwise by getAngleAtNodeToCenter
Definition: NBNode.cpp:2735
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2450
The connection was computed.
Definition: NBEdge.h:110
const Position & getPosition() const
Definition: NBNode.h:241
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:137
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.
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
void addSortedLinkFoes(const NBConnection &mayDrive, const NBConnection &mustStop)
add shorted link FOES
Definition: NBNode.cpp:1238
EdgeVector getConnectedEdges() const
Returns the list of outgoing edges unsorted.
Definition: NBEdge.cpp:1134
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 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
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition: NBNode.cpp:1220
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
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
#define SPLIT_CROSSING_WIDTH_THRESHOLD
Definition: NBNode.cpp:71
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:426
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
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
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn&#39;t set.
Definition: NBEdge.h:489
#define DEBUGCOND
Definition: NBNode.cpp:79
void add(double xoff, double yoff, double zoff)
std::string nextWalkingArea
the lane-id of the next walkingArea
Definition: NBNode.h:149
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::deque< int > * spread(const std::vector< int > &approachingLanes, int dest) const
the method that spreads the wished number of lanes from the the lane given by the bresenham-call to b...
Definition: NBNode.cpp:152
void closePolygon()
ensures that the last position equals the first
Lanes to edges - relationships are computed/loaded.
Definition: NBEdge.h:95
bool checkIsRemovable() const
check if node is removable
Definition: NBNode.cpp:1634
NBNode(const std::string &id, const Position &position, SumoXMLNodeType type)
Constructor.
Definition: NBNode.cpp:236
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
Definition: NBNode.cpp:1703
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
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:433
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
static void nextCCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
bool isSimpleContinuation(bool checkLaneNumbers=true) const
check if node is a simple continuation
Definition: NBNode.cpp:431
void reshiftPosition(double xoff, double yoff)
Applies an offset to the node.
Definition: NBNode.cpp:299
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
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
void replaceIncoming(const EdgeVector &which, NBEdge *const by)
Replaces incoming edges from the vector (sinks) by the given edge.
Definition: NBDistrict.cpp:108
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
EdgeVector edgesBetween(const NBEdge *e1, const NBEdge *e2) const
return all edges that lie clockwise between the given edges
Definition: NBNode.cpp:2571
static std::string getNodeIDFromInternalLane(const std::string id)
returns the node id for internal lanes, crossings and walkingareas
Definition: NBNode.cpp:2758