SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBNodeShapeComputer.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // This class computes shapes of junctions
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
12 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <algorithm>
36 #include <utils/geom/GeomHelper.h>
37 #include <utils/common/StdDefs.h>
39 #include <utils/common/ToString.h>
41 #include "NBNode.h"
42 #include "NBNodeShapeComputer.h"
43 
44 #ifdef CHECK_MEMORY_LEAKS
45 #include <foreign/nvwa/debug_new.h>
46 #endif // CHECK_MEMORY_LEAKS
47 
48 
49 // ===========================================================================
50 // method definitions
51 // ===========================================================================
53  : myNode(node) {}
54 
55 
57 
58 
61  UNUSED_PARAMETER(leftHand);
62  PositionVector ret;
63  // check whether the node is a dead end node or a node where only turning is possible
64  // in this case, we will use "computeNodeShapeByCrosses"
65  bool singleDirection = false;
66  if (myNode.myAllEdges.size() == 1) {
67  singleDirection = true;
68  }
69  if (myNode.myAllEdges.size() == 2 && myNode.getIncomingEdges().size() == 1) {
70  if (myNode.getIncomingEdges()[0]->isTurningDirectionAt(&myNode, myNode.getOutgoingEdges()[0])) {
71  singleDirection = true;
72  }
73  }
74  if (singleDirection) {
76  }
77  // check whether the node is a just something like a geometry
78  // node (one in and one out or two in and two out, pair-wise continuations)
79  // also in this case "computeNodeShapeByCrosses" is used
80  bool geometryLike = myNode.isSimpleContinuation();
81  if (geometryLike) {
82  // additionally, the angle between the edges must not be larger than 45 degrees
83  // (otherwise, we will try to compute the shape in a different way)
84  const EdgeVector& incoming = myNode.getIncomingEdges();
85  const EdgeVector& outgoing = myNode.getOutgoingEdges();
86  SUMOReal maxAngle = SUMOReal(0);
87  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
88  SUMOReal ia = (*i)->getAngleAtNode(&myNode);
89  for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); ++j) {
90  SUMOReal oa = (*j)->getAngleAtNode(&myNode);
92  if (22.5 >= ad) {
93  maxAngle = MAX2(ad, maxAngle);
94  }
95  }
96  }
97  if (maxAngle > 22.5) {
99  }
100  }
101 
102  //
103  ret = computeContinuationNodeShape(geometryLike);
104  // fail fall-back: use "computeNodeShapeByCrosses"
105  if (ret.size() < 3) {
107  }
108  return ret;
109 }
110 
111 
112 void
114  Line sub(l1.lineAt(0).getPositionAtDistance(100), l1[1]);
115  Line tmp(sub);
116  tmp.rotateAtP1(PI / 2);
117  tmp.extrapolateBy(100);
118  if (l1.intersects(tmp.p1(), tmp.p2())) {
119  SUMOReal offset1 = l1.intersectsAtLengths2D(tmp)[0];
120  Line tl1 = Line(
121  l1.lineAt(0).getPositionAtDistance(offset1),
122  l1[1]);
123  tl1.extrapolateBy(100);
124  l1.replaceAt(0, tl1.p1());
125  }
126  if (l2.intersects(tmp.p1(), tmp.p2())) {
127  SUMOReal offset2 = l2.intersectsAtLengths2D(tmp)[0];
128  Line tl2 = Line(
129  l2.lineAt(0).getPositionAtDistance(offset2),
130  l2[1]);
131  tl2.extrapolateBy(100);
132  l2.replaceAt(0, tl2.p1());
133  }
134 }
135 
136 
137 void
139  PositionVector counter,
140  size_t counterLanes, SUMOReal counterDist,
141  int laneDiff) {
142  counter.extrapolate(100);
143  Position counterPos = counter.positionAtLengthPosition2D(counterDist);
144  PositionVector t = g;
145  t.extrapolate(100);
147  if (p >= 0) {
148  counterPos = t.positionAtLengthPosition2D(p);
149  }
150  if (g[-1].distanceTo(counterPos) < SUMO_const_laneWidth * (SUMOReal) counterLanes) {
151  g.replaceAt(g.size() - 1, counterPos);
152  } else {
153  g.push_back_noDoublePos(counterPos);
154  }
155  if (decenter) {
156  Line l(g[-2], g[-1]);
158  l.move2side(-factor);//SUMO_const_laneWidthAndOffset);
159  g.replaceAt(g.size() - 1, l.p2());
160  }
161 }
162 
163 
164 void
166  PositionVector counter,
167  size_t counterLanes, SUMOReal counterDist,
168  int laneDiff) {
169  counter.extrapolate(100);
170  Position counterPos = counter.positionAtLengthPosition2D(counterDist);
171  PositionVector t = g;
172  t.extrapolate(100);
174  if (p >= 0) {
175  counterPos = t.positionAtLengthPosition2D(p);
176  }
177  if (g[0].distanceTo(counterPos) < SUMO_const_laneWidth * (SUMOReal) counterLanes) {
178  g.replaceAt(0, counterPos);
179  } else {
180  g.push_front_noDoublePos(counterPos);
181  }
182  if (decenter) {
183  Line l(g[0], g[1]);
185  l.move2side(-factor);
186  g.replaceAt(0, l.p1());
187  }
188 }
189 
190 
191 
194  // if we have less than two edges, we can not compute the node's shape this way
195  if (myNode.myAllEdges.size() < 2) {
196  return PositionVector();
197  }
198  // initialise
199  EdgeVector::const_iterator i;
200  // edges located in the value-vector have the same direction as the key edge
201  std::map<NBEdge*, EdgeVector > same;
202  // the counter-clockwise boundary of the edge regarding possible same-direction edges
203  std::map<NBEdge*, PositionVector> geomsCCW;
204  // the clockwise boundary of the edge regarding possible same-direction edges
205  std::map<NBEdge*, PositionVector> geomsCW;
206  // store relationships
207  std::map<NBEdge*, NBEdge*> ccwBoundary;
208  std::map<NBEdge*, NBEdge*> cwBoundary;
209  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end(); i++) {
210  cwBoundary[*i] = *i;
211  ccwBoundary[*i] = *i;
212  }
213  // check which edges are parallel
214  joinSameDirectionEdges(same, geomsCCW, geomsCW);
215  // compute unique direction list
216  EdgeVector newAll = computeUniqueDirectionList(same, geomsCCW, geomsCW, ccwBoundary, cwBoundary);
217  // if we have only two "directions", let's not compute the geometry using this method
218  if (newAll.size() < 2) {
219  return PositionVector();
220  }
221  // combine all geoms
222  std::map<NBEdge*, bool> myExtended;
223  std::map<NBEdge*, SUMOReal> distances;
224  for (i = newAll.begin(); i != newAll.end(); ++i) {
225  EdgeVector::const_iterator cwi = i;
226  cwi++;
227  if (cwi == newAll.end()) {
228  cwi = newAll.begin();
229  }
230  EdgeVector::const_iterator ccwi = i;
231  if (ccwi == newAll.begin()) {
232  ccwi = newAll.end() - 1;
233  } else {
234  ccwi--;
235  }
236 
237  assert(geomsCCW.find(*i) != geomsCCW.end());
238  assert(geomsCW.find(*ccwi) != geomsCW.end());
239  assert(geomsCW.find(*cwi) != geomsCW.end());
240  SUMOReal angleI = geomsCCW[*i].lineAt(0).atan2PositiveAngle();
241  SUMOReal angleCCW = geomsCW[*ccwi].lineAt(0).atan2PositiveAngle();
242  SUMOReal angleCW = geomsCW[*cwi].lineAt(0).atan2PositiveAngle();
243  SUMOReal ccad;
244  SUMOReal cad;
245  SUMOReal twoPI = (SUMOReal)(2 * PI);
246  if (angleI > angleCCW) {
247  ccad = angleI - angleCCW;
248  } else {
249  ccad = twoPI - angleCCW + angleI;
250  }
251 
252  if (angleI > angleCW) {
253  cad = twoPI - angleI + angleCW;
254  } else {
255  cad = angleCW - angleI;
256  }
257  if (ccad < 0) {
258  ccad += twoPI;
259  }
260  if (ccad > twoPI) {
261  ccad -= twoPI;
262  }
263  if (cad < 0) {
264  cad += twoPI;
265  }
266  if (cad > twoPI) {
267  cad -= twoPI;
268  }
269 
270  if (simpleContinuation && ccad < (SUMOReal)(45. / 180.*PI)) {
271  ccad += twoPI;
272  }
273  if (simpleContinuation && cad < (SUMOReal)(45. / 180.*PI)) {
274  cad += twoPI;
275  }
276 
277  if (fabs(ccad - cad) < (SUMOReal) 0.1 && *cwi == *ccwi) {
278  // compute the mean position between both edges ends ...
279  Position p;
280  if (myExtended.find(*ccwi) != myExtended.end()) {
281  p = geomsCCW[*ccwi][0];
282  p.add(geomsCW[*ccwi][0]);
283  p.mul(0.5);
284  } else {
285  p = geomsCCW[*ccwi][0];
286  p.add(geomsCW[*ccwi][0]);
287  p.add(geomsCCW[*i][0]);
288  p.add(geomsCW[*i][0]);
289  p.mul(0.25);
290  }
291  // ... compute the distance to this point ...
292  SUMOReal dist = geomsCCW[*i].nearest_position_on_line_to_point2D(p);
293  if (dist < 0) {
294  // ok, we have the problem that even the extrapolated geometry
295  // does not reach the point
296  // in this case, the geometry has to be extenden... too bad ...
297  // ... let's append the mean position to the geometry
298  PositionVector g = (*i)->getGeometry();
299  if (myNode.hasIncoming(*i)) {
301  } else {
303  }
304  (*i)->setGeometry(g);
305  // and rebuild previous information
306  geomsCCW[*i] = (*i)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
307  geomsCCW[*i].extrapolate(100);
308  geomsCW[*i] = (*i)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
309  geomsCW[*i].extrapolate(100);
310  // the distance is now = zero (the point we have appended)
311  distances[*i] = 100;
312  myExtended[*i] = true;
313  } else {
314  if (!simpleContinuation) {
315  // let us put some geometry stuff into it
316  dist = (SUMOReal) 1.5 + dist;
317  }
318  distances[*i] = dist;
319  }
320 
321  } else {
322  if (ccad < cad) {
323  if (!simpleContinuation) {
324  if (geomsCCW[*i].intersects(geomsCW[*ccwi])) {
325  distances[*i] = (SUMOReal) 1.5 + geomsCCW[*i].intersectsAtLengths2D(geomsCW[*ccwi])[0];
326  if (*cwi != *ccwi && geomsCW[*i].intersects(geomsCCW[*cwi])) {
327  SUMOReal a1 = distances[*i];
328  SUMOReal a2 = (SUMOReal) 1.5 + geomsCW[*i].intersectsAtLengths2D(geomsCCW[*cwi])[0];
329  if (ccad > (SUMOReal)((90. + 45.) / 180.*PI) && cad > (SUMOReal)((90. + 45.) / 180.*PI)) {
330  SUMOReal mmin = MIN2(distances[*cwi], distances[*ccwi]);
331  if (mmin > 100) {
332  distances[*i] = (SUMOReal) 5. + (SUMOReal) 100. - (SUMOReal)(mmin - 100); //100 + 1.5;
333  }
334  } else if (a2 > a1 + POSITION_EPS && a2 - a1 < (SUMOReal) 10) {
335  distances[*i] = a2;
336  }
337  }
338  } else {
339  if (*cwi != *ccwi && geomsCW[*i].intersects(geomsCCW[*cwi])) {
340  distances[*i] = (SUMOReal) 1.5 + geomsCW[*i].intersectsAtLengths2D(geomsCCW[*cwi])[0];
341  } else {
342  distances[*i] = (SUMOReal)(100. + 1.5);
343  }
344  }
345  } else {
346  if (geomsCCW[*i].intersects(geomsCW[*ccwi])) {
347  distances[*i] = geomsCCW[*i].intersectsAtLengths2D(geomsCW[*ccwi])[0];
348  } else {
349  distances[*i] = (SUMOReal) 100.;
350  }
351  }
352  } else {
353  if (!simpleContinuation) {
354  if (geomsCW[*i].intersects(geomsCCW[*cwi])) {
355  distances[*i] = (SUMOReal)(1.5 + geomsCW[*i].intersectsAtLengths2D(geomsCCW[*cwi])[0]);
356  if (*cwi != *ccwi && geomsCCW[*i].intersects(geomsCW[*ccwi])) {
357  SUMOReal a1 = distances[*i];
358  SUMOReal a2 = (SUMOReal)(1.5 + geomsCCW[*i].intersectsAtLengths2D(geomsCW[*ccwi])[0]);
359  if (ccad > (SUMOReal)((90. + 45.) / 180.*PI) && cad > (SUMOReal)((90. + 45.) / 180.*PI)) {
360  SUMOReal mmin = MIN2(distances[*cwi], distances[*ccwi]);
361  if (mmin > 100) {
362  distances[*i] = (SUMOReal) 5. + (SUMOReal) 100. - (SUMOReal)(mmin - 100); //100 + 1.5;
363  }
364  } else if (a2 > a1 + POSITION_EPS && a2 - a1 < (SUMOReal) 10) {
365  distances[*i] = a2;
366  }
367  }
368  } else {
369  if (*cwi != *ccwi && geomsCCW[*i].intersects(geomsCW[*ccwi])) {
370  distances[*i] = (SUMOReal) 1.5 + geomsCCW[*i].intersectsAtLengths2D(geomsCW[*ccwi])[0];
371  } else {
372  distances[*i] = (SUMOReal)(100. + 1.5);
373  }
374  }
375  } else {
376  if (geomsCW[*i].intersects(geomsCCW[*cwi])) {
377  distances[*i] = geomsCW[*i].intersectsAtLengths2D(geomsCCW[*cwi])[0];
378  } else {
379  distances[*i] = (SUMOReal) 100;
380  }
381  }
382  }
383  }
384  }
385 
386  for (i = newAll.begin(); i != newAll.end(); ++i) {
387  if (distances.find(*i) != distances.end()) {
388  continue;
389  }
390  EdgeVector::const_iterator cwi = i;
391  cwi++;
392  if (cwi == newAll.end()) {
393  cwi = newAll.begin();
394  }
395  EdgeVector::const_iterator ccwi = i;
396  if (ccwi == newAll.begin()) {
397  ccwi = newAll.end() - 1;
398  } else {
399  ccwi--;
400  }
401 
402  assert(geomsCW.find(*ccwi) != geomsCW.end());
403  assert(geomsCW.find(*cwi) != geomsCW.end());
404  Position p1 = distances.find(*cwi) != distances.end() && distances[*cwi] != -1
405  ? geomsCCW[*cwi].positionAtLengthPosition2D(distances[*cwi])
406  : geomsCCW[*cwi].positionAtLengthPosition2D((SUMOReal) - .1);
407  Position p2 = distances.find(*ccwi) != distances.end() && distances[*ccwi] != -1
408  ? geomsCW[*ccwi].positionAtLengthPosition2D(distances[*ccwi])
409  : geomsCW[*ccwi].positionAtLengthPosition2D((SUMOReal) - .1);
410  Line l(p1, p2);
411  l.extrapolateBy(1000);
412  SUMOReal angleI = geomsCCW[*i].lineAt(0).atan2PositiveAngle();
413  SUMOReal angleCCW = geomsCW[*ccwi].lineAt(0).atan2PositiveAngle();
414  SUMOReal angleCW = geomsCW[*cwi].lineAt(0).atan2PositiveAngle();
415  SUMOReal ccad;
416  SUMOReal cad;
417  SUMOReal twoPI = (SUMOReal)(2 * PI);
418  if (angleI > angleCCW) {
419  ccad = angleI - angleCCW;
420  } else {
421  ccad = twoPI - angleCCW + angleI;
422  }
423 
424  if (angleI > angleCW) {
425  cad = twoPI - angleI + angleCW;
426  } else {
427  cad = angleCW - angleI;
428  }
429 
430  if (ccad < 0) {
431  ccad += twoPI;
432  }
433  if (ccad > twoPI) {
434  ccad -= twoPI;
435  }
436  if (cad < 0) {
437  cad += twoPI;
438  }
439  if (cad > twoPI) {
440  cad -= twoPI;
441  }
442  SUMOReal offset = 0;
443  int laneDiff = (*i)->getNumLanes() - (*ccwi)->getNumLanes();
444  if (*ccwi != *cwi) {
445  laneDiff -= (*cwi)->getNumLanes();
446  }
447  laneDiff = 0;
448  if (myNode.hasIncoming(*i) && (*ccwi)->getNumLanes() % 2 == 1) {
449  laneDiff = 1;
450  }
451  if (myNode.hasOutgoing(*i) && (*cwi)->getNumLanes() % 2 == 1) {
452  laneDiff = 1;
453  }
454 
455  PositionVector g = (*i)->getGeometry();
456  PositionVector counter;
457  if (myNode.hasIncoming(*i)) {
458  if (myNode.hasOutgoing(*ccwi) && myNode.hasOutgoing(*cwi)) {
459  if (distances.find(*cwi) == distances.end()) {
460  return PositionVector();
461  }
462  replaceLastChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
463  (*cwi)->getGeometry(), (*cwi)->getNumLanes(), distances[*cwi],
464  laneDiff);
465  } else {
466  if (distances.find(*ccwi) == distances.end()) {
467  return PositionVector();
468  }
469  counter = (*ccwi)->getGeometry();
470  if (myNode.hasIncoming(*ccwi)) {
471  counter = counter.reverse();
472  }
473  replaceLastChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
474  counter, (*ccwi)->getNumLanes(), distances[*ccwi],
475  laneDiff);
476  }
477  } else {
478  if (myNode.hasIncoming(*ccwi) && myNode.hasIncoming(*cwi)) {
479  if (distances.find(*ccwi) == distances.end()) {
480  return PositionVector();
481  }
482  replaceFirstChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
483  (*ccwi)->getGeometry().reverse(), (*ccwi)->getNumLanes(), distances[*ccwi],
484  laneDiff);
485  } else {
486  if (distances.find(*cwi) == distances.end()) {
487  return PositionVector();
488  }
489  counter = (*cwi)->getGeometry();
490  if (myNode.hasIncoming(*cwi)) {
491  counter = counter.reverse();
492  }
493  replaceFirstChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
494  counter, (*cwi)->getNumLanes(), distances[*cwi],
495  laneDiff);
496  }
497  }
498  (*i)->setGeometry(g);
499 
500  if (cwBoundary[*i] != *i) {
501  PositionVector g = cwBoundary[*i]->getGeometry();
502  PositionVector counter = (*cwi)->getGeometry();
503  if (myNode.hasIncoming(*cwi)) {
504  counter = counter.reverse();
505  }
506  if (myNode.hasIncoming(cwBoundary[*i])) {
507  if (distances.find(*cwi) == distances.end()) {
508  return PositionVector();
509  }
510  replaceLastChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
511  counter, (*cwi)->getNumLanes(), distances[*cwi],
512  laneDiff);
513  } else {
514  if (distances.find(*cwi) == distances.end()) {
515  return PositionVector();
516  }
517  replaceFirstChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
518  counter, (*cwi)->getNumLanes(), distances[*cwi],
519  laneDiff);
520  }
521  cwBoundary[*i]->setGeometry(g);
522  myExtended[cwBoundary[*i]] = true;
523  geomsCW[*i] = cwBoundary[*i]->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
524  } else {
525  geomsCW[*i] = (*i)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
526 
527  }
528 
529  geomsCW[*i].extrapolate(100);
530 
531  if (ccwBoundary[*i] != *i) {
532  PositionVector g = ccwBoundary[*i]->getGeometry();
533  PositionVector counter = (*ccwi)->getGeometry();
534  if (myNode.hasIncoming(*ccwi)) {
535  counter = counter.reverse();
536  }
537  if (myNode.hasIncoming(ccwBoundary[*i])) {
538  if (distances.find(*ccwi) == distances.end()) {
539  return PositionVector();
540  }
541  replaceLastChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
542  counter, (*ccwi)->getNumLanes(), distances[*ccwi],
543  laneDiff);
544  } else {
545  if (distances.find(*cwi) == distances.end()) {
546  return PositionVector();
547  }
548  replaceFirstChecking(g, (*i)->getLaneSpreadFunction() == LANESPREAD_CENTER,
549  counter, (*cwi)->getNumLanes(), distances[*cwi],
550  laneDiff);
551  }
552  ccwBoundary[*i]->setGeometry(g);
553  myExtended[ccwBoundary[*i]] = true;
554  geomsCCW[*i] = ccwBoundary[*i]->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
555  } else {
556  geomsCCW[*i] = (*i)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
557 
558  }
559  geomsCCW[*i].extrapolate(100);
560 
561  computeSameEnd(geomsCW[*i], geomsCCW[*i]);
562 
563  // and rebuild previous information
564  if (((*cwi)->getNumLanes() + (*ccwi)->getNumLanes()) > (*i)->getNumLanes()) {
565  offset = 5;
566  }
567  if (ccwBoundary[*i] != cwBoundary[*i]) {
568  offset = 5;
569  }
570 
571  myExtended[*i] = true;
572  distances[*i] = 100 + offset;
573  }
574 
575  // build
576  PositionVector ret;
577  for (i = newAll.begin(); i != newAll.end(); ++i) {
578  PositionVector l = geomsCCW[*i];
579  SUMOReal len = l.length();
580  SUMOReal offset = distances[*i];
581  if (offset == -1) {
582  offset = (SUMOReal) - .1;
583  }
584  Position p;
585  if (len >= offset) {
586  p = l.positionAtLengthPosition2D(offset);
587  } else {
588  p = l.positionAtLengthPosition2D(len);
589  }
590  ret.push_back_noDoublePos(p);
591  //
592  l = geomsCW[*i];
593  len = l.length();
594  if (len >= offset) {
595  p = l.positionAtLengthPosition2D(offset);
596  } else {
597  p = l.positionAtLengthPosition2D(len);
598  }
599  ret.push_back_noDoublePos(p);
600  }
601  return ret;
602 }
603 
604 
605 
606 void
607 NBNodeShapeComputer::joinSameDirectionEdges(std::map<NBEdge*, EdgeVector >& same,
608  std::map<NBEdge*, PositionVector>& geomsCCW,
609  std::map<NBEdge*, PositionVector>& geomsCW) {
610  EdgeVector::const_iterator i, j;
611  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end() - 1; i++) {
612  // store current edge's boundary as current ccw/cw boundary
613  geomsCCW[*i] = (*i)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
614  geomsCW[*i] = (*i)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
615  // extend the boundary by extroplating it by 100m
616  PositionVector g1 =
617  myNode.hasIncoming(*i)
618  ? (*i)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth)
619  : (*i)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
620  Line l1 = g1.lineAt(0);
621  Line tmp = geomsCCW[*i].lineAt(0);
622  tmp.extrapolateBy(100);
623  geomsCCW[*i].replaceAt(0, tmp.p1());
624  tmp = geomsCW[*i].lineAt(0);
625  tmp.extrapolateBy(100);
626  geomsCW[*i].replaceAt(0, tmp.p1());
627  //
628  for (j = i + 1; j != myNode.myAllEdges.end(); j++) {
629  geomsCCW[*j] = (*j)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
630  geomsCW[*j] = (*j)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
631  PositionVector g2 =
632  myNode.hasIncoming(*j)
633  ? (*j)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth)
634  : (*j)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth);
635  Line l2 = g2.lineAt(0);
636  tmp = geomsCCW[*j].lineAt(0);
637  tmp.extrapolateBy(100);
638  geomsCCW[*j].replaceAt(0, tmp.p1());
639  tmp = geomsCW[*j].lineAt(0);
640  tmp.extrapolateBy(100);
641  geomsCW[*j].replaceAt(0, tmp.p1());
642  if (fabs(l1.atan2DegreeAngle() - l2.atan2DegreeAngle()) < 20) {
643  if (same.find(*i) == same.end()) {
644  same[*i] = EdgeVector();
645  }
646  if (same.find(*j) == same.end()) {
647  same[*j] = EdgeVector();
648  }
649  if (find(same[*i].begin(), same[*i].end(), *j) == same[*i].end()) {
650  same[*i].push_back(*j);
651  }
652  if (find(same[*j].begin(), same[*j].end(), *i) == same[*j].end()) {
653  same[*j].push_back(*i);
654  }
655  }
656  }
657  }
658 }
659 
660 
663  const std::map<NBEdge*, EdgeVector >& same,
664  std::map<NBEdge*, PositionVector>& geomsCCW,
665  std::map<NBEdge*, PositionVector>& geomsCW,
666  std::map<NBEdge*, NBEdge*>& ccwBoundary,
667  std::map<NBEdge*, NBEdge*>& cwBoundary) {
668  EdgeVector newAll = myNode.myAllEdges;
669  EdgeVector::const_iterator j;
670  EdgeVector::iterator i2;
671  std::map<NBEdge*, EdgeVector >::iterator k;
672  bool changed = true;
673  while (changed) {
674  changed = false;
675  for (i2 = newAll.begin(); !changed && i2 != newAll.end();) {
676  EdgeVector other;
677  if (same.find(*i2) != same.end()) {
678  other = same.find(*i2)->second;
679  }
680  for (j = other.begin(); j != other.end(); ++j) {
681  EdgeVector::iterator k = find(newAll.begin(), newAll.end(), *j);
682  if (k != newAll.end()) {
683  if (myNode.hasIncoming(*i2)) {
684  if (myNode.hasIncoming(*j)) {} else {
685  geomsCW[*i2] = geomsCW[*j];
686  cwBoundary[*i2] = *j;
687  computeSameEnd(geomsCW[*i2], geomsCCW[*i2]);
688  }
689  } else {
690  if (myNode.hasIncoming(*j)) {
691  ccwBoundary[*i2] = *j;
692  geomsCCW[*i2] = geomsCCW[*j];
693  computeSameEnd(geomsCW[*i2], geomsCCW[*i2]);
694  } else {}
695  }
696  newAll.erase(k);
697  changed = true;
698  }
699  }
700  if (!changed) {
701  ++i2;
702  }
703  }
704  }
705  return newAll;
706 }
707 
708 
711  PositionVector ret;
712  EdgeVector::const_iterator i;
713  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end(); i++) {
714  // compute crossing with normal
715  Line edgebound1 = (*i)->getCCWBoundaryLine(myNode, SUMO_const_halfLaneWidth).lineAt(0);
716  Line edgebound2 = (*i)->getCWBoundaryLine(myNode, SUMO_const_halfLaneWidth).lineAt(0);
717  Line cross(edgebound1);
718  cross.rotateAtP1(PI / 2.);
719  cross.add(myNode.getPosition() - cross.p1());
720  cross.extrapolateBy(500);
721  edgebound1.extrapolateBy(500);
722  edgebound2.extrapolateBy(500);
723  if (cross.intersects(edgebound1)) {
724  ret.push_back_noDoublePos(cross.intersectsAt(edgebound1));
725  }
726  if (cross.intersects(edgebound2)) {
727  ret.push_back_noDoublePos(cross.intersectsAt(edgebound2));
728  }
729  }
730  return ret;
731 }
732 
733 
734 
735 /****************************************************************************/