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