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