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