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