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.sourceforge.net/
13 // Copyright (C) 2001-2013 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 "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"
66 
67 #ifdef CHECK_MEMORY_LEAKS
68 #include <foreign/nvwa/debug_new.h>
69 #endif // CHECK_MEMORY_LEAKS
70 
71 
72 // ===========================================================================
73 // static members
74 // ===========================================================================
75 
76 // ===========================================================================
77 // method definitions
78 // ===========================================================================
79 /* -------------------------------------------------------------------------
80  * NBNode::ApproachingDivider-methods
81  * ----------------------------------------------------------------------- */
83  EdgeVector* approaching, NBEdge* currentOutgoing) :
84  myApproaching(approaching), myCurrentOutgoing(currentOutgoing) {
85  // check whether origin lanes have been given
86  assert(myApproaching != 0);
87 }
88 
89 
91 
92 
93 void
94 NBNode::ApproachingDivider::execute(const unsigned int src, const unsigned int dest) {
95  assert(myApproaching->size() > src);
96  // get the origin edge
97  NBEdge* incomingEdge = (*myApproaching)[src];
98  if (incomingEdge->getStep() == NBEdge::LANES2LANES_DONE || incomingEdge->getStep() == NBEdge::LANES2LANES_USER) {
99  return;
100  }
101  std::vector<int> approachingLanes =
102  incomingEdge->getConnectionLanes(myCurrentOutgoing);
103  assert(approachingLanes.size() != 0);
104  std::deque<int>* approachedLanes = spread(approachingLanes, dest);
105  assert(approachedLanes->size() <= myCurrentOutgoing->getNumLanes());
106  // set lanes
107  for (unsigned int i = 0; i < approachedLanes->size(); i++) {
108  unsigned int approached = (*approachedLanes)[i];
109  assert(approachedLanes->size() > i);
110  assert(approachingLanes.size() > i);
111  incomingEdge->setConnection((unsigned int) approachingLanes[i], myCurrentOutgoing,
112  approached, NBEdge::L2L_COMPUTED);
113  }
114  delete approachedLanes;
115 }
116 
117 
118 std::deque<int>*
119 NBNode::ApproachingDivider::spread(const std::vector<int>& approachingLanes,
120  int dest) const {
121  std::deque<int>* ret = new std::deque<int>();
122  unsigned int noLanes = (unsigned int) approachingLanes.size();
123  // when only one lane is approached, we check, whether the SUMOReal-value
124  // is assigned more to the left or right lane
125  if (noLanes == 1) {
126  ret->push_back(dest);
127  return ret;
128  }
129 
130  unsigned int noOutgoingLanes = myCurrentOutgoing->getNumLanes();
131  //
132  ret->push_back(dest);
133  unsigned int noSet = 1;
134  int roffset = 1;
135  int loffset = 1;
136  while (noSet < noLanes) {
137  // It may be possible, that there are not enough lanes the source
138  // lanes may be divided on
139  // In this case, they remain unset
140  // !!! this is only a hack. It is possible, that this yields in
141  // uncommon divisions
142  if (noOutgoingLanes == noSet) {
143  return ret;
144  }
145 
146  // as due to the conversion of SUMOReal->uint the numbers will be lower
147  // than they should be, we try to append to the left side first
148  //
149  // check whether the left boundary of the approached street has
150  // been overridden; if so, move all lanes to the right
151  if (dest + loffset >= static_cast<int>(noOutgoingLanes)) {
152  loffset -= 1;
153  roffset += 1;
154  for (unsigned int i = 0; i < ret->size(); i++) {
155  (*ret)[i] = (*ret)[i] - 1;
156  }
157  }
158  // append the next lane to the left of all edges
159  // increase the position (destination edge)
160  ret->push_back(dest + loffset);
161  noSet++;
162  loffset += 1;
163 
164  // as above
165  if (noOutgoingLanes == noSet) {
166  return ret;
167  }
168 
169  // now we try to append the next lane to the right side, when needed
170  if (noSet < noLanes) {
171  // check whether the right boundary of the approached street has
172  // been overridden; if so, move all lanes to the right
173  if (dest < roffset) {
174  loffset += 1;
175  roffset -= 1;
176  for (unsigned int i = 0; i < ret->size(); i++) {
177  (*ret)[i] = (*ret)[i] + 1;
178  }
179  }
180  ret->push_front(dest - roffset);
181  noSet++;
182  roffset += 1;
183  }
184  }
185  return ret;
186 }
187 
188 
189 
190 
191 /* -------------------------------------------------------------------------
192  * NBNode-methods
193  * ----------------------------------------------------------------------- */
194 NBNode::NBNode(const std::string& id, const Position& position) :
195  Named(StringUtils::convertUmlaute(id)),
196  myPosition(position),
198 { }
199 
200 
201 NBNode::NBNode(const std::string& id, const Position& position,
202  SumoXMLNodeType type) :
203  Named(StringUtils::convertUmlaute(id)),
204  myPosition(position),
205  myType(type), myDistrict(0), myRequest(0)
206 { }
207 
208 
209 NBNode::NBNode(const std::string& id, const Position& position, NBDistrict* district) :
210  Named(StringUtils::convertUmlaute(id)),
211  myPosition(position),
212  myType(NODETYPE_DISTRICT), myDistrict(district), myRequest(0)
213 { }
214 
215 
217  delete myRequest;
218 }
219 
220 
221 void
223  bool updateEdgeGeometries) {
224  myPosition = position;
225  // patch type
226  myType = type;
229  }
230  if (updateEdgeGeometries) {
231  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
232  PositionVector geom = (*i)->getGeometry();
233  geom[-1] = myPosition;
234  (*i)->setGeometry(geom);
235  }
236  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
237  PositionVector geom = (*i)->getGeometry();
238  geom[0] = myPosition;
239  (*i)->setGeometry(geom);
240  }
241  }
242 }
243 
244 
245 
246 // ----------- Applying offset
247 void
249  myPosition.add(xoff, yoff, 0);
250  myPoly.add(xoff, yoff, 0);
251 }
252 
253 
254 // ----------- Methods for dealing with assigned traffic lights
255 void
257  myTrafficLights.insert(tlDef);
259 }
260 
261 
262 void
264  tlDef->removeNode(this);
265  myTrafficLights.erase(tlDef);
266 }
267 
268 
269 void
271  std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
272  for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
273  removeTrafficLight(*i);
274  }
275 }
276 
277 
278 bool
280  if (!isTLControlled()) {
281  return false;
282  }
283  for (std::set<NBTrafficLightDefinition*>::const_iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
284  if ((*i)->getID().find("joined") == 0) {
285  return true;
286  }
287  }
288  return false;
289 }
290 
291 
292 // ----------- Prunning the input
293 unsigned int
295  unsigned int ret = 0;
296  unsigned int pos = 0;
297  EdgeVector::const_iterator j = myIncomingEdges.begin();
298  while (j != myIncomingEdges.end()) {
299  // skip edges which are only incoming and not outgoing
300  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), *j) == myOutgoingEdges.end()) {
301  ++j;
302  ++pos;
303  continue;
304  }
305  // an edge with both its origin and destination being the current
306  // node should be removed
307  NBEdge* dummy = *j;
308  WRITE_WARNING(" Removing self-looping edge '" + dummy->getID() + "'");
309  // get the list of incoming edges connected to the self-loop
310  EdgeVector incomingConnected;
311  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
312  if ((*i)->isConnectedTo(dummy) && *i != dummy) {
313  incomingConnected.push_back(*i);
314  }
315  }
316  // get the list of outgoing edges connected to the self-loop
317  EdgeVector outgoingConnected;
318  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
319  if (dummy->isConnectedTo(*i) && *i != dummy) {
320  outgoingConnected.push_back(*i);
321  }
322  }
323  // let the self-loop remap its connections
324  dummy->remapConnections(incomingConnected);
325  remapRemoved(tc, dummy, incomingConnected, outgoingConnected);
326  // delete the self-loop
327  ec.erase(dc, dummy);
328  j = myIncomingEdges.begin() + pos;
329  ++ret;
330  }
331  return ret;
332 }
333 
334 
335 // -----------
336 void
338  assert(edge != 0);
339  if (find(myIncomingEdges.begin(), myIncomingEdges.end(), edge) == myIncomingEdges.end()) {
340  myIncomingEdges.push_back(edge);
341  myAllEdges.push_back(edge);
342  }
343 }
344 
345 
346 void
348  assert(edge != 0);
349  if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge) == myOutgoingEdges.end()) {
350  myOutgoingEdges.push_back(edge);
351  myAllEdges.push_back(edge);
352  }
353 }
354 
355 
356 bool
358  // one in, one out->continuation
359  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
360  // both must have the same number of lanes
361  return (*(myIncomingEdges.begin()))->getNumLanes() == (*(myOutgoingEdges.begin()))->getNumLanes();
362  }
363  // two in and two out and both in reverse direction
364  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
365  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
366  NBEdge* in = *i;
367  EdgeVector::const_iterator opposite = find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(), NBContHelper::opposite_finder(in, this));
368  // must have an opposite edge
369  if (opposite == myOutgoingEdges.end()) {
370  return false;
371  }
372  // both must have the same number of lanes
374  if (in->getNumLanes() != (*opposite)->getNumLanes()) {
375  return false;
376  }
377  }
378  return true;
379  }
380  // nope
381  return false;
382 }
383 
384 
387  NBEdge* toE, int toL, int numPoints) const {
388  if (fromL >= (int) fromE->getNumLanes()) {
389  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' starts at a not existing lane.");
390  }
391  if (toL >= (int) toE->getNumLanes()) {
392  throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' yields in a not existing lane.");
393  }
394  bool noSpline = false;
395  PositionVector ret;
396  PositionVector init;
397  Position beg = fromE->getLaneShape(fromL).back();
398  Position end = toE->getLaneShape(toL).front();
399  Position intersection;
400  unsigned int noInitialPoints = 0;
401  if (beg.distanceTo(end) <= POSITION_EPS) {
402  noSpline = true;
403  } else {
404  if (fromE->getTurnDestination() == toE) {
405  // turnarounds:
406  // - end of incoming lane
407  // - position between incoming/outgoing end/begin shifted by the distance orthogonally
408  // - begin of outgoing lane
409  noInitialPoints = 3;
410  init.push_back(beg);
411  Line straightConn(fromE->getLaneShape(fromL)[-1], toE->getLaneShape(toL)[0]);
412  Position straightCenter = straightConn.getPositionAtDistance((SUMOReal) straightConn.length() / (SUMOReal) 2.);
413  Position center = straightCenter;//.add(straightCenter);
414  Line cross(straightConn);
415  cross.sub(cross.p1().x(), cross.p1().y());
416  cross.rotateAtP1(PI / 2);
417  center.sub(cross.p2());
418  init.push_back(center);
419  init.push_back(end);
420  } else {
421  const SUMOReal angle = fabs(fromE->getLaneShape(fromL).getEndLine().atan2Angle() - toE->getLaneShape(toL).getBegLine().atan2Angle());
422  if (angle < PI / 4. || angle > 7. / 4.*PI) {
423  // very low angle: almost straight
424  noInitialPoints = 4;
425  init.push_back(beg);
426  Line begL = fromE->getLaneShape(fromL).getEndLine();
427  begL.extrapolateSecondBy(100);
428  Line endL = toE->getLaneShape(toL).getBegLine();
429  endL.extrapolateFirstBy(100);
430  SUMOReal distance = beg.distanceTo(end);
431  if (distance > 10) {
432  {
433  SUMOReal off1 = fromE->getLaneShape(fromL).getEndLine().length() + (SUMOReal) 5. * (SUMOReal) fromE->getNumLanes();
434  off1 = MIN2(off1, (SUMOReal)(fromE->getLaneShape(fromL).getEndLine().length() + distance / 2.));
435  Position tmp = begL.getPositionAtDistance(off1);
436  init.push_back(tmp);
437  }
438  {
439  SUMOReal off1 = (SUMOReal) 100. - (SUMOReal) 5. * (SUMOReal) toE->getNumLanes();
440  off1 = MAX2(off1, (SUMOReal)(100. - distance / 2.));
441  Position tmp = endL.getPositionAtDistance(off1);
442  init.push_back(tmp);
443  }
444  } else {
445  noSpline = true;
446  }
447  init.push_back(end);
448  } else {
449  // turning
450  // - end of incoming lane
451  // - intersection of the extrapolated lanes
452  // - begin of outgoing lane
453  // attention: if there is no intersection, use a straight line
454  noInitialPoints = 3;
455  init.push_back(beg);
456  Line begL = fromE->getLaneShape(fromL).getEndLine();
457  Line endL = toE->getLaneShape(toL).getBegLine();
458  bool check = !begL.p1().almostSame(begL.p2()) && !endL.p1().almostSame(endL.p2());
459  if (check) {
460  begL.extrapolateSecondBy(100);
461  endL.extrapolateFirstBy(100);
462  } else {
463  WRITE_WARNING("Could not use edge geometry for internal lane, node '" + getID() + "'.");
464  }
465  if (!check || !begL.intersects(endL)) {
466  noSpline = true;
467  } else {
468  init.push_back(begL.intersectsAt(endL));
469  }
470  init.push_back(end);
471  }
472  }
473  }
474  //
475  if (noSpline) {
476  ret.push_back(fromE->getLaneShape(fromL).back());
477  ret.push_back(toE->getLaneShape(toL).front());
478  } else {
479  SUMOReal* def = new SUMOReal[1 + noInitialPoints * 3];
480  for (int i = 0; i < (int) init.size(); ++i) {
481  // starts at index 1
482  def[i * 3 + 1] = init[i].x();
483  def[i * 3 + 2] = 0;
484  def[i * 3 + 3] = init[i].y();
485  }
486  SUMOReal* ret_buf = new SUMOReal[numPoints * 3 + 1];
487  bezier(noInitialPoints, def, numPoints, ret_buf);
488  delete[] def;
489  Position prev;
490  for (int i = 0; i < (int) numPoints; i++) {
491  Position current(ret_buf[i * 3 + 1], ret_buf[i * 3 + 3]);
492  if (prev != current) {
493  ret.push_back(current);
494  }
495  prev = current;
496  }
497  delete[] ret_buf;
498  }
499  const NBEdge::Lane& lane = fromE->getLaneStruct(fromL);
500  if (lane.offset > 0) {
501  PositionVector beg = lane.shape.getSubpart(lane.shape.length() - lane.offset, lane.shape.length());;
502  beg.append(ret);
503  ret = beg;
504  }
505  return ret;
506 }
507 
508 
509 bool
510 NBNode::needsCont(NBEdge* fromE, NBEdge* toE, NBEdge* otherFromE, NBEdge* otherToE, const NBEdge::Connection& c) const {
512  return false;
513  }
514  if (fromE == otherFromE) {
515  // ignore same edge links
516  return false;
517  }
518  if (!foes(otherFromE, otherToE, fromE, toE)) {
519  // if they do not cross, no waiting place is needed
520  return false;
521  }
522  LinkDirection d1 = getDirection(fromE, toE);
523  LinkDirection d2 = getDirection(otherFromE, otherToE);
524  bool thisLeft = (d1 == LINKDIR_LEFT || d1 == LINKDIR_TURN);
525  bool otherLeft = (d2 == LINKDIR_LEFT || d2 == LINKDIR_TURN);
526  bool bothLeft = thisLeft && otherLeft;
527  if (c.tlID != "" && !bothLeft) {
528  // tls-controlled links will have space
529  return true;
530  }
531  if (fromE->getJunctionPriority(this) > 0 && otherFromE->getJunctionPriority(this) > 0) {
532  return mustBrake(fromE, toE, c.toLane);
533  }
534  return false;
535 }
536 
537 
538 void
540  delete myRequest; // possibly recomputation step
541  myRequest = 0;
542  if (myIncomingEdges.size() == 0 || myOutgoingEdges.size() == 0) {
543  // no logic if nothing happens here
545  return;
546  }
547  // check whether the node was set to be unregulated by the user
548  if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", getID())
549  || (oc.getBool("keep-nodes-unregulated.district-nodes") && (isNearDistrict() || isDistrict()))) {
551  return;
552  }
553  // compute the logic if necessary or split the junction
555  // build the request
556  myRequest = new NBRequest(ec, this,
558  // check whether it is not too large
559  unsigned int numConnections = myRequest->getSizes().second;
560  if (numConnections >= 64) {
561  // yep -> make it untcontrolled, warn
562  WRITE_WARNING("Junction '" + getID() + "' is too complicated (#links>64); will be set to unregulated.");
563  delete myRequest;
564  myRequest = 0;
566  } else if (numConnections == 0) {
567  delete myRequest;
568  myRequest = 0;
570  } else {
572  }
573  }
574 }
575 
576 
577 bool
579  if (myRequest) {
580  myRequest->writeLogic(myID, into);
581  return true;
582  }
583  return false;
584 }
585 
586 
587 void
588 NBNode::computeNodeShape(bool leftHand) {
589  if (myIncomingEdges.size() == 0 && myOutgoingEdges.size() == 0) {
590  return;
591  }
592  try {
593  NBNodeShapeComputer computer(*this);
594  myPoly = computer.compute(leftHand);
595  } catch (InvalidArgument&) {
596  WRITE_WARNING("For node '" + getID() + "': could not compute shape.");
597  // make sure our shape is not empty because our XML schema forbids empty attributes
598  myPoly.clear();
600  }
601 }
602 
603 
604 void
606  // special case a):
607  // one in, one out, the outgoing has one lane more
608  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1
609  && myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[0]->getNumLanes() - 1
610  && myIncomingEdges[0] != myOutgoingEdges[0]
611  && myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0])) {
612 
613  NBEdge* incoming = myIncomingEdges[0];
614  NBEdge* outgoing = myOutgoingEdges[0];
615  // check if it's not the turnaround
616  if (incoming->getTurnDestination() == outgoing) {
617  // will be added later or not...
618  return;
619  }
620  for (int i = 0; i < (int) incoming->getNumLanes(); ++i) {
621  incoming->setConnection(i, outgoing, i + 1, NBEdge::L2L_COMPUTED);
622  }
623  incoming->setConnection(0, outgoing, 0, NBEdge::L2L_COMPUTED);
624  return;
625  }
626  // special case b):
627  // two in, one out, the outgoing has the same number of lanes as the sum of the incoming
628  // --> highway on-ramp
629  bool check = false;
630  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 1) {
631  check = myIncomingEdges[0]->getNumLanes() + myIncomingEdges[1]->getNumLanes() == myOutgoingEdges[0]->getNumLanes();
632  check &= (myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES);
633  check &= (myIncomingEdges[1]->getStep() <= NBEdge::LANES2EDGES);
634  check &= myIncomingEdges[0] != myOutgoingEdges[0];
635  check &= myIncomingEdges[1] != myOutgoingEdges[0];
636  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0]);
637  check &= myIncomingEdges[1]->isConnectedTo(myOutgoingEdges[0]);
638  }
639  if (check) {
640  NBEdge* inc1 = myIncomingEdges[0];
641  NBEdge* inc2 = myIncomingEdges[1];
642  // for internal: check which one is the rightmost
643  SUMOReal a1 = inc1->getAngleAtNode(this);
644  SUMOReal a2 = inc2->getAngleAtNode(this);
647  if (ccw > cw) {
648  std::swap(inc1, inc2);
649  }
650  inc1->addLane2LaneConnections(0, myOutgoingEdges[0], 0, inc1->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
651  inc2->addLane2LaneConnections(0, myOutgoingEdges[0], inc1->getNumLanes(), inc2->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
652  return;
653  }
654  // special case c):
655  // one in, two out, the incoming has the same number of lanes as the sum of the outgoing
656  // --> highway off-ramp
657  check = false;
658  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 2) {
659  check = myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[1]->getNumLanes() + myOutgoingEdges[0]->getNumLanes();
660  check &= (myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES);
661  check &= myIncomingEdges[0] != myOutgoingEdges[0];
662  check &= myIncomingEdges[0] != myOutgoingEdges[1];
663  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0]);
664  check &= myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[1]);
665  }
666  if (check) {
667  NBEdge* out1 = myOutgoingEdges[0];
668  NBEdge* out2 = myOutgoingEdges[1];
669  // for internal: check which one is the rightmost
670  SUMOReal a1 = out1->getAngleAtNode(this);
671  SUMOReal a2 = out2->getAngleAtNode(this);
674  if (ccw < cw) {
675  std::swap(out1, out2);
676  }
677  myIncomingEdges[0]->addLane2LaneConnections(0, out1, 0, out1->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
678  myIncomingEdges[0]->addLane2LaneConnections(out1->getNumLanes(), out2, 0, out2->getNumLanes(), NBEdge::L2L_VALIDATED, false, true);
679  return;
680  }
681 
682  // go through this node's outgoing edges
683  // for every outgoing edge, compute the distribution of the node's
684  // incoming edges on this edge when approaching this edge
685  // the incoming edges' steps will then also be marked as LANE2LANE_RECHECK...
686  EdgeVector::reverse_iterator i;
687  for (i = myOutgoingEdges.rbegin(); i != myOutgoingEdges.rend(); i++) {
688  NBEdge* currentOutgoing = *i;
689  // get the information about edges that do approach this edge
690  EdgeVector* approaching = getEdgesThatApproach(currentOutgoing);
691  if (approaching->size() != 0) {
692  ApproachingDivider divider(approaching, currentOutgoing);
693  Bresenham::compute(&divider, static_cast<unsigned int>(approaching->size()),
694  currentOutgoing->getNumLanes());
695  }
696  delete approaching;
697  }
698  // ... but we may have the case that there are no outgoing edges
699  // In this case, we have to mark the incoming edges as being in state
700  // LANE2LANE( not RECHECK) by hand
701  if (myOutgoingEdges.size() == 0) {
702  for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
703  (*i)->markAsInLane2LaneState();
704  }
705  }
706 }
707 
708 
709 EdgeVector*
711  // get the position of the node to get the approaching nodes of
712  EdgeVector::const_iterator i = find(myAllEdges.begin(),
713  myAllEdges.end(), currentOutgoing);
714  // get the first possible approaching edge
716  // go through the list of edges clockwise and add the edges
717  EdgeVector* approaching = new EdgeVector();
718  for (; *i != currentOutgoing;) {
719  // check only incoming edges
720  if ((*i)->getToNode() == this && (*i)->getTurnDestination() != currentOutgoing) {
721  std::vector<int> connLanes = (*i)->getConnectionLanes(currentOutgoing);
722  if (connLanes.size() != 0) {
723  approaching->push_back(*i);
724  }
725  }
726  NBContHelper::nextCW(myAllEdges, i);
727  }
728  return approaching;
729 }
730 
731 
732 void
733 NBNode::replaceOutgoing(NBEdge* which, NBEdge* by, unsigned int laneOff) {
734  // replace the edge in the list of outgoing nodes
735  EdgeVector::iterator i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), which);
736  if (i != myOutgoingEdges.end()) {
737  (*i) = by;
738  i = find(myAllEdges.begin(), myAllEdges.end(), which);
739  (*i) = by;
740  }
741  // replace the edge in connections of incoming edges
742  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); ++i) {
743  (*i)->replaceInConnections(which, by, laneOff);
744  }
745  // replace within the connetion prohibition dependencies
746  replaceInConnectionProhibitions(which, by, 0, laneOff);
747 }
748 
749 
750 void
752  // replace edges
753  unsigned int laneOff = 0;
754  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
755  replaceOutgoing(*i, by, laneOff);
756  laneOff += (*i)->getNumLanes();
757  }
758  // removed SUMOReal occurences
760  // check whether this node belongs to a district and the edges
761  // must here be also remapped
762  if (myDistrict != 0) {
763  myDistrict->replaceOutgoing(which, by);
764  }
765 }
766 
767 
768 void
769 NBNode::replaceIncoming(NBEdge* which, NBEdge* by, unsigned int laneOff) {
770  // replace the edge in the list of incoming nodes
771  EdgeVector::iterator i = find(myIncomingEdges.begin(), myIncomingEdges.end(), which);
772  if (i != myIncomingEdges.end()) {
773  (*i) = by;
774  i = find(myAllEdges.begin(), myAllEdges.end(), which);
775  (*i) = by;
776  }
777  // replace within the connetion prohibition dependencies
778  replaceInConnectionProhibitions(which, by, laneOff, 0);
779 }
780 
781 
782 void
784  // replace edges
785  unsigned int laneOff = 0;
786  for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
787  replaceIncoming(*i, by, laneOff);
788  laneOff += (*i)->getNumLanes();
789  }
790  // removed SUMOReal occurences
792  // check whether this node belongs to a district and the edges
793  // must here be also remapped
794  if (myDistrict != 0) {
795  myDistrict->replaceIncoming(which, by);
796  }
797 }
798 
799 
800 
801 void
803  unsigned int whichLaneOff, unsigned int byLaneOff) {
804  // replace in keys
805  NBConnectionProhibits::iterator j = myBlockedConnections.begin();
806  while (j != myBlockedConnections.end()) {
807  bool changed = false;
808  NBConnection c = (*j).first;
809  if (c.replaceFrom(which, whichLaneOff, by, byLaneOff)) {
810  changed = true;
811  }
812  if (c.replaceTo(which, whichLaneOff, by, byLaneOff)) {
813  changed = true;
814  }
815  if (changed) {
816  myBlockedConnections[c] = (*j).second;
817  myBlockedConnections.erase(j);
818  j = myBlockedConnections.begin();
819  } else {
820  j++;
821  }
822  }
823  // replace in values
824  for (j = myBlockedConnections.begin(); j != myBlockedConnections.end(); j++) {
825  NBConnectionVector& prohibiting = (*j).second;
826  for (NBConnectionVector::iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
827  NBConnection& sprohibiting = *k;
828  sprohibiting.replaceFrom(which, whichLaneOff, by, byLaneOff);
829  sprohibiting.replaceTo(which, whichLaneOff, by, byLaneOff);
830  }
831  }
832 }
833 
834 
835 
836 void
838  unsigned int i, j;
839  // check incoming
840  for (i = 0; myIncomingEdges.size() > 0 && i < myIncomingEdges.size() - 1; i++) {
841  j = i + 1;
842  while (j < myIncomingEdges.size()) {
843  if (myIncomingEdges[i] == myIncomingEdges[j]) {
844  myIncomingEdges.erase(myIncomingEdges.begin() + j);
845  } else {
846  j++;
847  }
848  }
849  }
850  // check outgoing
851  for (i = 0; myOutgoingEdges.size() > 0 && i < myOutgoingEdges.size() - 1; i++) {
852  j = i + 1;
853  while (j < myOutgoingEdges.size()) {
854  if (myOutgoingEdges[i] == myOutgoingEdges[j]) {
855  myOutgoingEdges.erase(myOutgoingEdges.begin() + j);
856  } else {
857  j++;
858  }
859  }
860  }
861  // check all
862  for (i = 0; myAllEdges.size() > 0 && i < myAllEdges.size() - 1; i++) {
863  j = i + 1;
864  while (j < myAllEdges.size()) {
865  if (myAllEdges[i] == myAllEdges[j]) {
866  myAllEdges.erase(myAllEdges.begin() + j);
867  } else {
868  j++;
869  }
870  }
871  }
872 }
873 
874 
875 bool
876 NBNode::hasIncoming(const NBEdge* const e) const {
877  return find(myIncomingEdges.begin(), myIncomingEdges.end(), e) != myIncomingEdges.end();
878 }
879 
880 
881 bool
882 NBNode::hasOutgoing(const NBEdge* const e) const {
883  return find(myOutgoingEdges.begin(), myOutgoingEdges.end(), e) != myOutgoingEdges.end();
884 }
885 
886 
887 NBEdge*
889  EdgeVector edges = myIncomingEdges;
890  if (find(edges.begin(), edges.end(), e) != edges.end()) {
891  edges.erase(find(edges.begin(), edges.end(), e));
892  }
893  if (edges.size() == 0) {
894  return 0;
895  }
896  if (e->getToNode() == this) {
897  sort(edges.begin(), edges.end(), NBContHelper::edge_opposite_direction_sorter(e, this));
898  } else {
899  sort(edges.begin(), edges.end(), NBContHelper::edge_similar_direction_sorter(e));
900  }
901  return edges[0];
902 }
903 
904 
905 void
907  const NBConnection& mustStop) {
908  if (mayDrive.getFrom() == 0 ||
909  mayDrive.getTo() == 0 ||
910  mustStop.getFrom() == 0 ||
911  mustStop.getTo() == 0) {
912 
913  WRITE_WARNING("Something went wrong during the building of a connection...");
914  return; // !!! mark to recompute connections
915  }
916  NBConnectionVector conn = myBlockedConnections[mustStop];
917  conn.push_back(mayDrive);
918  myBlockedConnections[mustStop] = conn;
919 }
920 
921 
922 NBEdge*
923 NBNode::getPossiblySplittedIncoming(const std::string& edgeid) {
924  unsigned int size = (unsigned int) edgeid.length();
925  for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
926  std::string id = (*i)->getID();
927  if (id.substr(0, size) == edgeid) {
928  return *i;
929  }
930  }
931  return 0;
932 }
933 
934 
935 NBEdge*
936 NBNode::getPossiblySplittedOutgoing(const std::string& edgeid) {
937  unsigned int size = (unsigned int) edgeid.length();
938  for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
939  std::string id = (*i)->getID();
940  if (id.substr(0, size) == edgeid) {
941  return *i;
942  }
943  }
944  return 0;
945 }
946 
947 
948 void
949 NBNode::removeEdge(NBEdge* edge, bool removeFromConnections) {
950  EdgeVector::iterator i = find(myAllEdges.begin(), myAllEdges.end(), edge);
951  if (i != myAllEdges.end()) {
952  myAllEdges.erase(i);
953  i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge);
954  if (i != myOutgoingEdges.end()) {
955  myOutgoingEdges.erase(i);
956  } else {
957  i = find(myIncomingEdges.begin(), myIncomingEdges.end(), edge);
958  if (i != myIncomingEdges.end()) {
959  myIncomingEdges.erase(i);
960  } else {
961  // edge must have been either incoming or outgoing
962  assert(false);
963  }
964  }
965  if (removeFromConnections) {
966  for (i = myAllEdges.begin(); i != myAllEdges.end(); ++i) {
967  (*i)->removeFromConnections(edge);
968  }
969  }
970  }
971 }
972 
973 
974 Position
976  Position pos(0, 0);
977  EdgeVector::const_iterator i;
978  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
979  NBNode* conn = (*i)->getFromNode();
980  Position toAdd = conn->getPosition();
981  toAdd.sub(myPosition);
982  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
983  pos.add(toAdd);
984  }
985  for (i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
986  NBNode* conn = (*i)->getToNode();
987  Position toAdd = conn->getPosition();
988  toAdd.sub(myPosition);
989  toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
990  pos.add(toAdd);
991  }
992  pos.mul((SUMOReal) - 1.0 / (myIncomingEdges.size() + myOutgoingEdges.size()));
993  if (pos.x() == 0 && pos.y() == 0) {
994  pos = Position(1, 0);
995  }
996  pos.norm2d();
997  return pos;
998 }
999 
1000 
1001 
1002 void
1004  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1005  (*i)->invalidateConnections();
1006  }
1007 }
1008 
1009 
1010 void
1012  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1013  (*i)->invalidateConnections();
1014  }
1015 }
1016 
1017 
1018 bool
1019 NBNode::mustBrake(const NBEdge* const from, const NBEdge* const to, int toLane) const {
1020  // check whether it is participant to a traffic light
1021  // - controlled links are set by the traffic lights, not the normal
1022  // right-of-way rules
1023  // - uncontrolled participants (spip lanes etc.) should always break
1024  if (myTrafficLights.size() != 0) {
1025  // ok, we have a traffic light, return true by now, it will be later
1026  // controlled by the tls
1027  return true;
1028  }
1029  // unregulated->does not need to brake
1030  if (myRequest == 0) {
1031  return false;
1032  }
1033  // vehicles which do not have a following lane must always decelerate to the end
1034  if (to == 0) {
1035  return true;
1036  }
1037  // check whether any other connection on this node prohibits this connection
1038  bool try1 = myRequest->mustBrake(from, to);
1039  if (!try1 || toLane == -1) {
1040  return try1;
1041  }
1042  if (from->getSpeed() < 70. / 3.6) {
1043  return try1;
1044  }
1045  // on highways (on-ramps, in fact):
1046  // check whether any other connection uses the same destination edge
1047  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1048  if ((*i) == from) {
1049  continue;
1050  }
1051  const std::vector<NBEdge::Connection>& connections = (*i)->getConnections();
1052  for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) {
1053  if ((*j).toEdge == to && ((*j).toLane < 0 || (*j).toLane == toLane)) {
1054  return true;
1055  }
1056  }
1057  }
1058  return false;
1059 }
1060 
1061 
1062 bool
1063 NBNode::isLeftMover(const NBEdge* const from, const NBEdge* const to) const {
1064  // when the junction has only one incoming edge, there are no
1065  // problems caused by left blockings
1066  if (myIncomingEdges.size() == 1 || myOutgoingEdges.size() == 1) {
1067  return false;
1068  }
1069  SUMOReal fromAngle = from->getAngleAtNode(this);
1070  SUMOReal toAngle = to->getAngleAtNode(this);
1071  SUMOReal cw = GeomHelper::getCWAngleDiff(fromAngle, toAngle);
1072  SUMOReal ccw = GeomHelper::getCCWAngleDiff(fromAngle, toAngle);
1073  std::vector<NBEdge*>::const_iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), from);
1074  do {
1076  } while ((!hasOutgoing(*i) || from->isTurningDirectionAt(this, *i)) && *i != from);
1077  return cw < ccw && (*i) == to && myOutgoingEdges.size() > 2;
1078 }
1079 
1080 
1081 bool
1082 NBNode::forbids(const NBEdge* const possProhibitorFrom, const NBEdge* const possProhibitorTo,
1083  const NBEdge* const possProhibitedFrom, const NBEdge* const possProhibitedTo,
1084  bool regardNonSignalisedLowerPriority) const {
1085  return myRequest != 0 && myRequest->forbids(possProhibitorFrom, possProhibitorTo,
1086  possProhibitedFrom, possProhibitedTo,
1087  regardNonSignalisedLowerPriority);
1088 }
1089 
1090 
1091 bool
1092 NBNode::foes(const NBEdge* const from1, const NBEdge* const to1,
1093  const NBEdge* const from2, const NBEdge* const to2) const {
1094  return myRequest != 0 && myRequest->foes(from1, to1, from2, to2);
1095 }
1096 
1097 
1098 void
1100  NBEdge* removed, const EdgeVector& incoming,
1101  const EdgeVector& outgoing) {
1102  assert(find(incoming.begin(), incoming.end(), removed) == incoming.end());
1103  bool changed = true;
1104  while (changed) {
1105  changed = false;
1106  NBConnectionProhibits blockedConnectionsTmp = myBlockedConnections;
1107  NBConnectionProhibits blockedConnectionsNew;
1108  // remap in connections
1109  for (NBConnectionProhibits::iterator i = blockedConnectionsTmp.begin(); i != blockedConnectionsTmp.end(); i++) {
1110  const NBConnection& blocker = (*i).first;
1111  const NBConnectionVector& blocked = (*i).second;
1112  // check the blocked connections first
1113  // check whether any of the blocked must be changed
1114  bool blockedChanged = false;
1115  NBConnectionVector newBlocked;
1116  NBConnectionVector::const_iterator j;
1117  for (j = blocked.begin(); j != blocked.end(); j++) {
1118  const NBConnection& sblocked = *j;
1119  if (sblocked.getFrom() == removed || sblocked.getTo() == removed) {
1120  blockedChanged = true;
1121  }
1122  }
1123  // adapt changes if so
1124  for (j = blocked.begin(); blockedChanged && j != blocked.end(); j++) {
1125  const NBConnection& sblocked = *j;
1126  if (sblocked.getFrom() == removed && sblocked.getTo() == removed) {
1127  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1128  !!! newBlocked.push_back(NBConnection(*k, *k));
1129  }*/
1130  } else if (sblocked.getFrom() == removed) {
1131  assert(sblocked.getTo() != removed);
1132  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1133  newBlocked.push_back(NBConnection(*k, sblocked.getTo()));
1134  }
1135  } else if (sblocked.getTo() == removed) {
1136  assert(sblocked.getFrom() != removed);
1137  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1138  newBlocked.push_back(NBConnection(sblocked.getFrom(), *k));
1139  }
1140  } else {
1141  newBlocked.push_back(NBConnection(sblocked.getFrom(), sblocked.getTo()));
1142  }
1143  }
1144  if (blockedChanged) {
1145  blockedConnectionsNew[blocker] = newBlocked;
1146  changed = true;
1147  }
1148  // if the blocked were kept
1149  else {
1150  if (blocker.getFrom() == removed && blocker.getTo() == removed) {
1151  changed = true;
1152  /* for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
1153  !!! blockedConnectionsNew[NBConnection(*k, *k)] = blocked;
1154  }*/
1155  } else if (blocker.getFrom() == removed) {
1156  assert(blocker.getTo() != removed);
1157  changed = true;
1158  for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
1159  blockedConnectionsNew[NBConnection(*k, blocker.getTo())] = blocked;
1160  }
1161  } else if (blocker.getTo() == removed) {
1162  assert(blocker.getFrom() != removed);
1163  changed = true;
1164  for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
1165  blockedConnectionsNew[NBConnection(blocker.getFrom(), *k)] = blocked;
1166  }
1167  } else {
1168  blockedConnectionsNew[blocker] = blocked;
1169  }
1170  }
1171  }
1172  myBlockedConnections = blockedConnectionsNew;
1173  }
1174  // remap in traffic lights
1175  tc.remapRemoved(removed, incoming, outgoing);
1176 }
1177 
1178 
1180 NBNode::getDirection(const NBEdge* const incoming, const NBEdge* const outgoing) const {
1181  // ok, no connection at all -> dead end
1182  if (outgoing == 0) {
1183  return LINKDIR_NODIR;
1184  }
1185  // turning direction
1186  if (incoming->isTurningDirectionAt(this, outgoing)) {
1187  return LINKDIR_TURN;
1188  }
1189  // get the angle between incoming/outgoing at the junction
1190  SUMOReal angle =
1191  NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outgoing->getAngleAtNode(this));
1192  // ok, should be a straight connection
1193  if (abs((int) angle) + 1 < 45) {
1194  return LINKDIR_STRAIGHT;
1195  }
1196 
1197  // check for left and right, first
1198  if (angle > 0) {
1199  // check whether any other edge goes further to the right
1200  EdgeVector::const_iterator i =
1201  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1203  while ((*i) != incoming) {
1204  if ((*i)->getFromNode() == this) {
1205  return LINKDIR_PARTRIGHT;
1206  }
1207  NBContHelper::nextCW(myAllEdges, i);
1208  }
1209  return LINKDIR_RIGHT;
1210  }
1211  // check whether any other edge goes further to the left
1212  EdgeVector::const_iterator i =
1213  find(myAllEdges.begin(), myAllEdges.end(), outgoing);
1215  while ((*i) != incoming) {
1216  if ((*i)->getFromNode() == this && !incoming->isTurningDirectionAt(this, *i)) {
1217  return LINKDIR_PARTLEFT;
1218  }
1219  NBContHelper::nextCCW(myAllEdges, i);
1220  }
1221  return LINKDIR_LEFT;
1222 }
1223 
1224 
1225 LinkState
1226 NBNode::getLinkState(const NBEdge* incoming, NBEdge* outgoing, int fromlane,
1227  bool mayDefinitelyPass, const std::string& tlID) const {
1228  if (tlID != "") {
1230  }
1231  if (outgoing == 0) { // always off
1233  }
1235  return LINKSTATE_EQUAL; // all the same
1236  }
1237  if ((!incoming->isInnerEdge() && mustBrake(incoming, outgoing, fromlane)) && !mayDefinitelyPass) {
1238  return LINKSTATE_MINOR; // minor road
1239  }
1240  // traffic lights are not regarded here
1241  return LINKSTATE_MAJOR;
1242 }
1243 
1244 
1245 bool
1247  // check whether this node is included in a traffic light
1248  if (myTrafficLights.size() != 0) {
1249  return false;
1250  }
1251  EdgeVector::const_iterator i;
1252  // one in, one out -> just a geometry ...
1253  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1254  // ... if types match ...
1255  if (!myIncomingEdges[0]->expandableBy(myOutgoingEdges[0])) {
1256  return false;
1257  }
1258  //
1259  return myIncomingEdges[0]->getFromNode() != myOutgoingEdges[0]->getToNode();
1260  }
1261  // two in, two out -> may be something else
1262  if (myOutgoingEdges.size() == 2 && myIncomingEdges.size() == 2) {
1263  // check whether the origin nodes of the incoming edges differ
1264  std::set<NBNode*> origSet;
1265  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1266  origSet.insert((*i)->getFromNode());
1267  }
1268  if (origSet.size() < 2) {
1269  return false;
1270  }
1271  // check whether this node is an intermediate node of
1272  // a two-directional street
1273  for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1274  // try to find the opposite direction
1275  NBNode* origin = (*i)->getFromNode();
1276  // find the back direction of the current edge
1277  EdgeVector::const_iterator j =
1278  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1280  // check whether the back direction exists
1281  if (j != myOutgoingEdges.end()) {
1282  // check whether the edge from the backdirection (must be
1283  // the counter-clockwise one) may be joined with the current
1285  // check whether the types allow joining
1286  if (!(*i)->expandableBy(*j)) {
1287  return false;
1288  }
1289  } else {
1290  // ok, at least one outgoing edge is not an opposite
1291  // of an incoming one
1292  return false;
1293  }
1294  }
1295  return true;
1296  }
1297  // ok, a real node
1298  return false;
1299 }
1300 
1301 
1302 std::vector<std::pair<NBEdge*, NBEdge*> >
1304  assert(checkIsRemovable());
1305  std::vector<std::pair<NBEdge*, NBEdge*> > ret;
1306  // one in, one out-case
1307  if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
1308  ret.push_back(
1309  std::pair<NBEdge*, NBEdge*>(
1311  return ret;
1312  }
1313  // two in, two out-case
1314  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1315  NBNode* origin = (*i)->getFromNode();
1316  EdgeVector::const_iterator j =
1317  find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
1320  ret.push_back(std::pair<NBEdge*, NBEdge*>(*i, *j));
1321  }
1322  return ret;
1323 }
1324 
1325 
1326 const PositionVector&
1328  return myPoly;
1329 }
1330 
1331 
1332 NBEdge*
1334  for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
1335  if ((*i)->getToNode() == n) {
1336  return (*i);
1337  }
1338  }
1339  return 0;
1340 }
1341 
1342 
1343 bool
1345  if (isDistrict()) {
1346  return false;
1347  }
1348  EdgeVector edges;
1349  copy(getIncomingEdges().begin(), getIncomingEdges().end(),
1350  back_inserter(edges));
1351  copy(getOutgoingEdges().begin(), getOutgoingEdges().end(),
1352  back_inserter(edges));
1353  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
1354  NBEdge* t = *j;
1355  NBNode* other = 0;
1356  if (t->getToNode() == this) {
1357  other = t->getFromNode();
1358  } else {
1359  other = t->getToNode();
1360  }
1361  EdgeVector edges2;
1362  copy(other->getIncomingEdges().begin(), other->getIncomingEdges().end(), back_inserter(edges2));
1363  copy(other->getOutgoingEdges().begin(), other->getOutgoingEdges().end(), back_inserter(edges2));
1364  for (EdgeVector::const_iterator k = edges2.begin(); k != edges2.end(); ++k) {
1365  if ((*k)->getFromNode()->isDistrict() || (*k)->getToNode()->isDistrict()) {
1366  return true;
1367  }
1368  }
1369  }
1370  return false;
1371 }
1372 
1373 
1374 bool
1376  return myType == NODETYPE_DISTRICT;
1377 }
1378 
1379 
1380 void
1382  unsigned int noInternalNoSplits = 0;
1383  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1384  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
1385  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
1386  if ((*k).toEdge == 0) {
1387  continue;
1388  }
1389  noInternalNoSplits++;
1390  }
1391  }
1392  unsigned int lno = 0;
1393  unsigned int splitNo = 0;
1394  for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
1395  (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
1396  }
1397 }
1398 
1399 
1400 bool
1402  if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
1403  return true;
1404  }
1405  if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
1406  // check whether the incoming and outgoing edges are pairwise (near) parallel and
1407  // thus the only cross-connections could be turn-arounds
1408  NBEdge* out0 = myOutgoingEdges[0];
1409  NBEdge* out1 = myOutgoingEdges[1];
1410  for (EdgeVector::const_iterator it = myIncomingEdges.begin(); it != myIncomingEdges.end(); ++it) {
1411  NBEdge* inEdge = *it;
1412  SUMOReal angle0 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out0->getAngleAtNode(this)));
1413  SUMOReal angle1 = fabs(NBHelpers::relAngle(inEdge->getAngleAtNode(this), out1->getAngleAtNode(this)));
1414  if (MAX2(angle0, angle1) <= 160) {
1415  // neither of the outgoing edges is parallel to inEdge
1416  return false;
1417  }
1418  }
1419  return true;
1420  }
1421  return false;
1422 }
1423 
1424 /****************************************************************************/
1425