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