SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBNode.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // The representation of a single node
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
13 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <string>
35 #include <map>
36 #include <cassert>
37 #include <algorithm>
38 #include <vector>
39 #include <deque>
40 #include <set>
41 #include <cmath>
42 #include <iterator>
46 #include <utils/geom/Line.h>
47 #include <utils/geom/GeomHelper.h>
48 #include <utils/geom/bezier.h>
50 #include <utils/common/StdDefs.h>
51 #include <utils/common/ToString.h>
54 #include <iomanip>
55 #include "NBNode.h"
56 #include "NBAlgorithms.h"
57 #include "NBNodeCont.h"
58 #include "NBNodeShapeComputer.h"
59 #include "NBEdgeCont.h"
60 #include "NBTypeCont.h"
61 #include "NBHelpers.h"
62 #include "NBDistrict.h"
63 #include "NBContHelper.h"
64 #include "NBRequest.h"
65 #include "NBOwnTLDef.h"
68 
69 #ifdef CHECK_MEMORY_LEAKS
70 #include <foreign/nvwa/debug_new.h>
71 #endif // CHECK_MEMORY_LEAKS
72 
73 // allow to extend a crossing across multiple edges
74 #define EXTEND_CROSSING_ANGLE_THRESHOLD 35.0 // degrees
75 // create intermediate walking areas if either of the following thresholds is exceeded
76 #define SPLIT_CROSSING_WIDTH_THRESHOLD 1.5 // meters
77 #define SPLIT_CROSSING_ANGLE_THRESHOLD 5 // degrees
78 // do not build uncontrolled crossings across edges with a speed above the threshold
79 #define UNCONTROLLED_CROSSING_SPEED_THRESHOLD 13.89 // meters/second
80 
81 // ===========================================================================
82 // static members
83 // ===========================================================================
84 const int NBNode::MAX_CONNECTIONS(64);
85 const int NBNode::FORWARD(1);
86 const int NBNode::BACKWARD(-1);
88 
89 // ===========================================================================
90 // method definitions
91 // ===========================================================================
92 /* -------------------------------------------------------------------------
93  * NBNode::ApproachingDivider-methods
94  * ----------------------------------------------------------------------- */
96  EdgeVector* approaching, NBEdge* currentOutgoing, const bool buildCrossingsAndWalkingAreas) :
97  myApproaching(approaching), myCurrentOutgoing(currentOutgoing) {
98  // check whether origin lanes have been given
99  assert(myApproaching != 0);
100  // collect lanes which are expliclity targeted
101  std::set<int> approachedLanes;
102  for (EdgeVector::iterator it = myApproaching->begin(); it != myApproaching->end(); ++it) {
103  const std::vector<NBEdge::Connection> conns = (*it)->getConnections();
104  for (std::vector<NBEdge::Connection>::const_iterator it_con = conns.begin(); it_con != conns.end(); ++it_con) {
105  if ((*it_con).toEdge == myCurrentOutgoing) {
106  approachedLanes.insert((*it_con).toLane);
107  }
108  }
109  }
110  // compute the indices of lanes that should be targeted (excluding pedestrian
111  // lanes that will be connected from walkingAreas and forbidden lanes)
112  // if the lane is targeted by an explicitly set connection we need
113  // to make it available anyway
114  for (int i = 0; i < (int)currentOutgoing->getNumLanes(); ++i) {
115  if (((buildCrossingsAndWalkingAreas && currentOutgoing->getPermissions(i) == SVC_PEDESTRIAN)
116  || isForbidden(currentOutgoing->getPermissions(i)))
117  && approachedLanes.count(i) == 0) {
118  continue;
119  }
120  myAvailableLanes.push_back((unsigned int)i);
121  }
122 }
123 
124 
126 
127 
128 void
129 NBNode::ApproachingDivider::execute(const unsigned int src, const unsigned int dest) {
130  assert(myApproaching->size() > src);
131  // get the origin edge
132  NBEdge* incomingEdge = (*myApproaching)[src];
133  if (incomingEdge->getStep() == NBEdge::LANES2LANES_DONE || incomingEdge->getStep() == NBEdge::LANES2LANES_USER) {
134  return;
135  }
136  std::vector<int> approachingLanes =
137  incomingEdge->getConnectionLanes(myCurrentOutgoing);
138  assert(approachingLanes.size() != 0);
139  std::deque<int>* approachedLanes = spread(approachingLanes, dest);
140  assert(approachedLanes->size() <= myAvailableLanes.size());
141  // set lanes
142  for (unsigned int i = 0; i < approachedLanes->size(); i++) {
143  assert(approachedLanes->size() > i);
144  assert(approachingLanes.size() > i);
145  unsigned int approached = myAvailableLanes[(*approachedLanes)[i]];
146  //std::cout << "setting connection from " << incomingEdge->getID() << "_" << approachingLanes[i] << " to " << myCurrentOutgoing->getID() << "_" << approached << "\n";
147  incomingEdge->setConnection((unsigned int) approachingLanes[i], myCurrentOutgoing,
148  approached, NBEdge::L2L_COMPUTED);
149  }
150  delete approachedLanes;
151 }
152 
153 
154 std::deque<int>*
155 NBNode::ApproachingDivider::spread(const std::vector<int>& approachingLanes,
156  int dest) const {
157  std::deque<int>* ret = new std::deque<int>();
158  unsigned int noLanes = (unsigned int) approachingLanes.size();
159  // when only one lane is approached, we check, whether the SUMOReal-value
160  // is assigned more to the left or right lane
161  if (noLanes == 1) {
162  ret->push_back(dest);
163  return ret;
164  }
165 
166  unsigned int noOutgoingLanes = (unsigned int)myAvailableLanes.size();
167  //
168  ret->push_back(dest);
169  unsigned int noSet = 1;
170  int roffset = 1;
171  int loffset = 1;
172  while (noSet < noLanes) {
173  // It may be possible, that there are not enough lanes the source
174  // lanes may be divided on
175  // In this case, they remain unset
176  // !!! this is only a hack. It is possible, that this yields in
177  // uncommon divisions
178  if (noOutgoingLanes == noSet) {
179  return ret;
180  }
181 
182  // as due to the conversion of SUMOReal->uint the numbers will be lower
183  // than they should be, we try to append to the left side first
184  //
185  // check whether the left boundary of the approached street has
186  // been overridden; if so, move all lanes to the right
187  if (dest + loffset >= static_cast<int>(noOutgoingLanes)) {
188  loffset -= 1;
189  roffset += 1;
190  for (unsigned int i = 0; i < ret->size(); i++) {
191  (*ret)[i] = (*ret)[i] - 1;
192  }
193  }
194  // append the next lane to the left of all edges
195  // increase the position (destination edge)
196  ret->push_back(dest + loffset);
197  noSet++;
198  loffset += 1;
199 
200  // as above
201  if (noOutgoingLanes == noSet) {
202  return ret;
203  }
204 
205  // now we try to append the next lane to the right side, when needed
206  if (noSet < noLanes) {
207  // check whether the right boundary of the approached street has
208  // been overridden; if so, move all lanes to the right
209  if (dest < roffset) {
210  loffset += 1;
211  roffset -= 1;
212  for (unsigned int i = 0; i < ret->size(); i++) {
213  (*ret)[i] = (*ret)[i] + 1;
214  }
215  }
216  ret->push_front(dest - roffset);
217  noSet++;
218  roffset += 1;
219  }
220  }
221  return ret;
222 }
223 
224 
225 /* -------------------------------------------------------------------------
226  * NBNode-methods
227  * ----------------------------------------------------------------------- */
228 NBNode::NBNode(const std::string& id, const Position& position,
229  SumoXMLNodeType type) :
230  Named(StringUtils::convertUmlaute(id)),
231  myPosition(position),
232  myType(type),
233  myDistrict(0),
234  myHaveCustomPoly(false),
235  myRequest(0)
236 { }
237 
238 
239 NBNode::NBNode(const std::string& id, const Position& position, NBDistrict* district) :
240  Named(StringUtils::convertUmlaute(id)),
241  myPosition(position),
242  myType(district == 0 ? NODETYPE_UNKNOWN : NODETYPE_DISTRICT),
243  myDistrict(district),
244  myHaveCustomPoly(false),
245  myRequest(0)
246 { }
247 
248 
250  delete myRequest;
251 }
252 
253 
254 void
256  bool updateEdgeGeometries) {
257  myPosition = position;
258  // patch type
259  myType = type;
262  }
263  if (updateEdgeGeometries) {
264  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
265  PositionVector geom = (*i)->getGeometry();
266  geom[-1] = myPosition;
267  (*i)->setGeometry(geom);
268  }
269  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
270  PositionVector geom = (*i)->getGeometry();
271  geom[0] = myPosition;
272  (*i)->setGeometry(geom);
273  }
274  }
275 }
276 
277 
278 
279 // ----------- Applying offset
280 void
282  myPosition.add(xoff, yoff, 0);
283  myPoly.add(xoff, yoff, 0);
284 }
285 
286 
287 // ----------- Methods for dealing with assigned traffic lights
288 void
290  myTrafficLights.insert(tlDef);
293  }
294 }
295 
296 
297 void
299  tlDef->removeNode(this);
300  myTrafficLights.erase(tlDef);
301 }
302 
303 
304 void
306  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
307  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
308  removeTrafficLight(*i);
309  }
310 }
311 
312 
313 bool
315  if (!isTLControlled()) {
316  return false;
317  }
318  for (std::set<NBTrafficLightDefinition*>::const_iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
319  if ((*i)->getID().find("joined") == 0) {
320  return true;
321  }
322  }
323  return false;
324 }
325 
326 
327 void
329  if (isTLControlled()) {
330  std::set<NBTrafficLightDefinition*> oldDefs(myTrafficLights);
331  for (std::set<NBTrafficLightDefinition*>::iterator it = oldDefs.begin(); it != oldDefs.end(); ++it) {
332  NBTrafficLightDefinition* orig = *it;
333  if (dynamic_cast<NBOwnTLDef*>(orig) == 0) {
334  NBTrafficLightDefinition* newDef = new NBOwnTLDef(orig->getID(), orig->getOffset(), orig->getType());
335  const std::vector<NBNode*>& nodes = orig->getNodes();
336  while (!nodes.empty()) {
337  nodes.front()->removeTrafficLight(orig);
338  newDef->addNode(nodes.front());
339  }
340  tlCont.removeFully(orig->getID());
341  tlCont.insert(newDef);
342  }
343  }
344  }
345 }
346 
347 
348 void
350  for (std::set<NBTrafficLightDefinition*>::iterator it = myTrafficLights.begin(); it != myTrafficLights.end(); ++it) {
351  (*it)->shiftTLConnectionLaneIndex(edge, offset);
352  }
353 }
354 
355 // ----------- Prunning the input
356 unsigned int
358  unsigned int ret = 0;
359  unsigned int pos = 0;
360  EdgeVector::const_iterator j = myIncomingEdges.begin();
361  while (j != myIncomingEdges.end()) {
362  // skip edges which are only incoming and not outgoing
363  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), *j) == myOutgoingEdges.end()) {
364  ++j;
365  ++pos;
366  continue;
367  }
368  // an edge with both its origin and destination being the current
369  // node should be removed
370  NBEdge* dummy = *j;
371  WRITE_WARNING(" Removing self-looping edge '" + dummy->getID() + "'");
372  // get the list of incoming edges connected to the self-loop
373  EdgeVector incomingConnected;
374  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
375  if ((*i)->isConnectedTo(dummy) && *i != dummy) {
376  incomingConnected.push_back(*i);
377  }
378  }
379  // get the list of outgoing edges connected to the self-loop
380  EdgeVector outgoingConnected;
381  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
382  if (dummy->isConnectedTo(*i) && *i != dummy) {
383  outgoingConnected.push_back(*i);
384  }
385  }
386  // let the self-loop remap its connections
387  dummy->remapConnections(incomingConnected);
388  remapRemoved(tc, dummy, incomingConnected, outgoingConnected);
389  // delete the self-loop
390  ec.erase(dc, dummy);
391  j = myIncomingEdges.begin() + pos;
392  ++ret;
393  }
394  return ret;
395 }
396 
397 
398 // -----------
399 void
401  assert(edge != 0);
402  if (find(myIncomingEdges.begin(), myIncomingEdges.end(), edge) == myIncomingEdges.end()) {
403  myIncomingEdges.push_back(edge);
404  myAllEdges.push_back(edge);
405  }
406 }
407 
408 
409 void
411  assert(edge != 0);
412  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge) == myOutgoingEdges.end()) {
413  myOutgoingEdges.push_back(edge);
414  myAllEdges.push_back(edge);
415  }
416 }
417 
418 
419 bool
421  // one in, one out->continuation
422  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
423  // both must have the same number of lanes
424  return (*(myIncomingEdges.begin()))->getNumLanes() == (*(myOutgoingEdges.begin()))->getNumLanes();
425  }
426  // two in and two out and both in reverse direction
427  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
428  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
429  NBEdge* in = *i;
430  EdgeVector::const_iterator opposite = find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(), NBContHelper::opposite_finder(in, this));
431  // must have an opposite edge
432  if (opposite == myOutgoingEdges.end()) {
433  return false;
434  }
435  // both must have the same number of lanes
437  if (in->getNumLanes() != (*opposite)->getNumLanes()) {
438  return false;
439  }
440  }
441  return true;
442  }
443  // nope
444  return false;
445 }
446 
447 
450  NBEdge* toE, int toL, int numPoints) const {
451  if (fromL >= (int) fromE->getNumLanes()) {
452  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' starts at a not existing lane.");
453  }
454  if (toL >= (int) toE->getNumLanes()) {
455  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' yields in a not existing lane.");
456  }
457  bool noSpline = false;
458  PositionVector ret;
459  PositionVector init;
460  Position beg = fromE->getLaneShape(fromL).back();
461  Position end = toE->getLaneShape(toL).front();
462  Position intersection;
463  unsigned int noInitialPoints = 0;
464  if (beg.distanceTo(end) <= POSITION_EPS) {
465  noSpline = true;
466  } else {
467  if (fromE->getTurnDestination() == toE) {
468  // turnarounds:
469  // - end of incoming lane
470  // - position between incoming/outgoing end/begin shifted by the distance orthogonally
471  // - begin of outgoing lane
472  noInitialPoints = 3;
473  init.push_back(beg);
474  Line straightConn(fromE->getLaneShape(fromL)[-1], toE->getLaneShape(toL)[0]);
475  Position straightCenter = straightConn.getPositionAtDistance((SUMOReal) straightConn.length() / (SUMOReal) 2.);
476  Position center = straightCenter;//.add(straightCenter);
477  Line cross(straightConn);
478  cross.sub(cross.p1().x(), cross.p1().y());
479  cross.rotateAtP1(M_PI / 2);
480  center.sub(cross.p2());
481  init.push_back(center);
482  init.push_back(end);
483  } else {
484  const SUMOReal angle = fabs(fromE->getLaneShape(fromL).getEndLine().atan2Angle() - toE->getLaneShape(toL).getBegLine().atan2Angle());
485  if (angle < M_PI / 4. || angle > 7. / 4.*M_PI) {
486  // very low angle: almost straight
487  noInitialPoints = 4;
488  init.push_back(beg);
489  Line begL = fromE->getLaneShape(fromL).getEndLine();
490  begL.extrapolateSecondBy(100);
491  Line endL = toE->getLaneShape(toL).getBegLine();
492  endL.extrapolateFirstBy(100);
493  SUMOReal distance = beg.distanceTo(end);
494  if (distance > 10) {
495  {
496  SUMOReal off1 = fromE->getLaneShape(fromL).getEndLine().length() + (SUMOReal) 5. * (SUMOReal) fromE->getNumLanes();
497  off1 = MIN2(off1, (SUMOReal)(fromE->getLaneShape(fromL).getEndLine().length() + distance / 2.));
498  Position tmp = begL.getPositionAtDistance(off1);
499  init.push_back(tmp);
500  }
501  {
502  SUMOReal off1 = (SUMOReal) 100. - (SUMOReal) 5. * (SUMOReal) toE->getNumLanes();
503  off1 = MAX2(off1, (SUMOReal)(100. - distance / 2.));
504  Position tmp = endL.getPositionAtDistance(off1);
505  init.push_back(tmp);
506  }
507  } else {
508  noSpline = true;
509  }
510  init.push_back(end);
511  } else {
512  // turning
513  // - end of incoming lane
514  // - intersection of the extrapolated lanes
515  // - begin of outgoing lane
516  // attention: if there is no intersection, use a straight line
517  noInitialPoints = 3;
518  init.push_back(beg);
519  Line begL = fromE->getLaneShape(fromL).getEndLine();
520  Line endL = toE->getLaneShape(toL).getBegLine();
521  bool check = !begL.p1().almostSame(begL.p2()) && !endL.p1().almostSame(endL.p2());
522  if (check) {
523  begL.extrapolateSecondBy(100);
524  endL.extrapolateFirstBy(100);
525  } else {
526  WRITE_WARNING("Could not use edge geometry for internal lane, node '" + getID() + "'.");
527  }
528  if (!check || !begL.intersects(endL)) {
529  noSpline = true;
530  } else {
531  init.push_back(begL.intersectsAt(endL));
532  }
533  init.push_back(end);
534  }
535  }
536  }
537  //
538  if (noSpline) {
539  ret.push_back(fromE->getLaneShape(fromL).back());
540  ret.push_back(toE->getLaneShape(toL).front());
541  } else {
542  SUMOReal* def = new SUMOReal[1 + noInitialPoints * 3];
543  for (int i = 0; i < (int) init.size(); ++i) {
544  // starts at index 1
545  def[i * 3 + 1] = init[i].x();
546  def[i * 3 + 2] = 0;
547  def[i * 3 + 3] = init[i].y();
548  }
549  SUMOReal* ret_buf = new SUMOReal[numPoints * 3 + 1];
550  bezier(noInitialPoints, def, numPoints, ret_buf);
551  delete[] def;
552  Position prev;
553  for (int i = 0; i < (int) numPoints; i++) {
554  Position current(ret_buf[i * 3 + 1], ret_buf[i * 3 + 3]);
555  if (prev != current) {
556  ret.push_back(current);
557  }
558  prev = current;
559  }
560  delete[] ret_buf;
561  }
562  const NBEdge::Lane& lane = fromE->getLaneStruct(fromL);
563  if (lane.endOffset > 0) {
564  PositionVector beg = lane.shape.getSubpart(lane.shape.length() - lane.endOffset, lane.shape.length());;
565  beg.append(ret);
566  ret = beg;
567  }
568  return ret;
569 }
570 
571 
572 bool
573 NBNode::needsCont(NBEdge* fromE, NBEdge* toE, NBEdge* otherFromE, NBEdge* otherToE, const NBEdge::Connection& c) const {
575  return false;
576  }
577  if (fromE == otherFromE) {
578  // ignore same edge links
579  return false;
580  }
581  if (!foes(otherFromE, otherToE, fromE, toE)) {
582  // if they do not cross, no waiting place is needed
583  return false;
584  }
585  LinkDirection d1 = getDirection(fromE, toE);
586  LinkDirection d2 = getDirection(otherFromE, otherToE);
587  bool thisLeft = (d1 == LINKDIR_LEFT || d1 == LINKDIR_TURN);
588  bool otherLeft = (d2 == LINKDIR_LEFT || d2 == LINKDIR_TURN);
589  bool bothLeft = thisLeft && otherLeft;
590  if (c.tlID != "" && !bothLeft) {
591  // tls-controlled links will have space
592  return true;
593  }
594  if (fromE->getJunctionPriority(this) > 0 && otherFromE->getJunctionPriority(this) > 0) {
595  return mustBrake(fromE, toE, c.toLane);
596  }
597  return false;
598 }
599 
600 
601 void
603  delete myRequest; // possibly recomputation step
604  myRequest = 0;
605  if (myIncomingEdges.size() == 0 || myOutgoingEdges.size() == 0) {
606  // no logic if nothing happens here
608  return;
609  }
610  // check whether the node was set to be unregulated by the user
611  if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", getID())
612  || (oc.getBool("keep-nodes-unregulated.district-nodes") && (isNearDistrict() || isDistrict()))) {
614  return;
615  }
616  // compute the logic if necessary or split the junction
618  // build the request
620  // check whether it is not too large
621  unsigned int numConnections = numNormalConnections();
622  if (numConnections >= MAX_CONNECTIONS) {
623  // yep -> make it untcontrolled, warn
624  WRITE_WARNING("Junction '" + getID() + "' is too complicated (#links>64); will be set to unregulated.");
625  delete myRequest;
626  myRequest = 0;
628  } else if (numConnections == 0) {
629  delete myRequest;
630  myRequest = 0;
632  } else {
634  }
635  }
636 }
637 
638 
639 bool
640 NBNode::writeLogic(OutputDevice& into, const bool checkLaneFoes) const {
641  if (myRequest) {
642  myRequest->writeLogic(myID, into, checkLaneFoes);
643  return true;
644  }
645  return false;
646 }
647 
648 
649 void
650 NBNode::computeNodeShape(bool leftHand, SUMOReal mismatchThreshold) {
651  if (myHaveCustomPoly) {
652  return;
653  }
654  if (myIncomingEdges.size() == 0 && myOutgoingEdges.size() == 0) {
655  // may be an intermediate step during network editing
656  myPoly.clear();
658  return;
659  }
660  try {
661  NBNodeShapeComputer computer(*this);
662  myPoly = computer.compute(leftHand);
663  if (myPoly.size() > 0) {
664  PositionVector tmp = myPoly;
665  tmp.push_back_noDoublePos(tmp[0]); // need closed shape
666  if (mismatchThreshold >= 0
667  && !tmp.around(myPosition)
668  && tmp.distance(myPosition) > mismatchThreshold) {
669  WRITE_WARNING("Junction shape for '" + myID + "' has distance " + toString(tmp.distance(myPosition)) + " to its given position");
670  }
671  }
672  } catch (InvalidArgument&) {
673  WRITE_WARNING("For node '" + getID() + "': could not compute shape.");
674  // make sure our shape is not empty because our XML schema forbids empty attributes
675  myPoly.clear();
677  }
678 }
679 
680 
681 void
682 NBNode::computeLanes2Lanes(const bool buildCrossingsAndWalkingAreas) {
683  // special case a):
684  // one in, one out, the outgoing has one lane more
685  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1
686  && myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[0]->getNumLanes() - 1
687  && myIncomingEdges[0] != myOutgoingEdges[0]
688  && myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0])) {
689 
690  NBEdge* incoming = myIncomingEdges[0];
691  NBEdge* outgoing = myOutgoingEdges[0];
692  // check if it's not the turnaround
693  if (incoming->getTurnDestination() == outgoing) {
694  // will be added later or not...
695  return;
696  }
697  for (int i = 0; i < (int) incoming->getNumLanes(); ++i) {
698  incoming->setConnection(i, outgoing, i + 1, NBEdge::L2L_COMPUTED);
699  }
700  incoming->setConnection(0, outgoing, 0, NBEdge::L2L_COMPUTED);
701  return;
702  }
703  // special case b):
704  // two in, one out, the outgoing has the same number of lanes as the sum of the incoming
705  // --> highway on-ramp
706  bool check = false;
707  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 1) {
708  check = myIncomingEdges[0]->getNumLanes() + myIncomingEdges[1]->getNumLanes() == myOutgoingEdges[0]->getNumLanes();
709  check &= (myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES);
710  check &= (myIncomingEdges[1]->getStep() <= NBEdge::LANES2EDGES);
711  check &= myIncomingEdges[0] != myOutgoingEdges[0];
712  check &= myIncomingEdges[1] != myOutgoingEdges[0];
713  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0]);
714  check &= myIncomingEdges[1]->isConnectedTo(myOutgoingEdges[0]);
715  }
716  if (check) {
717  NBEdge* inc1 = myIncomingEdges[0];
718  NBEdge* inc2 = myIncomingEdges[1];
719  // for internal: check which one is the rightmost
720  SUMOReal a1 = inc1->getAngleAtNode(this);
721  SUMOReal a2 = inc2->getAngleAtNode(this);
724  if (ccw > cw) {
725  std::swap(inc1, inc2);
726  }
727  inc1->addLane2LaneConnections(0, myOutgoingEdges[0], 0, inc1->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
728  inc2->addLane2LaneConnections(0, myOutgoingEdges[0], inc1->getNumLanes(), inc2->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
729  return;
730  }
731  // special case c):
732  // one in, two out, the incoming has the same number of lanes as the sum of the outgoing
733  // --> highway off-ramp
734  check = false;
735  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 2) {
736  check = myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[1]->getNumLanes() + myOutgoingEdges[0]->getNumLanes();
737  check &= (myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES);
738  check &= myIncomingEdges[0] != myOutgoingEdges[0];
739  check &= myIncomingEdges[0] != myOutgoingEdges[1];
740  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0]);
741  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[1]);
742  }
743  if (check) {
744  NBEdge* out1 = myOutgoingEdges[0];
745  NBEdge* out2 = myOutgoingEdges[1];
746  // for internal: check which one is the rightmost
748  std::swap(out1, out2);
749  }
750  myIncomingEdges[0]->addLane2LaneConnections(0, out1, 0, out1->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
751  myIncomingEdges[0]->addLane2LaneConnections(out1->getNumLanes(), out2, 0, out2->getNumLanes(), NBEdge::L2L_VALIDATED, false, true);
752  return;
753  }
754 
755  // go through this node's outgoing edges
756  // for every outgoing edge, compute the distribution of the node's
757  // incoming edges on this edge when approaching this edge
758  // the incoming edges' steps will then also be marked as LANE2LANE_RECHECK...
759  EdgeVector::reverse_iterator i;
760  for (i = myOutgoingEdges.rbegin(); i != myOutgoingEdges.rend(); i++) {
761  NBEdge* currentOutgoing = *i;
762  // get the information about edges that do approach this edge
763  EdgeVector* approaching = getEdgesThatApproach(currentOutgoing);
764  const unsigned int numApproaching = (unsigned int)approaching->size();
765  if (numApproaching != 0) {
766  ApproachingDivider divider(approaching, currentOutgoing, buildCrossingsAndWalkingAreas);
767  Bresenham::compute(&divider, numApproaching, divider.numAvailableLanes());
768  }
769  delete approaching;
770  }
771  // ... but we may have the case that there are no outgoing edges
772  // In this case, we have to mark the incoming edges as being in state
773  // LANE2LANE( not RECHECK) by hand
774  if (myOutgoingEdges.size() == 0) {
775  for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
776  (*i)->markAsInLane2LaneState();
777  }
778  }
779 
780  // DEBUG
781  //std::cout << "connections at " << getID() << "\n";
782  //for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
783  // const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
784  // for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
785  // std::cout << " " << (*i)->getID() << "_" << (*k).fromLane << " -> " << (*k).toEdge->getID() << "_" << (*k).toLane << "\n";
786  // }
787  //}
788 }
789 
790 
791 EdgeVector*
793  // get the position of the node to get the approaching nodes of
794  EdgeVector::const_iterator i = find(myAllEdges.begin(),
795  myAllEdges.end(), currentOutgoing);
796  // get the first possible approaching edge
798  // go through the list of edges clockwise and add the edges
799  EdgeVector* approaching = new EdgeVector();
800  for (; *i != currentOutgoing;) {
801  // check only incoming edges
802  if ((*i)->getToNode() == this && (*i)->getTurnDestination() != currentOutgoing) {
803  std::vector<int> connLanes = (*i)->getConnectionLanes(currentOutgoing);
804  if (connLanes.size() != 0) {
805  approaching->push_back(*i);
806  }
807  }
808  NBContHelper::nextCW(myAllEdges, i);
809  }
810  return approaching;
811 }
812 
813 
814 void
815 NBNode::replaceOutgoing(NBEdge* which, NBEdge* by, unsigned int laneOff) {
816  // replace the edge in the list of outgoing nodes
817  EdgeVector::iterator i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), which);
818  if (i != myOutgoingEdges.end()) {
819  (*i) = by;
820  i = find(myAllEdges.begin(), myAllEdges.end(), which);
821  (*i) = by;
822  }
823  // replace the edge in connections of incoming edges
824  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); ++i) {
825  (*i)->replaceInConnections(which, by, laneOff);
826  }
827  // replace within the connetion prohibition dependencies
828  replaceInConnectionProhibitions(which, by, 0, laneOff);
829 }
830 
831 
832 void
834  // replace edges
835  unsigned int laneOff = 0;
836  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
837  replaceOutgoing(*i, by, laneOff);
838  laneOff += (*i)->getNumLanes();
839  }
840  // removed SUMOReal occurences
842  // check whether this node belongs to a district and the edges
843  // must here be also remapped
844  if (myDistrict != 0) {
845  myDistrict->replaceOutgoing(which, by);
846  }
847 }
848 
849 
850 void
851 NBNode::replaceIncoming(NBEdge* which, NBEdge* by, unsigned int laneOff) {
852  // replace the edge in the list of incoming nodes
853  EdgeVector::iterator i = find(myIncomingEdges.begin(), myIncomingEdges.end(), which);
854  if (i != myIncomingEdges.end()) {
855  (*i) = by;
856  i = find(myAllEdges.begin(), myAllEdges.end(), which);
857  (*i) = by;
858  }
859  // replace within the connetion prohibition dependencies
860  replaceInConnectionProhibitions(which, by, laneOff, 0);
861 }
862 
863 
864 void
866  // replace edges
867  unsigned int laneOff = 0;
868  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
869  replaceIncoming(*i, by, laneOff);
870  laneOff += (*i)->getNumLanes();
871  }
872  // removed SUMOReal occurences
874  // check whether this node belongs to a district and the edges
875  // must here be also remapped
876  if (myDistrict != 0) {
877  myDistrict->replaceIncoming(which, by);
878  }
879 }
880 
881 
882 
883 void
885  unsigned int whichLaneOff, unsigned int byLaneOff) {
886  // replace in keys
887  NBConnectionProhibits::iterator j = myBlockedConnections.begin();
888  while (j != myBlockedConnections.end()) {
889  bool changed = false;
890  NBConnection c = (*j).first;
891  if (c.replaceFrom(which, whichLaneOff, by, byLaneOff)) {
892  changed = true;
893  }
894  if (c.replaceTo(which, whichLaneOff, by, byLaneOff)) {
895  changed = true;
896  }
897  if (changed) {
898  myBlockedConnections[c] = (*j).second;
899  myBlockedConnections.erase(j);
900  j = myBlockedConnections.begin();
901  } else {
902  j++;
903  }
904  }
905  // replace in values
906  for (j = myBlockedConnections.begin(); j != myBlockedConnections.end(); j++) {
907  NBConnectionVector& prohibiting = (*j).second;
908  for (NBConnectionVector::iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
909  NBConnection& sprohibiting = *k;
910  sprohibiting.replaceFrom(which, whichLaneOff, by, byLaneOff);
911  sprohibiting.replaceTo(which, whichLaneOff, by, byLaneOff);
912  }
913  }
914 }
915 
916 
917 
918 void
920  unsigned int i, j;
921  // check incoming
922  for (i = 0; myIncomingEdges.size() > 0 && i < myIncomingEdges.size() - 1; i++) {
923  j = i + 1;
924  while (j < myIncomingEdges.size()) {
925  if (myIncomingEdges[i] == myIncomingEdges[j]) {
926  myIncomingEdges.erase(myIncomingEdges.begin() + j);
927  } else {
928  j++;
929  }
930  }
931  }
932  // check outgoing
933  for (i = 0; myOutgoingEdges.size() > 0 && i < myOutgoingEdges.size() - 1; i++) {
934  j = i + 1;
935  while (j < myOutgoingEdges.size()) {
936  if (myOutgoingEdges[i] == myOutgoingEdges[j]) {
937  myOutgoingEdges.erase(myOutgoingEdges.begin() + j);
938  } else {
939  j++;
940  }
941  }
942  }
943  // check all
944  for (i = 0; myAllEdges.size() > 0 && i < myAllEdges.size() - 1; i++) {
945  j = i + 1;
946  while (j < myAllEdges.size()) {
947  if (myAllEdges[i] == myAllEdges[j]) {
948  myAllEdges.erase(myAllEdges.begin() + j);
949  } else {
950  j++;
951  }
952  }
953  }
954 }
955 
956 
957 bool
958 NBNode::hasIncoming(const NBEdge* const e) const {
959  return find(myIncomingEdges.begin(), myIncomingEdges.end(), e) != myIncomingEdges.end();
960 }
961 
962 
963 bool
964 NBNode::hasOutgoing(const NBEdge* const e) const {
965  return find(myOutgoingEdges.begin(), myOutgoingEdges.end(), e) != myOutgoingEdges.end();
966 }
967 
968 
969 NBEdge*
971  EdgeVector edges = myIncomingEdges;
972  if (find(edges.begin(), edges.end(), e) != edges.end()) {
973  edges.erase(find(edges.begin(), edges.end(), e));
974  }
975  if (edges.size() == 0) {
976  return 0;
977  }
978  if (e->getToNode() == this) {
979  sort(edges.begin(), edges.end(), NBContHelper::edge_opposite_direction_sorter(e, this));
980  } else {
981  sort(edges.begin(), edges.end(), NBContHelper::edge_similar_direction_sorter(e));
982  }
983  return edges[0];
984 }
985 
986 
987 void
989  const NBConnection& mustStop) {
990  if (mayDrive.getFrom() == 0 ||
991  mayDrive.getTo() == 0 ||
992  mustStop.getFrom() == 0 ||
993  mustStop.getTo() == 0) {
994 
995  WRITE_WARNING("Something went wrong during the building of a connection...");
996  return; // !!! mark to recompute connections
997  }
998  NBConnectionVector conn = myBlockedConnections[mustStop];
999  conn.push_back(mayDrive);
1000  myBlockedConnections[mustStop] = conn;
1001 }
1002 
1003 
1004 NBEdge*
1005 NBNode::getPossiblySplittedIncoming(const std::string& edgeid) {
1006  unsigned int size = (unsigned int) edgeid.length();
1007  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1008  std::string id = (*i)->getID();
1009  if (id.substr(0, size) == edgeid) {
1010  return *i;
1011  }
1012  }
1013  return 0;
1014 }
1015 
1016 
1017 NBEdge*
1018 NBNode::getPossiblySplittedOutgoing(const std::string& edgeid) {
1019  unsigned int size = (unsigned int) edgeid.length();
1020  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1021  std::string id = (*i)->getID();
1022  if (id.substr(0, size) == edgeid) {
1023  return *i;
1024  }
1025  }
1026  return 0;
1027 }
1028 
1029 
1030 void
1031 NBNode::removeEdge(NBEdge* edge, bool removeFromConnections) {
1032  EdgeVector::iterator i = find(myAllEdges.begin(), myAllEdges.end(), edge);
1033  if (i != myAllEdges.end()) {
1034  myAllEdges.erase(i);
1035  i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge);
1036  if (i != myOutgoingEdges.end()) {
1037  myOutgoingEdges.erase(i);
1038  } else {
1039  i = find(myIncomingEdges.begin(), myIncomingEdges.end(), edge);
1040  if (i != myIncomingEdges.end()) {
1041  myIncomingEdges.erase(i);
1042  } else {
1043  // edge must have been either incoming or outgoing
1044  assert(false);
1045  }
1046  }
1047  if (removeFromConnections) {
1048  for (i = myAllEdges.begin(); i != myAllEdges.end(); ++i) {
1049  (*i)->removeFromConnections(edge);
1050  }
1051  }
1052  }
1053 }
1054 
1055 
1056 Position
1058  Position pos(0, 0);
1059  EdgeVector::const_iterator i;
1060  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1061  NBNode* conn = (*i)->getFromNode();
1062  Position toAdd = conn->getPosition();
1063  toAdd.sub(myPosition);
1064  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1065  pos.add(toAdd);
1066  }
1067  for (i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1068  NBNode* conn = (*i)->getToNode();
1069  Position toAdd = conn->getPosition();
1070  toAdd.sub(myPosition);
1071  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
1072  pos.add(toAdd);
1073  }
1074  pos.mul((SUMOReal) - 1.0 / (myIncomingEdges.size() + myOutgoingEdges.size()));
1075  if (pos.x() == 0 && pos.y() == 0) {
1076  pos = Position(1, 0);
1077  }
1078  pos.norm2d();
1079  return pos;
1080 }
1081 
1082 
1083 
1084 void
1086  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1087  (*i)->invalidateConnections();
1088  }
1089 }
1090 
1091 
1092 void
1094  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1095  (*i)->invalidateConnections();
1096  }
1097 }
1098 
1099 
1100 bool
1101 NBNode::mustBrake(const NBEdge* const from, const NBEdge* const to, int /* toLane */) const {
1102  // check whether it is participant to a traffic light
1103  // - controlled links are set by the traffic lights, not the normal
1104  // right-of-way rules
1105  // - uncontrolled participants (spip lanes etc.) should always break
1106  if (myTrafficLights.size() != 0) {
1107  // ok, we have a traffic light, return true by now, it will be later
1108  // controlled by the tls
1109  return true;
1110  }
1111  // unregulated->does not need to brake
1112  if (myRequest == 0) {
1113  return false;
1114  }
1115  // vehicles which do not have a following lane must always decelerate to the end
1116  if (to == 0) {
1117  return true;
1118  }
1119  // check whether any other connection on this node prohibits this connection
1120  return myRequest->mustBrake(from, to);
1121 }
1122 
1123 bool
1124 NBNode::mustBrakeForCrossing(const NBEdge* const from, const NBEdge* const to, const NBNode::Crossing& crossing) const {
1125  return myRequest->mustBrakeForCrossing(from, to, crossing);
1126 }
1127 
1128 
1129 bool
1130 NBNode::isLeftMover(const NBEdge* const from, const NBEdge* const to) const {
1131  // when the junction has only one incoming edge, there are no
1132  // problems caused by left blockings
1133  if (myIncomingEdges.size() == 1 || myOutgoingEdges.size() == 1) {
1134  return false;
1135  }
1136  SUMOReal fromAngle = from->getAngleAtNode(this);
1137  SUMOReal toAngle = to->getAngleAtNode(this);
1138  SUMOReal cw = GeomHelper::getCWAngleDiff(fromAngle, toAngle);
1139  SUMOReal ccw = GeomHelper::getCCWAngleDiff(fromAngle, toAngle);
1140  std::vector<NBEdge*>::const_iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), from);
1141  do {
1143  } while ((!hasOutgoing(*i) || from->isTurningDirectionAt(this, *i)) && *i != from);
1144  return cw < ccw && (*i) == to && myOutgoingEdges.size() > 2;
1145 }
1146 
1147 
1148 bool
1149 NBNode::forbids(const NBEdge* const possProhibitorFrom, const NBEdge* const possProhibitorTo,
1150  const NBEdge* const possProhibitedFrom, const NBEdge* const possProhibitedTo,
1151  bool regardNonSignalisedLowerPriority) const {
1152  return myRequest != 0 && myRequest->forbids(possProhibitorFrom, possProhibitorTo,
1153  possProhibitedFrom, possProhibitedTo,
1154  regardNonSignalisedLowerPriority);
1155 }
1156 
1157 
1158 bool
1159 NBNode::foes(const NBEdge* const from1, const NBEdge* const to1,
1160  const NBEdge* const from2, const NBEdge* const to2) const {
1161  return myRequest != 0 && myRequest->foes(from1, to1, from2, to2);
1162 }
1163 
1164 
1165 void
1167  NBEdge* removed, const EdgeVector& incoming,
1168  const EdgeVector& outgoing) {
1169  assert(find(incoming.begin(), incoming.end(), removed) == incoming.end());
1170  bool changed = true;
1171  while (changed) {
1172  changed = false;
1173  NBConnectionProhibits blockedConnectionsTmp = myBlockedConnections;
1174  NBConnectionProhibits blockedConnectionsNew;
1175  // remap in connections
1176  for (NBConnectionProhibits::iterator i = blockedConnectionsTmp.begin(); i != blockedConnectionsTmp.end(); i++) {
1177  const NBConnection& blocker = (*i).first;
1178  const NBConnectionVector& blocked = (*i).second;
1179  // check the blocked connections first
1180  // check whether any of the blocked must be changed
1181  bool blockedChanged = false;
1182  NBConnectionVector newBlocked;
1183  NBConnectionVector::const_iterator j;
1184  for (j = blocked.begin(); j != blocked.end(); j++) {
1185  const NBConnection& sblocked = *j;
1186  if (sblocked.getFrom() == removed || sblocked.getTo() == removed) {
1187  blockedChanged = true;
1188  }
1189  }
1190  // adapt changes if so
1191  for (j = blocked.begin(); blockedChanged && j != blocked.end(); j++) {
1192  const NBConnection& sblocked = *j;
1193  if (sblocked.getFrom() == removed && sblocked.getTo() == removed) {
1194  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1195  !!! newBlocked.push_back(NBConnection(*k, *k));
1196  }*/
1197  } else if (sblocked.getFrom() == removed) {
1198  assert(sblocked.getTo() != removed);
1199  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1200  newBlocked.push_back(NBConnection(*k, sblocked.getTo()));
1201  }
1202  } else if (sblocked.getTo() == removed) {
1203  assert(sblocked.getFrom() != removed);
1204  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1205  newBlocked.push_back(NBConnection(sblocked.getFrom(), *k));
1206  }
1207  } else {
1208  newBlocked.push_back(NBConnection(sblocked.getFrom(), sblocked.getTo()));
1209  }
1210  }
1211  if (blockedChanged) {
1212  blockedConnectionsNew[blocker] = newBlocked;
1213  changed = true;
1214  }
1215  // if the blocked were kept
1216  else {
1217  if (blocker.getFrom() == removed && blocker.getTo() == removed) {
1218  changed = true;
1219  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1220  !!! blockedConnectionsNew[NBConnection(*k, *k)] = blocked;
1221  }*/
1222  } else if (blocker.getFrom() == removed) {
1223  assert(blocker.getTo() != removed);
1224  changed = true;
1225  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1226  blockedConnectionsNew[NBConnection(*k, blocker.getTo())] = blocked;
1227  }
1228  } else if (blocker.getTo() == removed) {
1229  assert(blocker.getFrom() != removed);
1230  changed = true;
1231  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1232  blockedConnectionsNew[NBConnection(blocker.getFrom(), *k)] = blocked;
1233  }
1234  } else {
1235  blockedConnectionsNew[blocker] = blocked;
1236  }
1237  }
1238  }
1239  myBlockedConnections = blockedConnectionsNew;
1240  }
1241  // remap in traffic lights
1242  tc.remapRemoved(removed, incoming, outgoing);
1243 }
1244 
1245 
1247 NBNode::getDirection(const NBEdge* const incoming, const NBEdge* const outgoing) const {
1248  // ok, no connection at all -> dead end
1249  if (outgoing == 0) {
1250  return LINKDIR_NODIR;
1251  }
1252  // turning direction
1253  if (incoming->isTurningDirectionAt(this, outgoing)) {
1254  return LINKDIR_TURN;
1255  }
1256  // get the angle between incoming/outgoing at the junction
1257  SUMOReal angle =
1258  NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outgoing->getAngleAtNode(this));
1259  // ok, should be a straight connection
1260  if (abs((int) angle) + 1 < 45) {
1261  return LINKDIR_STRAIGHT;
1262  }
1263 
1264  // check for left and right, first
1265  if (angle > 0) {
1266  // check whether any other edge goes further to the right
1267  EdgeVector::const_iterator i =
1268  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1270  while ((*i) != incoming) {
1271  if ((*i)->getFromNode() == this) {
1272  return LINKDIR_PARTRIGHT;
1273  }
1274  NBContHelper::nextCW(myAllEdges, i);
1275  }
1276  return LINKDIR_RIGHT;
1277  }
1278  // check whether any other edge goes further to the left
1279  EdgeVector::const_iterator i =
1280  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1282  while ((*i) != incoming) {
1283  if ((*i)->getFromNode() == this && !incoming->isTurningDirectionAt(this, *i)) {
1284  return LINKDIR_PARTLEFT;
1285  }
1286  NBContHelper::nextCCW(myAllEdges, i);
1287  }
1288  return LINKDIR_LEFT;
1289 }
1290 
1291 
1292 LinkState
1293 NBNode::getLinkState(const NBEdge* incoming, NBEdge* outgoing, int fromlane,
1294  bool mayDefinitelyPass, const std::string& tlID) const {
1295  if (tlID != "") {
1297  }
1298  if (outgoing == 0) { // always off
1300  }
1302  return LINKSTATE_EQUAL; // all the same
1303  }
1304  if (myType == NODETYPE_ALLWAY_STOP) {
1305  return LINKSTATE_ALLWAY_STOP; // all drive, first one to arrive may drive first
1306  }
1307  if ((!incoming->isInnerEdge() && mustBrake(incoming, outgoing, fromlane)) && !mayDefinitelyPass) {
1308  return myType == NODETYPE_PRIORITY_STOP ? LINKSTATE_STOP : LINKSTATE_MINOR; // minor road
1309  }
1310  // traffic lights are not regarded here
1311  return LINKSTATE_MAJOR;
1312 }
1313 
1314 
1315 bool
1317  // check whether this node is included in a traffic light
1318  if (myTrafficLights.size() != 0) {
1319  return false;
1320  }
1321  EdgeVector::const_iterator i;
1322  // one in, one out -> just a geometry ...
1323  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1324  // ... if types match ...
1325  if (!myIncomingEdges[0]->expandableBy(myOutgoingEdges[0])) {
1326  return false;
1327  }
1328  //
1329  return myIncomingEdges[0]->getFromNode() != myOutgoingEdges[0]->getToNode();
1330  }
1331  // two in, two out -> may be something else
1332  if (myOutgoingEdges.size() == 2 && myIncomingEdges.size() == 2) {
1333  // check whether the origin nodes of the incoming edges differ
1334  std::set<NBNode*> origSet;
1335  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1336  origSet.insert((*i)->getFromNode());
1337  }
1338  if (origSet.size() < 2) {
1339  return false;
1340  }
1341  // check whether this node is an intermediate node of
1342  // a two-directional street
1343  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1344  // try to find the opposite direction
1345  NBNode* origin = (*i)->getFromNode();
1346  // find the back direction of the current edge
1347  EdgeVector::const_iterator j =
1348  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1350  // check whether the back direction exists
1351  if (j != myOutgoingEdges.end()) {
1352  // check whether the edge from the backdirection (must be
1353  // the counter-clockwise one) may be joined with the current
1355  // check whether the types allow joining
1356  if (!(*i)->expandableBy(*j)) {
1357  return false;
1358  }
1359  } else {
1360  // ok, at least one outgoing edge is not an opposite
1361  // of an incoming one
1362  return false;
1363  }
1364  }
1365  return true;
1366  }
1367  // ok, a real node
1368  return false;
1369 }
1370 
1371 
1372 std::vector<std::pair<NBEdge*, NBEdge*> >
1374  assert(checkIsRemovable());
1375  std::vector<std::pair<NBEdge*, NBEdge*> > ret;
1376  // one in, one out-case
1377  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1378  ret.push_back(
1379  std::pair<NBEdge*, NBEdge*>(
1381  return ret;
1382  }
1383  // two in, two out-case
1384  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1385  NBNode* origin = (*i)->getFromNode();
1386  EdgeVector::const_iterator j =
1387  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1390  ret.push_back(std::pair<NBEdge*, NBEdge*>(*i, *j));
1391  }
1392  return ret;
1393 }
1394 
1395 
1396 const PositionVector&
1398  return myPoly;
1399 }
1400 
1401 
1402 void
1404  myPoly = shape;
1405  myHaveCustomPoly = (myPoly.size() > 1);
1406 }
1407 
1408 
1409 NBEdge*
1411  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1412  if ((*i)->getToNode() == n) {
1413  return (*i);
1414  }
1415  }
1416  return 0;
1417 }
1418 
1419 
1420 bool
1422  if (isDistrict()) {
1423  return false;
1424  }
1425  EdgeVector edges;
1426  copy(getIncomingEdges().begin(), getIncomingEdges().end(),
1427  back_inserter(edges));
1428  copy(getOutgoingEdges().begin(), getOutgoingEdges().end(),
1429  back_inserter(edges));
1430  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
1431  NBEdge* t = *j;
1432  NBNode* other = 0;
1433  if (t->getToNode() == this) {
1434  other = t->getFromNode();
1435  } else {
1436  other = t->getToNode();
1437  }
1438  EdgeVector edges2;
1439  copy(other->getIncomingEdges().begin(), other->getIncomingEdges().end(), back_inserter(edges2));
1440  copy(other->getOutgoingEdges().begin(), other->getOutgoingEdges().end(), back_inserter(edges2));
1441  for (EdgeVector::const_iterator k = edges2.begin(); k != edges2.end(); ++k) {
1442  if ((*k)->getFromNode()->isDistrict() || (*k)->getToNode()->isDistrict()) {
1443  return true;
1444  }
1445  }
1446  }
1447  return false;
1448 }
1449 
1450 
1451 bool
1453  return myType == NODETYPE_DISTRICT;
1454 }
1455 
1456 
1457 int
1459  //gDebugFlag1 = getID() == "C";
1460  int numGuessed = 0;
1461  if (myCrossings.size() > 0) {
1462  // user supplied crossings, do not guess
1463  return numGuessed;
1464  }
1465  if (gDebugFlag1) {
1466  std::cout << "guess crossings for " << getID() << "\n";
1467  }
1468  if (gDebugFlag1) {
1469  std::cout << "ordering of myAllEdges=" << toString(myAllEdges) << "\n";
1470  }
1471  // check for pedestrial lanes going clockwise around the node
1472  std::vector<std::pair<NBEdge*, bool> > normalizedLanes;
1473  for (EdgeVector::const_iterator it = myAllEdges.begin(); it != myAllEdges.end(); ++it) {
1474  NBEdge* edge = *it;
1475  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
1476  if (edge->getFromNode() == this) {
1477  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
1478  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
1479  }
1480  } else {
1481  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
1482  normalizedLanes.push_back(std::make_pair(edge, ((*it_l).permissions & SVC_PEDESTRIAN) != 0));
1483  }
1484  }
1485  }
1486  // do we even have a pedestrian lane?
1487  int firstSidewalk = -1;
1488  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1489  if (normalizedLanes[i].second) {
1490  firstSidewalk = i;
1491  break;
1492  }
1493  }
1494  if (firstSidewalk != -1) {
1495  // rotate lanes to ensure that the first one allows pedestrians
1496  std::vector<std::pair<NBEdge*, bool> > tmp;
1497  copy(normalizedLanes.begin() + firstSidewalk, normalizedLanes.end(), std::back_inserter(tmp));
1498  copy(normalizedLanes.begin(), normalizedLanes.begin() + firstSidewalk, std::back_inserter(tmp));
1499  normalizedLanes = tmp;
1500  // find candidates
1501  EdgeVector candidates;
1502  bool hadCandidates = false;
1503  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1504  NBEdge* edge = normalizedLanes[i].first;
1505  const bool allowsPed = normalizedLanes[i].second;
1506  if (gDebugFlag1) {
1507  std::cout << " cands=" << toString(candidates) << " edge=" << edge->getID() << " allowsPed=" << allowsPed << "\n";
1508  }
1509  if (!allowsPed && (candidates.size() == 0 || candidates.back() != edge)) {
1510  candidates.push_back(edge);
1511  } else if (allowsPed) {
1512  if (candidates.size() > 0) {
1513  hadCandidates = true;
1514  numGuessed += checkCrossing(candidates);
1515  candidates.clear();
1516  }
1517  }
1518  }
1519  if (hadCandidates) {
1520  // avoid wrapping around to the same sidewalk
1521  numGuessed += checkCrossing(candidates);
1522  }
1523  }
1525  return numGuessed;
1526 }
1527 
1528 
1529 int
1531  if (gDebugFlag1) {
1532  std::cout << "checkCrossing candidates=" << toString(candidates) << "\n";
1533  }
1534  if (candidates.size() == 0) {
1535  if (gDebugFlag1) {
1536  std::cout << "no crossing added (numCandidates=" << candidates.size() << ")\n";
1537  }
1538  return 0;
1539  } else {
1540  // check whether the edges may be part of a common crossing due to having similar angle
1541  SUMOReal prevAngle = -100000; // dummy
1542  for (size_t i = 0; i < candidates.size(); ++i) {
1543  NBEdge* edge = candidates[i];
1544  SUMOReal angle = edge->getCrossingAngle(this);
1545  // edges should be sorted by angle but this only holds true approximately
1546  if (i > 0 && fabs(angle - prevAngle) > EXTEND_CROSSING_ANGLE_THRESHOLD) {
1547  if (gDebugFlag1) {
1548  std::cout << "no crossing added (found angle difference of " << fabs(angle - prevAngle) << " at i=" << i << "\n";
1549  }
1550  return 0;
1551  }
1553  if (gDebugFlag1) {
1554  std::cout << "no crossing added (uncontrolled, edge with speed=" << edge->getSpeed() << ")\n";
1555  }
1556  return 0;
1557  }
1558  prevAngle = angle;
1559  }
1560  if (candidates.size() == 1) {
1562  if (gDebugFlag1) {
1563  std::cout << "adding crossing: " << toString(candidates) << "\n";
1564  }
1565  return 1;
1566  } else {
1567  // check for intermediate walking areas
1568  SUMOReal prevAngle = -100000; // dummy
1569  for (EdgeVector::iterator it = candidates.begin(); it != candidates.end(); ++it) {
1570  SUMOReal angle = (*it)->getCrossingAngle(this);
1571  if (it != candidates.begin()) {
1572  NBEdge* prev = *(it - 1);
1573  NBEdge* curr = *it;
1574  Position prevPos, currPos;
1575  unsigned int laneI;
1576  // compute distance between candiate edges
1577  SUMOReal intermediateWidth = 0;
1578  if (prev->getToNode() == this) {
1579  laneI = prev->getNumLanes() - 1;
1580  prevPos = prev->getLanes()[laneI].shape[-1];
1581  } else {
1582  laneI = 0;
1583  prevPos = prev->getLanes()[laneI].shape[0];
1584  }
1585  intermediateWidth -= 0.5 * prev->getLaneWidth(laneI);
1586  if (curr->getFromNode() == this) {
1587  laneI = curr->getNumLanes() - 1;
1588  currPos = curr->getLanes()[laneI].shape[0];
1589  } else {
1590  laneI = 0;
1591  currPos = curr->getLanes()[laneI].shape[-1];
1592  }
1593  intermediateWidth -= 0.5 * curr->getLaneWidth(laneI);
1594  intermediateWidth += currPos.distanceTo2D(prevPos);
1595  if (gDebugFlag1) {
1596  std::cout
1597  << " prevAngle=" << prevAngle
1598  << " angle=" << angle
1599  << " intermediateWidth=" << intermediateWidth
1600  << "\n";
1601  }
1602  if (fabs(prevAngle - angle) > SPLIT_CROSSING_ANGLE_THRESHOLD
1603  || (intermediateWidth > SPLIT_CROSSING_WIDTH_THRESHOLD)) {
1604  return checkCrossing(EdgeVector(candidates.begin(), it))
1605  + checkCrossing(EdgeVector(it, candidates.end()));
1606  }
1607  }
1608  prevAngle = angle;
1609  }
1611  if (gDebugFlag1) {
1612  std::cout << "adding crossing: " << toString(candidates) << "\n";
1613  }
1614  return 1;
1615  }
1616  }
1617 }
1618 
1619 
1620 void
1621 NBNode::buildInnerEdges(bool buildCrossingsAndWalkingAreas) {
1622  // build inner edges for vehicle movements across the junction
1623  unsigned int noInternalNoSplits = 0;
1624  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1625  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
1626  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1627  if ((*k).toEdge == 0) {
1628  continue;
1629  }
1630  noInternalNoSplits++;
1631  }
1632  }
1633  unsigned int lno = 0;
1634  unsigned int splitNo = 0;
1635  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1636  (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
1637  }
1638  if (buildCrossingsAndWalkingAreas) {
1639  buildCrossings();
1641  // ensure that all crossings are properly connected
1642  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); it++) {
1643  if ((*it).prevWalkingArea == "" || (*it).nextWalkingArea == "") {
1644  // there is no way to check this apart from trying to build all
1645  // walkingAreas and there is no way to recover because the junction
1646  // logic assumes that the crossing can be built.
1647  throw ProcessError("Invalid crossing at node '" + getID() + "' with edges '" + toString((*it).edges) + "'.");
1648  }
1649  }
1650  }
1651 
1652 }
1653 
1654 
1655 unsigned int
1657  //gDebugFlag1 = getID() == "C";
1658  unsigned int index = 0;
1659  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); it++) {
1660  (*it).id = ":" + getID() + "_c" + toString(index++);
1661  if ((*it).edges.size() > 2) {
1662  WRITE_ERROR("Crossings across more than 2 edges not yet implemented (" + toString((*it).edges) + ")");
1663  continue;
1664  }
1665  // compute shape
1666  EdgeVector& edges = (*it).edges;
1667  (*it).shape.clear();
1668  std::sort(edges.begin(), edges.end(), edge_by_direction_sorter(this));
1669  const int begDir = (edges.front()->getFromNode() == this ? FORWARD : BACKWARD);
1670  const int endDir = (edges.back()->getToNode() == this ? FORWARD : BACKWARD);
1671  NBEdge::Lane crossingBeg = edges.front()->getFirstNonPedestrianLane(begDir);
1672  NBEdge::Lane crossingEnd = edges.back()->getFirstNonPedestrianLane(endDir);
1673  crossingBeg.width = (crossingBeg.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingBeg.width);
1674  crossingEnd.width = (crossingEnd.width == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : crossingEnd.width);
1675  crossingBeg.shape.move2side(begDir * crossingBeg.width / 2);
1676  crossingEnd.shape.move2side(endDir * crossingEnd.width / 2);
1677  crossingBeg.shape.extrapolate((*it).width / 2);
1678  crossingEnd.shape.extrapolate((*it).width / 2);
1679  (*it).shape.push_back(crossingBeg.shape[begDir == FORWARD ? 0 : -1]);
1680  (*it).shape.push_back(crossingEnd.shape[endDir == FORWARD ? -1 : 0]);
1681  }
1682  return index;
1683 }
1684 
1685 
1686 void
1688  //gDebugFlag1 = getID() == "E";
1689  unsigned int index = 0;
1690  myWalkingAreas.clear();
1691  if (gDebugFlag1) {
1692  std::cout << "build walkingAreas for " << getID() << ":\n";
1693  }
1694  // get begin shapes of all lanes in outgoing direction ordered clockwise
1695  std::vector<std::pair<NBEdge*, NBEdge::Lane> > normalizedLanes;
1696  for (EdgeVector::const_iterator it = myAllEdges.begin(); it != myAllEdges.end(); ++it) {
1697  NBEdge* edge = *it;
1698  const std::vector<NBEdge::Lane>& lanes = edge->getLanes();
1699  if (edge->getFromNode() == this) {
1700  for (std::vector<NBEdge::Lane>::const_reverse_iterator it_l = lanes.rbegin(); it_l != lanes.rend(); ++it_l) {
1701  NBEdge::Lane l = *it_l;
1702  l.shape = l.shape.getSubpartByIndex(0, 2);
1703  normalizedLanes.push_back(std::make_pair(edge, l));
1704  }
1705  } else {
1706  for (std::vector<NBEdge::Lane>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); ++it_l) {
1707  NBEdge::Lane l = *it_l;
1708  l.shape = l.shape.reverse();
1709  l.shape = l.shape.getSubpartByIndex(0, 2);
1710  normalizedLanes.push_back(std::make_pair(edge, l));
1711  }
1712  }
1713  }
1714  //if (gDebugFlag1) std::cout << " normalizedLanes=" << normalizedLanes.size() << "\n";
1715  // collect [start,cound[ indices in normalizedLanes that belong to a walkingArea
1716  std::vector<std::pair<int, int> > waIndices;
1717  int start = -1;
1718  NBEdge* prevEdge = normalizedLanes.back().first;
1719  for (int i = 0; i < (int)normalizedLanes.size(); ++i) {
1720  NBEdge* edge = normalizedLanes[i].first;
1721  NBEdge::Lane& l = normalizedLanes[i].second;
1722  if (start == -1) {
1723  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
1724  start = i;
1725  }
1726  } else {
1727  if ((l.permissions & SVC_PEDESTRIAN) == 0 || crossingBetween(edge, prevEdge)) {
1728  waIndices.push_back(std::make_pair(start, i - start));
1729  if ((l.permissions & SVC_PEDESTRIAN) != 0) {
1730  start = i;
1731  } else {
1732  start = -1;
1733  }
1734 
1735  }
1736  }
1737  if (gDebugFlag1) std::cout << " i=" << i << " edge=" << edge->getID() << " start=" << start << " ped=" << ((l.permissions & SVC_PEDESTRIAN) != 0)
1738  << " waI=" << waIndices.size() << " crossingBetween=" << crossingBetween(edge, prevEdge) << "\n";
1739  prevEdge = edge;
1740  }
1741  // deal with wrap-around issues
1742  if (start != - 1) {
1743  const int waNumLanes = (int)normalizedLanes.size() - start;
1744  if (waIndices.size() == 0) {
1745  waIndices.push_back(std::make_pair(start, waNumLanes));
1746  if (gDebugFlag1) {
1747  std::cout << " single wa, end at wrap-around\n";
1748  }
1749  } else {
1750  if (waIndices.front().first == 0) {
1751  NBEdge* edge = normalizedLanes.front().first;
1752  NBEdge* prevEdge = normalizedLanes.back().first;
1753  if (crossingBetween(edge, prevEdge)) {
1754  // do not wrap-around if there is a crossing in between
1755  waIndices.push_back(std::make_pair(start, waNumLanes));
1756  if (gDebugFlag1) {
1757  std::cout << " do not wrap around, turn-around in between\n";
1758  }
1759  } else {
1760  // first walkingArea wraps around
1761  waIndices.front().first = start;
1762  waIndices.front().second = waNumLanes + waIndices.front().second;
1763  if (gDebugFlag1) {
1764  std::cout << " wrapping around\n";
1765  }
1766  }
1767  } else {
1768  // last walkingArea ends at the wrap-around
1769  waIndices.push_back(std::make_pair(start, waNumLanes));
1770  if (gDebugFlag1) {
1771  std::cout << " end at wrap-around\n";
1772  }
1773  }
1774  }
1775  }
1776  if (gDebugFlag1) {
1777  std::cout << " normalizedLanes=" << normalizedLanes.size() << " waIndices:\n";
1778  for (int i = 0; i < (int)waIndices.size(); ++i) {
1779  std::cout << " " << waIndices[i].first << ", " << waIndices[i].second << "\n";
1780  }
1781  }
1782  // build walking areas connected to a sidewalk
1783  for (int i = 0; i < (int)waIndices.size(); ++i) {
1784  const bool buildExtensions = waIndices[i].second != (int)normalizedLanes.size();
1785  const int start = waIndices[i].first;
1786  const int prev = start > 0 ? start - 1 : (int)normalizedLanes.size() - 1;
1787  const int count = waIndices[i].second;
1788  const int end = (start + count) % normalizedLanes.size();
1789 
1790  WalkingArea wa(":" + getID() + "_w" + toString(index++), DEFAULT_CROSSING_WIDTH);
1791  if (gDebugFlag1) {
1792  std::cout << "build walkingArea " << wa.id << " start=" << start << " end=" << end << " count=" << count << " prev=" << prev << ":\n";
1793  }
1794  SUMOReal endCrossingWidth = DEFAULT_CROSSING_WIDTH;
1795  SUMOReal startCrossingWidth = DEFAULT_CROSSING_WIDTH;
1796  // check for connected crossings
1797  bool connectsCrossing = false;
1798  std::vector<Position> connectedPoints;
1799  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
1800  if ((*it).edges.back() == normalizedLanes[end].first
1801  && (normalizedLanes[end].second.permissions & SVC_PEDESTRIAN) == 0) {
1802  // crossing ends
1803  (*it).nextWalkingArea = wa.id;
1804  endCrossingWidth = (*it).width;
1805  connectsCrossing = true;
1806  connectedPoints.push_back((*it).shape[-1]);
1807  if (gDebugFlag1) {
1808  std::cout << " crossing " << (*it).id << " ends\n";
1809  }
1810  }
1811  if ((*it).edges.front() == normalizedLanes[prev].first
1812  && (normalizedLanes[prev].second.permissions & SVC_PEDESTRIAN) == 0) {
1813  // crossing starts
1814  (*it).prevWalkingArea = wa.id;
1815  wa.nextCrossing = (*it).id;
1816  startCrossingWidth = (*it).width;
1817  connectsCrossing = true;
1818  if (isTLControlled()) {
1819  wa.tlID = (*getControllingTLS().begin())->getID();
1820  }
1821  connectedPoints.push_back((*it).shape[0]);
1822  if (gDebugFlag1) {
1823  std::cout << " crossing " << (*it).id << " starts\n";
1824  }
1825  }
1826  if (gDebugFlag1) std::cout << " check connections to crossing " << (*it).id
1827  << " cFront=" << (*it).edges.front()->getID() << " cBack=" << (*it).edges.back()->getID()
1828  << " wEnd=" << normalizedLanes[end].first->getID() << " wStart=" << normalizedLanes[start].first->getID()
1829  << " wStartPrev=" << normalizedLanes[prev].first->getID()
1830  << "\n";
1831  }
1832  if (count < 2 && !connectsCrossing) {
1833  // not relevant for walking
1834  continue;
1835  }
1836  wa.width = (endCrossingWidth + startCrossingWidth) / 2;
1837  // build shape and connections
1838  std::set<NBEdge*> connected;
1839  for (int j = 0; j < count; ++j) {
1840  const int nlI = (start + j) % normalizedLanes.size();
1841  NBEdge* edge = normalizedLanes[nlI].first;
1842  NBEdge::Lane l = normalizedLanes[nlI].second;
1844  if (connected.count(edge) == 0) {
1845  if (edge->getFromNode() == this) {
1846  wa.nextSidewalks.push_back(edge->getID());
1847  connectedPoints.push_back(edge->getLaneShape(0)[0]);
1848  } else {
1849  wa.prevSidewalks.push_back(edge->getID());
1850  connectedPoints.push_back(edge->getLaneShape(0)[-1]);
1851  }
1852  connected.insert(edge);
1853  }
1854  l.shape.move2side(-l.width / 2);
1855  wa.shape.push_back(l.shape[0]);
1856  l.shape.move2side(l.width);
1857  wa.shape.push_back(l.shape[0]);
1858  }
1859  if (buildExtensions) {
1860  // extension at starting crossing
1861  NBEdge::Lane l = normalizedLanes[start].second;
1862  l.shape.extrapolate(startCrossingWidth);
1863  l.shape.move2side(-l.width / 2);
1864  wa.shape.push_front(l.shape[0]);
1865  // extension at ending crossing
1866  l = normalizedLanes[end > 0 ? end - 1 : normalizedLanes.size() - 1].second;
1867  l.shape.extrapolate(endCrossingWidth);
1868  l.shape.move2side(l.width / 2);
1869  wa.shape.push_back(l.shape[0]);
1870  }
1871  if (connected.size() == 2 && !connectsCrossing && wa.nextSidewalks.size() == 1 && wa.prevSidewalks.size() == 1) {
1872  // do not build a walkingArea since a normal connection exists
1873  NBEdge* e1 = *connected.begin();
1874  NBEdge* e2 = *(++connected.begin());
1875  if (e1->hasConnectionTo(e2, 0, 0) || e2->hasConnectionTo(e1, 0, 0)) {
1876  continue;
1877  }
1878  }
1879  // determine length (average of all possible connections)
1880  SUMOReal lengthSum = 0;
1881  int combinations = 0;
1882  for (std::vector<Position>::const_iterator it1 = connectedPoints.begin(); it1 != connectedPoints.end(); ++it1) {
1883  for (std::vector<Position>::const_iterator it2 = connectedPoints.begin(); it2 != connectedPoints.end(); ++it2) {
1884  const Position& p1 = *it1;
1885  const Position& p2 = *it2;
1886  if (p1 != p2) {
1887  lengthSum += p1.distanceTo2D(p2);
1888  combinations += 1;
1889  }
1890  }
1891  }
1892  if (gDebugFlag1) {
1893  std::cout << " combinations=" << combinations << " connectedPoints=" << connectedPoints << "\n";
1894  }
1895  wa.length = POSITION_EPS;
1896  if (combinations > 0) {
1897  wa.length = MAX2(POSITION_EPS, lengthSum / combinations);
1898  }
1899  myWalkingAreas.push_back(wa);
1900  }
1901  // build walkingAreas between split crossings
1902  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
1903  Crossing& prev = *it;
1904  Crossing& next = (it != myCrossings.begin() ? * (it - 1) : * (myCrossings.end() - 1));
1905  if (prev.nextWalkingArea == "") {
1906  WalkingArea wa(":" + getID() + "_w" + toString(index++), prev.width);
1907  prev.nextWalkingArea = wa.id;
1908  wa.nextCrossing = next.id;
1909  next.prevWalkingArea = wa.id;
1910  if (isTLControlled()) {
1911  wa.tlID = (*getControllingTLS().begin())->getID();
1912  }
1913  // back of previous crossing
1914  PositionVector tmp = prev.shape;
1915  tmp.move2side(-prev.width / 2);
1916  wa.shape.push_back(tmp[-1]);
1917  tmp.move2side(prev.width);
1918  wa.shape.push_back(tmp[-1]);
1919  // front of next crossing
1920  tmp = next.shape;
1921  tmp.move2side(prev.width / 2);
1922  wa.shape.push_back(tmp[0]);
1923  tmp.move2side(-prev.width);
1924  wa.shape.push_back(tmp[0]);
1925  // length (special case)
1926  wa.length = MAX2(POSITION_EPS, prev.shape.back().distanceTo2D(next.shape.front()));
1927  myWalkingAreas.push_back(wa);
1928  }
1929  }
1930 }
1931 
1932 
1933 bool
1934 NBNode::crossingBetween(const NBEdge* e1, const NBEdge* e2) const {
1935  if (e1 == e2) {
1936  return false;
1937  }
1938  for (std::vector<Crossing>::const_iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
1939  const EdgeVector& edges = (*it).edges;
1940  EdgeVector::const_iterator it1 = find(edges.begin(), edges.end(), e1);
1941  EdgeVector::const_iterator it2 = find(edges.begin(), edges.end(), e2);
1942  if (it1 != edges.end() && it2 != edges.end()) {
1943  return true;
1944  }
1945  }
1946  return false;
1947 }
1948 
1949 
1950 EdgeVector
1951 NBNode::edgesBetween(const NBEdge* e1, const NBEdge* e2) const {
1952  EdgeVector result;
1953  EdgeVector::const_iterator it = find(myAllEdges.begin(), myAllEdges.end(), e1);
1954  assert(it != myAllEdges.end());
1956  EdgeVector::const_iterator it_end = find(myAllEdges.begin(), myAllEdges.end(), e2);
1957  assert(it_end != myAllEdges.end());
1958  while (it != it_end) {
1959  result.push_back(*it);
1960  NBContHelper::nextCW(myAllEdges, it);
1961  }
1962  return result;
1963 }
1964 
1965 
1966 bool
1968  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
1969  return true;
1970  }
1971  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
1972  // check whether the incoming and outgoing edges are pairwise (near) parallel and
1973  // thus the only cross-connections could be turn-arounds
1974  NBEdge* out0 = myOutgoingEdges[0];
1975  NBEdge* out1 = myOutgoingEdges[1];
1976  for (EdgeVector::const_iterator it = myIncomingEdges.begin(); it != myIncomingEdges.end(); ++it) {
1977  NBEdge* inEdge = *it;
1978  SUMOReal angle0 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out0->getAngleAtNode(this)));
1979  SUMOReal angle1 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out1->getAngleAtNode(this)));
1980  if (MAX2(angle0, angle1) <= 160) {
1981  // neither of the outgoing edges is parallel to inEdge
1982  return false;
1983  }
1984  }
1985  return true;
1986  }
1987  return false;
1988 }
1989 
1990 
1991 void
1995  }
1996 }
1997 
1998 
1999 void
2000 NBNode::addCrossing(EdgeVector edges, SUMOReal width, bool priority) {
2001  myCrossings.push_back(Crossing(this, edges, width, priority));
2002 }
2003 
2004 
2005 const NBNode::Crossing&
2006 NBNode::getCrossing(const std::string& id) const {
2007  for (std::vector<Crossing>::const_iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2008  if ((*it).id == id) {
2009  return *it;
2010  }
2011  }
2012  throw ProcessError("Request for unknown crossing '" + id + "'");
2013 }
2014 
2015 
2016 void
2017 NBNode::setCrossingTLIndices(unsigned int startIndex) {
2018  for (std::vector<Crossing>::iterator it = myCrossings.begin(); it != myCrossings.end(); ++it) {
2019  (*it).tlLinkNo = startIndex++;
2020  }
2021 }
2022 
2023 
2024 int
2026  return myRequest->getSizes().second;
2027 }
2028 
2029 Position
2031  /* Conceptually, the center point would be identical with myPosition.
2032  * However, if the shape is influenced by custom geometry endpoints of the adjoining edges,
2033  * myPosition may fall outside the shape. In this case it is better to use
2034  * the center of the shape
2035  **/
2036  PositionVector tmp = myPoly;
2037  tmp.closePolygon();
2038  //std::cout << getID() << " around=" << tmp.around(myPosition) << " dist=" << tmp.distance(myPosition) << "\n";
2039  if (tmp.size() < 3 || tmp.around(myPosition) || tmp.distance(myPosition) < POSITION_EPS) {
2040  return myPosition;
2041  } else {
2042  return myPoly.getPolygonCenter();
2043  }
2044 }
2045 
2046 
2047 /****************************************************************************/
2048