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.dlr.de/
12 // Copyright (C) 2001-2015 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>
34 #include <iterator>
37 #include <utils/geom/GeomHelper.h>
38 #include <utils/common/StdDefs.h>
41 #include <utils/common/ToString.h>
43 #include "NBNode.h"
44 #include "NBNodeShapeComputer.h"
45 
46 #ifdef CHECK_MEMORY_LEAKS
47 #include <foreign/nvwa/debug_new.h>
48 #endif // CHECK_MEMORY_LEAKS
49 
50 
51 // ===========================================================================
52 // method definitions
53 // ===========================================================================
55  : myNode(node) {}
56 
57 
59 
60 
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 "computeNodeShapeSmall"
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.getOutgoingEdges()[0])) {
72  singleDirection = true;
73  }
74  }
75  if (singleDirection) {
76  return computeNodeShapeSmall();
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 "computeNodeShapeSmall" 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) {
99  return computeNodeShapeSmall();
100  }
101  }
102 
103  //
104  ret = computeNodeShapeDefault(geometryLike);
105  // fail fall-back: use "computeNodeShapeSmall"
106  if (ret.size() < 3) {
107  ret = computeNodeShapeSmall();
108  }
109  return ret;
110 }
111 
112 
113 void
115  Line sub(l1.lineAt(0).getPositionAtDistance2D(100), l1[1]);
116  Line tmp(sub);
117  tmp.rotateAtP1(M_PI / 2);
118  tmp.extrapolateBy2D(100);
119  if (l1.intersects(tmp.p1(), tmp.p2())) {
120  SUMOReal offset1 = l1.intersectsAtLengths2D(tmp)[0];
121  Line tl1 = Line(
122  l1.lineAt(0).getPositionAtDistance2D(offset1),
123  l1[1]);
124  tl1.extrapolateBy2D(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).getPositionAtDistance2D(offset2),
131  l2[1]);
132  tl2.extrapolateBy2D(100);
133  l2.replaceAt(0, tl2.p1());
134  }
135 }
136 
137 
140  // if we have less than two edges, we can not compute the node's shape this way
141  if (myNode.myAllEdges.size() < 2) {
142  return PositionVector();
143  }
144  // magic values
146  const int cornerDetail = OptionsCont::getOptions().getInt("junctions.corner-detail");
147 
148  // initialise
149  EdgeVector::const_iterator i;
150  // edges located in the value-vector have the same direction as the key edge
151  std::map<NBEdge*, std::set<NBEdge*> > same;
152  // the counter-clockwise boundary of the edge regarding possible same-direction edges
153  GeomsMap geomsCCW;
154  // the clockwise boundary of the edge regarding possible same-direction edges
155  GeomsMap geomsCW;
156  // store relationships
157  std::map<NBEdge*, NBEdge*> ccwBoundary;
158  std::map<NBEdge*, NBEdge*> cwBoundary;
159  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end(); i++) {
160  cwBoundary[*i] = *i;
161  ccwBoundary[*i] = *i;
162  }
163  // check which edges are parallel
164  joinSameDirectionEdges(same, geomsCCW, geomsCW);
165  // compute unique direction list
166  EdgeVector newAll = computeUniqueDirectionList(same, geomsCCW, geomsCW, ccwBoundary, cwBoundary);
167  // if we have only two "directions", let's not compute the geometry using this method
168  if (newAll.size() < 2) {
169  return PositionVector();
170  }
171 
172  // All geoms are outoing from myNode.
173  // for every direction in newAll we compute the offset at which the
174  // intersection ends and the edge starts. This value is saved in 'distances'
175  // If the geometries need to be extended to get an intersection, this is
176  // recorded in 'myExtended'
177  std::map<NBEdge*, SUMOReal> distances;
178  std::map<NBEdge*, bool> myExtended;
179 
180  for (i = newAll.begin(); i != newAll.end(); ++i) {
181  EdgeVector::const_iterator cwi = i;
182  EdgeVector::const_iterator ccwi = i;
183  SUMOReal ccad;
184  SUMOReal cad;
185  initNeighbors(newAll, i, geomsCW, geomsCCW, cwi, ccwi, cad, ccad);
186  assert(geomsCCW.find(*i) != geomsCCW.end());
187  assert(geomsCW.find(*ccwi) != geomsCW.end());
188  assert(geomsCW.find(*cwi) != geomsCW.end());
189 
190  // there are only 2 directions and they are almost parallel
191  if (*cwi == *ccwi &&
192  (
193  // no change in lane numbers, even low angles still give a good intersection
194  (simpleContinuation && fabs(ccad - cad) < (SUMOReal) 0.1)
195  // lane numbers change, a direct intersection could be far away from the node position
196  // so we use a larger threshold
197  || (!simpleContinuation && fabs(ccad - cad) < DEG2RAD(22.5)))
198  ) {
199  // compute the mean position between both edges ends ...
200  Position p;
201  if (myExtended.find(*ccwi) != myExtended.end()) {
202  p = geomsCCW[*ccwi][0];
203  p.add(geomsCW[*ccwi][0]);
204  p.mul(0.5);
205  } else {
206  p = geomsCCW[*ccwi][0];
207  p.add(geomsCW[*ccwi][0]);
208  p.add(geomsCCW[*i][0]);
209  p.add(geomsCW[*i][0]);
210  p.mul(0.25);
211  }
212  // ... compute the distance to this point ...
213  SUMOReal dist = geomsCCW[*i].nearest_offset_to_point2D(p);
214  if (dist < 0) {
215  // ok, we have the problem that even the extrapolated geometry
216  // does not reach the point
217  // in this case, the geometry has to be extenden... too bad ...
218  // ... let's append the mean position to the geometry
219  PositionVector g = (*i)->getGeometry();
220  if (myNode.hasIncoming(*i)) {
222  } else {
224  }
225  (*i)->setGeometry(g);
226  // and rebuild previous information
227  geomsCCW[*i] = (*i)->getCCWBoundaryLine(myNode);
228  geomsCCW[*i].extrapolate(100);
229  geomsCW[*i] = (*i)->getCWBoundaryLine(myNode);
230  geomsCW[*i].extrapolate(100);
231  // the distance is now = zero (the point we have appended)
232  distances[*i] = 100;
233  myExtended[*i] = true;
234  } else {
235  if (!simpleContinuation) {
236  // since there are only two (almost parallel) directions, the
237  // concept of a turning radius does not quite fit. Instead we need
238  // to enlarge the intersection to accomodate the change in
239  // the number of lanes
240  // @todo: make this independently configurable
241  dist += radius;
242  }
243  distances[*i] = dist;
244  }
245 
246  } else {
247  // the angles are different enough to compute the intersection of
248  // the outer boundaries directly (or there are more than 2 directions). The "nearer" neighbar causes the furthest distance
249  const bool ccwCloser = ccad < cad;
250  // the border facing the closer neighbor
251  const PositionVector& currGeom = ccwCloser ? geomsCCW[*i] : geomsCW[*i];
252  // the border facing the far neighbor
253  const PositionVector& currGeom2 = ccwCloser ? geomsCW[*i] : geomsCCW[*i];
254  // the border of the closer neighbor
255  const PositionVector& neighGeom = ccwCloser ? geomsCW[*ccwi] : geomsCCW[*cwi];
256  // the border of the far neighbor
257  const PositionVector& neighGeom2 = ccwCloser ? geomsCCW[*cwi] : geomsCW[*ccwi];
258  if (!simpleContinuation) {
259  if (currGeom.intersects(neighGeom)) {
260  distances[*i] = radius + closestIntersection(currGeom, neighGeom, 100);
261  if (*cwi != *ccwi && currGeom2.intersects(neighGeom2)) {
262  const SUMOReal farAngleDist = ccwCloser ? cad : ccad;
263  SUMOReal a1 = distances[*i];
264  SUMOReal a2 = radius + closestIntersection(currGeom2, neighGeom2, 100);
265  if (ccad > DEG2RAD(90. + 45.) && cad > DEG2RAD(90. + 45.)) {
266  SUMOReal mmin = MIN2(distances[*cwi], distances[*ccwi]);
267  if (mmin > 100) {
268  distances[*i] = (SUMOReal) 5. + (SUMOReal) 100. - (SUMOReal)(mmin - 100); //100 + 1.5;
269  }
270  } else if (fabs(a2 - a1) < 10 || farAngleDist < DEG2RAD(135)) {
271  distances[*i] = MAX2(a1, a2);
272  }
273  }
274  } else {
275  if (*cwi != *ccwi && currGeom2.intersects(neighGeom2)) {
276  distances[*i] = radius + currGeom2.intersectsAtLengths2D(neighGeom2)[0];
277  } else {
278  distances[*i] = 100 + radius;
279  }
280  }
281  } else {
282  if (currGeom.intersects(neighGeom)) {
283  distances[*i] = currGeom.intersectsAtLengths2D(neighGeom)[0];
284  } else {
285  distances[*i] = (SUMOReal) 100.;
286  }
287  }
288  }
289  }
290 
291  for (i = newAll.begin(); i != newAll.end(); ++i) {
292  if (distances.find(*i) == distances.end()) {
293  assert(false);
294  distances[*i] = 100;
295  }
296  }
297 
298  // build
299  PositionVector ret;
300  for (i = newAll.begin(); i != newAll.end(); ++i) {
301  const PositionVector& ccwBound = geomsCCW[*i];
302  SUMOReal len = ccwBound.length();
303  SUMOReal offset = distances[*i];
304  if (offset == -1) {
305  offset = (SUMOReal) - .1;
306  }
307  Position p;
308  if (len >= offset) {
309  p = ccwBound.positionAtOffset2D(offset);
310  } else {
311  p = ccwBound.positionAtOffset2D(len);
312  }
313  p.set(p.x(), p.y(), myNode.getPosition().z());
314  if (i != newAll.begin()) {
315  ret.append(getSmoothCorner(geomsCW[*(i - 1)].reverse(), ccwBound, ret[-1], p, cornerDetail));
316  }
317  ret.push_back_noDoublePos(p);
318  //
319  const PositionVector& cwBound = geomsCW[*i];
320  len = cwBound.length();
321  if (len >= offset) {
322  p = cwBound.positionAtOffset2D(offset);
323  } else {
324  p = cwBound.positionAtOffset2D(len);
325  }
326  p.set(p.x(), p.y(), myNode.getPosition().z());
327  ret.push_back_noDoublePos(p);
328  }
329  // final curve segment
330  ret.append(getSmoothCorner(geomsCW[*(newAll.end() - 1)], geomsCCW[*newAll.begin()], ret[-1], ret[0], cornerDetail));
331  return ret;
332 }
333 
334 
335 SUMOReal
337  std::vector<SUMOReal> intersections = geom1.intersectsAtLengths2D(geom2);
338  SUMOReal result = intersections[0];
339  for (std::vector<SUMOReal>::iterator it = intersections.begin() + 1; it != intersections.end(); ++it) {
340  if (fabs(*it - offset) < fabs(result - offset)) {
341  result = *it;
342  }
343  }
344  return result;
345 }
346 
347 
350  const Position& begPoint, const Position& endPoint, int cornerDetail) {
351  PositionVector ret;
352  if (cornerDetail > 0) {
353  begShape = begShape.reverse();
354  begShape[-1] = begPoint;
355  endShape[0] = endPoint;
356  PositionVector curve = myNode.computeSmoothShape(begShape, endShape, cornerDetail + 2, false, 25, 25);
357  if (curve.size() > 2) {
358  curve.eraseAt(0);
359  curve.eraseAt(-1);
360  ret = curve;
361  }
362  }
363  return ret;
364 }
365 
366 void
367 NBNodeShapeComputer::joinSameDirectionEdges(std::map<NBEdge*, std::set<NBEdge*> >& same,
368  GeomsMap& geomsCCW,
369  GeomsMap& geomsCW) {
370  EdgeVector::const_iterator i, j;
371  // compute boundary lines and extend it by 100m
372  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end() - 1; i++) {
373  // store current edge's boundary as current ccw/cw boundary
374  try {
375  geomsCCW[*i] = (*i)->getCCWBoundaryLine(myNode);
376  } catch (InvalidArgument& e) {
377  WRITE_WARNING(std::string("While computing intersection geometry: ") + std::string(e.what()));
378  geomsCCW[*i] = (*i)->getGeometry();
379  }
380  try {
381  geomsCW[*i] = (*i)->getCWBoundaryLine(myNode);
382  } catch (InvalidArgument& e) {
383  WRITE_WARNING(std::string("While computing intersection geometry: ") + std::string(e.what()));
384  geomsCW[*i] = (*i)->getGeometry();
385  }
386  // extend the boundary by extroplating it by 100m
387  PositionVector g1 =
388  myNode.hasIncoming(*i)
389  ? (*i)->getCCWBoundaryLine(myNode)
390  : (*i)->getCWBoundaryLine(myNode);
391  Line l1 = g1.lineAt(0);
392  Line tmp = geomsCCW[*i].lineAt(0);
393  tmp.extrapolateBy2D(100);
394  geomsCCW[*i].replaceAt(0, tmp.p1());
395  tmp = geomsCW[*i].lineAt(0);
396  tmp.extrapolateBy2D(100);
397  geomsCW[*i].replaceAt(0, tmp.p1());
398  //
399  for (j = i + 1; j != myNode.myAllEdges.end(); j++) {
400  geomsCCW[*j] = (*j)->getCCWBoundaryLine(myNode);
401  geomsCW[*j] = (*j)->getCWBoundaryLine(myNode);
402  PositionVector g2 =
403  myNode.hasIncoming(*j)
404  ? (*j)->getCCWBoundaryLine(myNode)
405  : (*j)->getCWBoundaryLine(myNode);
406  Line l2 = g2.lineAt(0);
407  tmp = geomsCCW[*j].lineAt(0);
408  tmp.extrapolateBy2D(100);
409  geomsCCW[*j].replaceAt(0, tmp.p1());
410  tmp = geomsCW[*j].lineAt(0);
411  tmp.extrapolateBy2D(100);
412  geomsCW[*j].replaceAt(0, tmp.p1());
413  }
414  }
415  // compute same (edges where an intersection doesn't work well
416  // (always check an edge and its cw neightbor)
417  // distance to look ahead for a misleading angle
418  const SUMOReal angleChangeLookahead = 35;
419  EdgeSet foundOpposite;
420  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end() - 1; i++) {
421  EdgeVector::const_iterator j = i + 1;
422  if (j == myNode.myAllEdges.end()) {
423  j = myNode.myAllEdges.begin();
424  }
425  const bool incoming = (*i)->getToNode() == &myNode;
426  const bool incoming2 = (*j)->getToNode() == &myNode;
427  const Position positionAtNode = (*i)->getGeometry()[incoming ? -1 : 0];
428  const Position positionAtNode2 = (*j)->getGeometry()[incoming2 ? -1 : 0];
429  PositionVector g1 = incoming ? (*i)->getCCWBoundaryLine(myNode) : (*i)->getCWBoundaryLine(myNode);
430  PositionVector g2 = incoming ? (*j)->getCCWBoundaryLine(myNode) : (*j)->getCWBoundaryLine(myNode);
431  Line l1 = g1.lineAt(0);
432  Line l2 = g2.lineAt(0);
433  const SUMOReal angle1further = (g1.size() > 2 && l1.length2D() < angleChangeLookahead ?
434  g1.lineAt(1).atan2DegreeAngle() : l1.atan2DegreeAngle());
435  const SUMOReal angle2further = (g2.size() > 2 && l2.length2D() < angleChangeLookahead ?
436  g2.lineAt(1).atan2DegreeAngle() : l2.atan2DegreeAngle());
437  const SUMOReal angleDiff = NBHelpers::relAngle(l1.atan2DegreeAngle(), l2.atan2DegreeAngle());
438  const SUMOReal angleDiffFurther = NBHelpers::relAngle(angle1further, angle2further);
439  const bool ambiguousGeometry = ((angleDiff > 0 && angleDiffFurther < 0) || (angleDiff < 0 && angleDiffFurther > 0));
440  const bool differentDirs = (incoming != incoming2);
441  //if (ambiguousGeometry) {
442  // @todo: this warning would be helpful in many cases. However, if angle and angleFurther jump between 179 and -179 it is misleading
443  // WRITE_WARNING("Ambigous angles at node '" + myNode.getID() + "' for edges '" + (*i)->getID() + "' and '" + (*j)->getID() + "'.");
444  //}
445  if (fabs(angleDiff) < 20) {
446  const bool isOpposite = differentDirs && foundOpposite.count(*i) == 0;
447  if (isOpposite) {
448  foundOpposite.insert(*i);
449  foundOpposite.insert(*j);
450  }
451  if (isOpposite || ambiguousGeometry || badIntersection(*i, *j, geomsCW[*i], geomsCCW[*j], 100)) {
452  // maintain equivalence relation for all members of the equivalence class
453  for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
454  if (*j != *k) {
455  same[*k].insert(*j);
456  same[*j].insert(*k);
457  }
458  }
459  for (std::set<NBEdge*>::iterator k = same[*j].begin(); k != same[*j].end(); ++k) {
460  if (*i != *k) {
461  same[*k].insert(*i);
462  same[*i].insert(*k);
463  }
464  }
465  same[*i].insert(*j);
466  same[*j].insert(*i);
467  }
468  }
469  }
470 }
471 
472 
473 bool
475  const PositionVector& e1cw, const PositionVector& e2ccw,
476  SUMOReal distance) {
477  // check whether the two edges are on top of each other. In that case they should be joined
478  // also, if they never touch along their common length
479  const SUMOReal commonLength = MIN3(distance, e1->getGeometry().length(), e2->getGeometry().length());
480  PositionVector geom1 = e1->getGeometry();
481  PositionVector geom2 = e2->getGeometry();
482  // shift to make geom the centerline of the edge regardless of spreadtype
484  geom1.move2side(e1->getTotalWidth() / 2);
485  }
487  geom2.move2side(e2->getTotalWidth() / 2);
488  }
489  // always let geometry start at myNode
490  if (e1->getToNode() == &myNode) {
491  geom1 = geom1.reverse();
492  }
493  if (e2->getToNode() == &myNode) {
494  geom2 = geom2.reverse();
495  }
496  geom1 = geom1.getSubpart2D(0, commonLength);
497  geom2 = geom2.getSubpart2D(0, commonLength);
498  std::vector<SUMOReal> distances = geom1.distances(geom2, true);
499  const SUMOReal minDistanceThreshold = (e1->getTotalWidth() + e2->getTotalWidth()) / 2 + POSITION_EPS;
500  const SUMOReal minDist = VectorHelper<SUMOReal>::minValue(distances);
501  const SUMOReal maxDist = VectorHelper<SUMOReal>::maxValue(distances);
502  const bool onTop = maxDist - POSITION_EPS < minDistanceThreshold;
503  const bool curvingTowards = geom1[0].distanceTo2D(geom2[0]) > minDistanceThreshold && minDist < minDistanceThreshold;
504  const bool intersects = e1cw.intersects(e2ccw);
505  return onTop || curvingTowards || !intersects;
506 }
507 
508 
511  std::map<NBEdge*, std::set<NBEdge*> >& same,
512  GeomsMap& geomsCCW,
513  GeomsMap& geomsCW,
514  std::map<NBEdge*, NBEdge*>& ccwBoundary,
515  std::map<NBEdge*, NBEdge*>& cwBoundary) {
516  EdgeVector newAll = myNode.myAllEdges;
517  std::set<NBEdge*>::const_iterator j;
518  EdgeVector::iterator i2;
519  std::map<NBEdge*, EdgeVector >::iterator k;
520  bool changed = true;
521  while (changed) {
522  changed = false;
523  for (i2 = newAll.begin(); !changed && i2 != newAll.end();) {
524  std::set<NBEdge*> other = same[*i2];
525  for (j = other.begin(); j != other.end(); ++j) {
526  EdgeVector::iterator k = find(newAll.begin(), newAll.end(), *j);
527  if (k != newAll.end()) {
528  if (myNode.hasIncoming(*i2)) {
529  if (myNode.hasIncoming(*j)) {} else {
530  geomsCW[*i2] = geomsCW[*j];
531  cwBoundary[*i2] = *j;
532  computeSameEnd(geomsCW[*i2], geomsCCW[*i2]);
533  }
534  } else {
535  if (myNode.hasIncoming(*j)) {
536  ccwBoundary[*i2] = *j;
537  geomsCCW[*i2] = geomsCCW[*j];
538  computeSameEnd(geomsCW[*i2], geomsCCW[*i2]);
539  } else {}
540  }
541  newAll.erase(k);
542  changed = true;
543  }
544  }
545  if (!changed) {
546  ++i2;
547  }
548  }
549  }
550  return newAll;
551 }
552 
553 
554 void
555 NBNodeShapeComputer::initNeighbors(const EdgeVector& edges, const EdgeVector::const_iterator& current,
556  GeomsMap& geomsCW,
557  GeomsMap& geomsCCW,
558  EdgeVector::const_iterator& cwi,
559  EdgeVector::const_iterator& ccwi,
560  SUMOReal& cad,
561  SUMOReal& ccad) {
562  const SUMOReal twoPI = (SUMOReal)(2 * M_PI);
563  cwi = current;
564  cwi++;
565  if (cwi == edges.end()) {
566  std::advance(cwi, -((int)edges.size())); // set to edges.begin();
567  }
568  ccwi = current;
569  if (ccwi == edges.begin()) {
570  std::advance(ccwi, edges.size() - 1); // set to edges.end() - 1;
571  } else {
572  ccwi--;
573  }
574 
575  const SUMOReal angleCurCCW = geomsCCW[*current].lineAt(0).atan2PositiveAngle();
576  const SUMOReal angleCurCW = geomsCW[*current].lineAt(0).atan2PositiveAngle();
577  const SUMOReal angleCCW = geomsCW[*ccwi].lineAt(0).atan2PositiveAngle();
578  const SUMOReal angleCW = geomsCCW[*cwi].lineAt(0).atan2PositiveAngle();
579  if (angleCurCCW > angleCCW) {
580  ccad = angleCurCCW - angleCCW;
581  } else {
582  ccad = twoPI - (angleCCW - angleCurCCW);
583  }
584 
585  if (angleCurCW > angleCW) {
586  cad = twoPI - (angleCurCW - angleCW);
587  } else {
588  cad = angleCW - angleCurCW;
589  }
590 
591  if (ccad < 0) {
592  ccad += twoPI;
593  }
594  if (ccad > twoPI) {
595  ccad -= twoPI;
596  }
597  if (cad < 0) {
598  cad += twoPI;
599  }
600  if (cad > twoPI) {
601  cad -= twoPI;
602  }
603 }
604 
605 
606 
609  PositionVector ret;
610  EdgeVector::const_iterator i;
611  for (i = myNode.myAllEdges.begin(); i != myNode.myAllEdges.end(); i++) {
612  // compute crossing with normal
613  Line edgebound1 = (*i)->getCCWBoundaryLine(myNode).lineAt(0);
614  Line edgebound2 = (*i)->getCWBoundaryLine(myNode).lineAt(0);
615  Line cross(edgebound1);
616  cross.rotateAtP1(M_PI / 2.);
617  cross.add(myNode.getPosition() - cross.p1());
618  cross.extrapolateBy2D(500);
619  edgebound1.extrapolateBy2D(500);
620  edgebound2.extrapolateBy2D(500);
621  if (cross.intersects(edgebound1)) {
622  Position np = cross.intersectsAt(edgebound1);
623  np.set(np.x(), np.y(), myNode.getPosition().z());
624  ret.push_back_noDoublePos(np);
625  }
626  if (cross.intersects(edgebound2)) {
627  Position np = cross.intersectsAt(edgebound2);
628  np.set(np.x(), np.y(), myNode.getPosition().z());
629  ret.push_back_noDoublePos(np);
630  }
631  }
632  return ret;
633 }
634 
635 
636 
637 /****************************************************************************/
SUMOReal length2D() const
Definition: Line.cpp:186
SUMOReal atan2DegreeAngle() const
Definition: Line.cpp:152
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges.
Definition: NBNode.h:247
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
void replaceAt(int index, const Position &by)
SUMOReal getRadius() const
Returns the turning radius of this node.
Definition: NBNode.h:279
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:119
#define M_PI
Definition: angles.h:37
PositionVector getSmoothCorner(PositionVector begShape, PositionVector endShape, const Position &begPoint, const Position &endPoint, int cornerDetail)
Compute smoothed corner shape.
Position getPositionAtDistance2D(SUMOReal offset) const
Definition: Line.cpp:114
The representation of a single edge during network building.
Definition: NBEdge.h:71
PositionVector computeNodeShapeDefault(bool simpleContinuation)
Computes the node geometry Edges with the same direction are grouped. Then the node geometry is built...
void rotateAtP1(SUMOReal rot)
Definition: Line.cpp:237
bool intersects(const Position &p1, const Position &p2) const
SUMOReal getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition: NBEdge.cpp:2299
static T minValue(const std::vector< T > &v)
Definition: VectorHelper.h:108
const NBNode & myNode
The node to compute the geometry for.
T MAX2(T a, T b)
Definition: StdDefs.h:74
void eraseAt(int i)
std::map< NBEdge *, PositionVector > GeomsMap
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1038
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 WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:69
SUMOReal closestIntersection(const PositionVector &geom1, const PositionVector &geom2, SUMOReal offset)
return the intersection point closest to the given offset
PositionVector reverse() const
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges.
Definition: NBNode.h:255
NBNodeShapeComputer(const NBNode &node)
Constructor.
std::vector< SUMOReal > distances(const PositionVector &s, bool perpendicular=false) const
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition: NBNode.h:746
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:235
const Position & p1() const
Definition: Line.cpp:89
std::set< NBEdge * > EdgeSet
Definition: NBCont.h:51
bool isSimpleContinuation() const
Definition: NBNode.cpp:438
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
A list of positions.
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
Definition: Line.h:51
T MIN2(T a, T b)
Definition: StdDefs.h:68
PositionVector computeSmoothShape(const PositionVector &begShape, const PositionVector &endShape, int numPoints, bool isTurnaround, SUMOReal extrapolateBeg, SUMOReal extrapolateEnd) const
Compute a smooth curve between the given geometries.
Definition: NBNode.cpp:467
#define POSITION_EPS
Definition: config.h:189
#define DEG2RAD(x)
Definition: GeomHelper.h:45
PositionVector compute()
Computes the shape of the assigned junction.
bool intersects(const Line &l) const
Definition: Line.cpp:180
SUMOReal length() const
Returns the length.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:367
~NBNodeShapeComputer()
Destructor.
PositionVector computeNodeShapeSmall()
Computes the node geometry using normals.
std::vector< NBEdge * > EdgeVector
Definition: NBCont.h:41
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:519
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:405
void set(SUMOReal x, SUMOReal y)
Definition: Position.h:78
static void initNeighbors(const EdgeVector &edges, const EdgeVector::const_iterator &current, GeomsMap &geomsCW, GeomsMap &geomsCCW, EdgeVector::const_iterator &cwi, EdgeVector::const_iterator &ccwi, SUMOReal &cad, SUMOReal &ccad)
Initialize neighbors and angles.
void mul(SUMOReal val)
Multiplies both positions with the given value.
Definition: Position.h:99
bool badIntersection(const NBEdge *e1, const NBEdge *e2, const PositionVector &e1cw, const PositionVector &e2ccw, SUMOReal distance)
void joinSameDirectionEdges(std::map< NBEdge *, std::set< NBEdge * > > &same, GeomsMap &geomsCCW, GeomsMap &geomsCW)
Joins edges and computes ccw/cw boundaries.
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge&#39;s lanes&#39; lateral offset is computed.
Definition: NBEdge.h:599
Represents a single node (junction) during network building.
Definition: NBNode.h:75
void extrapolateBy2D(SUMOReal length)
Definition: Line.cpp:69
static const SUMOReal DEFAULT_RADIUS
the default turning radius at intersections in m
Definition: NBNode.h:190
void move2side(SUMOReal amount)
#define SUMOReal
Definition: config.h:215
static const SUMOReal UNSPECIFIED_RADIUS
unspecified lane width
Definition: NBNode.h:193
T MIN3(T a, T b, T c)
Definition: StdDefs.h:81
static SUMOReal relAngle(SUMOReal angle1, SUMOReal angle2)
Definition: NBHelpers.cpp:63
void push_back_noDoublePos(const Position &p)
void computeSameEnd(PositionVector &l1, PositionVector &l2)
static T maxValue(const std::vector< T > &v)
Definition: VectorHelper.h:98
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
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:174
void add(SUMOReal x, SUMOReal y)
Definition: Line.cpp:198
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
EdgeVector computeUniqueDirectionList(std::map< NBEdge *, std::set< NBEdge * > > &same, GeomsMap &geomsCCW, GeomsMap &geomsCW, std::map< NBEdge *, NBEdge * > &ccwBoundary, std::map< NBEdge *, NBEdge * > &cwBoundary)
Joins edges and computes ccw/cw boundaries.