41#define DEBUGCOND (myNode.getID() == "C")
56 myRadius(node.getRadius()) {
70#ifdef DEBUG_NODE_SHAPE
102 assert(l1[0].distanceTo2D(l1[1]) >=
EXT);
103 assert(l2[0].distanceTo2D(l2[1]) >=
EXT);
106 tmp.push_back(l1[1]);
108 tmp[1].set(-tmp[1].y(), tmp[1].x());
113 if (l2.
length2D() - offset > POSITION_EPS) {
116 l2.erase(l2.begin(), l2.begin() + (l2.size() - tl2.size()));
134 double smallRadius = useDefaultRadius ? oc.
getFloat(
"junctions.small-radius") :
myRadius;
135 const int cornerDetail = oc.
getInt(
"junctions.corner-detail");
136 const double sCurveStretch = oc.
getFloat(
"junctions.scurve-stretch");
137 const bool useEndpoints = oc.
getBool(
"junctions.endpoint-shape");
138 const bool rectangularCut = oc.
getBool(
"rectangular-lane-cut");
139 const bool openDriveOutput = oc.
isSet(
"opendrive-output");
146 const double advanceStopLine = oc.
exists(
"opendrive-files") && oc.
isSet(
"opendrive-files") ? oc.
getFloat(
"opendrive.advance-stopline") : 0;
149#ifdef DEBUG_NODE_SHAPE
151 std::cout <<
"\ncomputeNodeShapeDefault node " <<
myNode.
getID() <<
" simple=" << simpleContinuation <<
" useDefaultRadius=" << useDefaultRadius <<
" radius=" <<
myRadius <<
"\n";
156 EdgeVector::const_iterator i;
158 std::map<NBEdge*, std::set<NBEdge*> > same;
171 if (newAll.size() < 2) {
180 std::map<NBEdge*, double> distances;
181 std::map<NBEdge*, double> distances2;
182 std::map<NBEdge*, bool> myExtended;
184 for (i = newAll.begin(); i != newAll.end(); ++i) {
185 EdgeVector::const_iterator cwi = i;
186 EdgeVector::const_iterator ccwi = i;
189 initNeighbors(newAll, i, geomsCW, geomsCCW, cwi, ccwi, cad, ccad);
190 assert(geomsCCW.find(*i) != geomsCCW.end());
191 assert(geomsCW.find(*ccwi) != geomsCW.end());
192 assert(geomsCW.find(*cwi) != geomsCW.end());
198 (simpleContinuation && fabs(ccad - cad) < (
double) 0.1)
201 || (!simpleContinuation && fabs(ccad - cad) <
DEG2RAD(22.5)))
205 if (myExtended.find(*ccwi) != myExtended.end()) {
206 p = geomsCCW[*ccwi][0];
207 p.
add(geomsCW[*ccwi][0]);
209#ifdef DEBUG_NODE_SHAPE
211 std::cout <<
" extended: p=" << p <<
" angle=" << (ccad - cad) <<
"\n";
215 p = geomsCCW[*ccwi][0];
216 p.
add(geomsCW[*ccwi][0]);
217 p.
add(geomsCCW[*i][0]);
218 p.
add(geomsCW[*i][0]);
220#ifdef DEBUG_NODE_SHAPE
222 std::cout <<
" unextended: p=" << p <<
" angle=" << (ccad - cad) <<
"\n";
228 geomsCCW[*i].nearest_offset_to_point2D(p),
229 geomsCW[*i].nearest_offset_to_point2D(p));
245 (*i)->setGeometry(g);
247 geomsCCW[*i] = (*i)->getCCWBoundaryLine(
myNode);
248 geomsCCW[*i].extrapolate(
EXT);
249 geomsCW[*i] = (*i)->getCWBoundaryLine(
myNode);
250 geomsCW[*i].extrapolate(
EXT);
253 myExtended[*i] =
true;
254#ifdef DEBUG_NODE_SHAPE
256 std::cout <<
" extending (dist=" << dist <<
")\n";
260 if (!simpleContinuation) {
264 double radius2 = fabs(ccad - cad) * (*i)->getNumLanes();
265 if (radius2 > NUMERICAL_EPS || openDriveOutput) {
266 radius2 =
MAX2(0.15, radius2);
273 radius2 =
MAX2(radius2, width / 2);
275 if (!useDefaultRadius) {
279#ifdef DEBUG_NODE_SHAPE
281 std::cout <<
" using radius=" << radius2 <<
" ccad=" << ccad <<
" cad=" << cad <<
"\n";
285 distances[*i] = dist;
291 const bool ccwCloser = ccad < cad;
294 const bool neighLargeTurn = ccwCloser ? ccwLargeTurn : cwLargeTurn;
295 const bool neigh2LargeTurn = ccwCloser ? cwLargeTurn : ccwLargeTurn;
297 const PositionVector& currGeom = ccwCloser ? geomsCCW[*i] : geomsCW[*i];
299 const PositionVector& currGeom2 = ccwCloser ? geomsCW[*i] : geomsCCW[*i];
301 const PositionVector& neighGeom = ccwCloser ? geomsCW[*ccwi] : geomsCCW[*cwi];
303 const PositionVector& neighGeom2 = ccwCloser ? geomsCCW[*cwi] : geomsCW[*ccwi];
305 const bool keepBothDistances =
isDivided(*i, same[*i], geomsCCW[*i], geomsCW[*i]);
306#ifdef DEBUG_NODE_SHAPE
308 std::cout <<
" i=" << (*i)->getID() <<
" neigh=" << (*ccwi)->getID() <<
" neigh2=" << (*cwi)->getID() <<
"\n";
309 std::cout <<
" ccwCloser=" << ccwCloser <<
" divided=" << keepBothDistances
310 <<
"\n currGeom=" << currGeom <<
" neighGeom=" << neighGeom
311 <<
"\n currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2
315 if (!simpleContinuation) {
316 if (useEndpoints && !(*i)->hasDefaultGeometryEndpointAtNode(&
myNode)) {
320#ifdef DEBUG_NODE_SHAPE
322 std::cout <<
" neigh intersects dist=" << distances[*i] <<
" currGeom=" << currGeom <<
" neighGeom=" << neighGeom <<
"\n";
325 if (*cwi != *ccwi && currGeom2.
intersects(neighGeom2)) {
328 const double farAngleDist = ccwCloser ? cad : ccad;
329 double a1 = distances[*i];
331#ifdef DEBUG_NODE_SHAPE
333 std::cout <<
" neigh2 also intersects a1=" << a1 <<
" a2=" << a2 <<
" ccad=" <<
RAD2DEG(ccad) <<
" cad=" <<
RAD2DEG(cad) <<
" dist[cwi]=" << distances[*cwi] <<
" dist[ccwi]=" << distances[*ccwi] <<
" farAngleDist=" <<
RAD2DEG(farAngleDist) <<
" currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2 <<
"\n";
340 if (keepBothDistances) {
348 distances[*i] =
MAX2(a1, a2);
351 && (fabs(ccad - cad) >
DEG2RAD(10)
356#ifdef DEBUG_NODE_SHAPE
358 std::cout <<
" ignore a2\n";
362 }
else if (farAngleDist <
DEG2RAD(135) || (fabs(
RAD2DEG(farAngleDist) - 180) > 1 && fabs(a2 - a1) < 10)) {
363 if (keepBothDistances) {
371 distances[*i] =
MAX2(a1, a2);
374#ifdef DEBUG_NODE_SHAPE
376 std::cout <<
" a1=" << a1 <<
" a2=" << a2 <<
" keepBoth=" << keepBothDistances <<
" dist=" << distances[*i] <<
"\n";
381 if (*cwi != *ccwi && currGeom2.
intersects(neighGeom2)) {
383#ifdef DEBUG_NODE_SHAPE
385 std::cout <<
" neigh2 intersects dist=" << distances[*i] <<
" currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2 <<
"\n";
390#ifdef DEBUG_NODE_SHAPE
392 std::cout <<
" no intersects dist=" << distances[*i] <<
" currGeom=" << currGeom <<
" neighGeom=" << neighGeom <<
" currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2 <<
"\n";
401 distances[*i] = (double)
EXT;
405 if (useDefaultRadius && sCurveStretch > 0) {
407 if (sCurveWidth > 0) {
408 const double sCurveRadius =
myRadius + sCurveWidth /
SUMO_const_laneWidth * sCurveStretch * pow((*i)->getSpeed(), 2 + sCurveStretch) / 1000;
409 const double stretch =
EXT + sCurveRadius - distances[*i];
411 distances[*i] += stretch;
413 const double shorten = distances[*i] -
EXT;
414 (*i)->shortenGeometryAtNode(&
myNode, shorten);
415 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
416 (*k)->shortenGeometryAtNode(&
myNode, shorten);
418#ifdef DEBUG_NODE_SHAPE
420 std::cout <<
" stretching junction: sCurveWidth=" << sCurveWidth <<
" sCurveRadius=" << sCurveRadius <<
" stretch=" << stretch <<
" dist=" << distances[*i] <<
"\n";
428 for (
NBEdge*
const edge : newAll) {
429 if (distances.find(edge) == distances.end()) {
431 distances[edge] =
EXT;
435 const double off =
EXT - NUMERICAL_EPS;
439 for (
NBEdge*
const edge : newAll) {
440 if (distances[edge] < off && edge->hasDefaultGeometryEndpointAtNode(&
myNode)) {
441 for (EdgeVector::const_iterator j = newAll.begin(); j != newAll.end(); ++j) {
442 if (distances[*j] > off && (*j)->hasDefaultGeometryEndpointAtNode(&
myNode) && distances[edge] + distances[*j] < minDistSum) {
444 if (angleDiff > 160 || angleDiff < 20) {
445#ifdef DEBUG_NODE_SHAPE
447 std::cout <<
" increasing dist for i=" << edge->getID() <<
" because of j=" << (*j)->getID() <<
" jDist=" << distances[*j]
448 <<
" oldI=" << distances[edge] <<
" newI=" << minDistSum - distances[*j]
449 <<
" angleDiff=" << angleDiff
450 <<
" geomI=" << edge->getGeometry() <<
" geomJ=" << (*j)->getGeometry() <<
"\n";
453 distances[edge] = minDistSum - distances[*j];
463 for (i = newAll.begin(); i != newAll.end(); ++i) {
467 double offset = distances[*i];
468 double offset2 = distances2.count(*i) != 0 ? distances2[*i] : offset;
469 if (offset != offset2) {
476 const double oDelta = fabs(offset - offset2);
479#ifdef DEBUG_NODE_SHAPE
480 std::cout <<
" i=" << (*i)->getID() <<
" offset=" << offset <<
" offset2=" << offset2 <<
" dWidth=" << dWidth <<
" angle=" << angle <<
" same=" <<
joinNamedToStringSorting(same[*i],
",") <<
"\n";
482 offset =
MAX2(offset, offset2);
486 if (!(*i)->hasDefaultGeometryEndpointAtNode(&
myNode)) {
488 if (advanceStopLine > 0 && offset <
EXT) {
489#ifdef DEBUG_NODE_SHAPE
490 std::cout <<
" i=" << (*i)->getID() <<
" offset=" << offset <<
" advanceStopLine=" << advanceStopLine <<
"\n";
493 (*i)->extendGeometryAtNode(&
myNode, advanceStopLine);
494 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
495 (*k)->extendGeometryAtNode(&
myNode, advanceStopLine);
498 offset =
MAX2(
EXT - advanceStopLine, offset);
499 offset2 =
MAX2(
EXT - advanceStopLine, offset2);
508 if (i != newAll.begin()) {
516#ifdef DEBUG_NODE_SHAPE
518 std::cout <<
" build stopLine for i=" << (*i)->getID() <<
" offset=" << offset <<
" offset2=" << offset2 <<
" dist=" << distances[*i] <<
" cwLength=" << cwBound.
length2D() <<
" ccwLength=" << ccwBound.
length2D() <<
" p=" << p <<
" p2=" << p2 <<
" ccwBound=" << ccwBound <<
" cwBound=" << cwBound <<
"\n";
521 (*i)->setNodeBorder(&
myNode, p, p2, rectangularCut);
522 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
523 (*k)->setNodeBorder(&
myNode, p, p2, rectangularCut);
527 ret.
append(
getSmoothCorner(geomsCW[*(newAll.end() - 1)], geomsCCW[*newAll.begin()], ret[-1], ret[0], cornerDetail));
528#ifdef DEBUG_NODE_SHAPE
530 std::cout <<
" final shape=" << ret <<
"\n";
540 double result = intersections[0];
541 for (std::vector<double>::iterator it = intersections.begin() + 1; it != intersections.end(); ++it) {
542 if (fabs(*it - offset) < fabs(result - offset)) {
551 std::map<
NBEdge*, std::set<NBEdge*> >& same)
const {
560 for (
NBEdge* e2s : same[e2]) {
565 for (
NBEdge* e1s : same[e1]) {
566 if ((e2s->getPermissions() & e1s->getPermissions() &
SVC_LARGE_TURN) != 0
567 && (e2s->getToNode() == e1s->getFromNode() || e1s->getToNode() == e2s->getFromNode())) {
572 for (
NBEdge* e1s : same[e1]) {
586 if (cornerDetail > 0) {
589#ifdef DEBUG_SMOOTH_CORNERS
591 std::cout <<
" begLength=" << begShape2.
length2D() <<
" begSplit=" << begSplit <<
"\n";
594 if (begSplit > POSITION_EPS && begSplit < begShape2.
length2D() - POSITION_EPS) {
595 begShape2 = begShape2.
splitAt(begSplit,
true).first;
601#ifdef DEBUG_SMOOTH_CORNERS
603 std::cout <<
" endLength=" << endShape2.
length2D() <<
" endSplit=" << endSplit <<
"\n";
606 if (endSplit > POSITION_EPS && endSplit < endShape2.
length2D() - POSITION_EPS) {
607 endShape2 = endShape2.
splitAt(endSplit,
true).second;
614#ifdef DEBUG_SMOOTH_CORNERS
616 std::cout <<
"getSmoothCorner begPoint=" << begPoint <<
" endPoint=" << endPoint
617 <<
" begShape=" << begShape <<
" endShape=" << endShape
618 <<
" begShape2=" << begShape2 <<
" endShape2=" << endShape2
622 if (begShape2.size() < 2 || endShape2.size() < 2) {
626 NBNode* recordError =
nullptr;
627#ifdef DEBUG_SMOOTH_CORNERS
629 std::cout <<
" angle=" <<
RAD2DEG(angle) <<
"\n";
640#ifdef DEBUG_SMOOTH_CORNERS
642 std::cout <<
" curve=" << curve <<
" curveLength=" << curve.
length2D() <<
" dist=" << begPoint.
distanceTo2D(endPoint) <<
" curvature=" << curvature <<
"\n";
645 if (curvature > 2 && angle >
DEG2RAD(85)) {
649 if (curve.size() > 2) {
650 curve.erase(curve.begin());
663 for (
NBEdge*
const edge : edges) {
666 geomsCCW[edge] = edge->getCCWBoundaryLine(
myNode);
668 WRITE_WARNING(
"While computing intersection geometry at junction '" +
myNode.
getID() +
"': " + std::string(e.what()));
669 geomsCCW[edge] = edge->getGeometry();
672 geomsCW[edge] = edge->getCWBoundaryLine(
myNode);
674 WRITE_WARNING(
"While computing intersection geometry at junction '" +
myNode.
getID() +
"': " + std::string(e.what()));
675 geomsCW[edge] = edge->getGeometry();
678 if (geomsCCW[edge].length2D() < NUMERICAL_EPS) {
679 geomsCCW[edge] = edge->getGeometry();
681 if (geomsCW[edge].length2D() < NUMERICAL_EPS) {
682 geomsCW[edge] = edge->getGeometry();
685 geomsCCW[edge] = geomsCCW[edge].getSubpart2D(0,
MAX2(
EXT, edge->getTotalWidth()));
686 geomsCW[edge] = geomsCW[edge].getSubpart2D(0,
MAX2(
EXT, edge->getTotalWidth()));
688 geomsCCW[edge].extrapolate2D(
EXT,
true);
689 geomsCW[edge].extrapolate2D(
EXT,
true);
691 geomsCCW[edge].extrapolate(
EXT2,
false,
true);
692 geomsCW[edge].extrapolate(
EXT2,
false,
true);
700 const double angleChangeLookahead = 35;
703 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); i++) {
704 EdgeVector::const_iterator j;
705 if (i == edges.end() - 1) {
711 && !(*i)->hasDefaultGeometryEndpointAtNode(&
myNode)
712 && !(*j)->hasDefaultGeometryEndpointAtNode(&
myNode)) {
715 const bool incoming = (*i)->getToNode() == &
myNode;
716 const bool incoming2 = (*j)->getToNode() == &
myNode;
717 const bool differentDirs = (incoming != incoming2);
718 const bool sameGeom = (*i)->getGeometry() == (differentDirs ? (*j)->getGeometry().reverse() : (*j)->getGeometry());
721 const double angle1further = (g1.size() > 2 && g1[0].distanceTo2D(g1[1]) < angleChangeLookahead ?
723 const double angle2further = (g2.size() > 2 && g2[0].distanceTo2D(g2[1]) < angleChangeLookahead ?
727 const bool ambiguousGeometry = ((angleDiff > 0 && angleDiffFurther < 0) || (angleDiff < 0 && angleDiffFurther > 0));
732#ifdef DEBUG_NODE_SHAPE
734 std::cout <<
" checkSameDirection " << (*i)->getID() <<
" " << (*j)->getID()
735 <<
" diffDirs=" << differentDirs
736 <<
" isOpposite=" << (differentDirs && foundOpposite.count(*i) == 0)
737 <<
" angleDiff=" << angleDiff
738 <<
" ambiguousGeometry=" << ambiguousGeometry
744 if (sameGeom || fabs(angleDiff) <
DEG2RAD(20)) {
745 const bool isOpposite = differentDirs && foundOpposite.count(*i) == 0;
747 foundOpposite.insert(*i);
748 foundOpposite.insert(*j);
752 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
758 for (std::set<NBEdge*>::iterator k = same[*j].begin(); k != same[*j].end(); ++k) {
766#ifdef DEBUG_NODE_SHAPE
768 std::cout <<
" joinedSameDirectionEdges " << (*i)->getID() <<
" " << (*j)->getID() <<
" isOpposite=" << isOpposite <<
" ambiguousGeometry=" << ambiguousGeometry <<
"\n";
800 double endAngleDiff = 0;
801 if (geom1.size() >= 2 && geom2.size() >= 2) {
804 geom2.
angleAt2D((
int)geom2.size() - 2))));
807 std::vector<double> distances = geom1.
distances(geom2,
true);
808 std::vector<double> distances2 = geom1.
distances(geom2);
811 const bool curvingTowards = geom1[0].distanceTo2D(geom2[0]) > minDistanceThreshold && minDist < minDistanceThreshold;
812 const bool onTop = (maxDist - POSITION_EPS < minDistanceThreshold) && endAngleDiff < 30;
814 const bool neverTouch = minDist > minDistanceThreshold * 2 && !bothDefault;
819#ifdef DEBUG_NODE_SHAPE
821 std::cout <<
" badIntersect: onTop=" << onTop <<
" curveTo=" << curvingTowards <<
" intersects=" << intersects
822 <<
" endAngleDiff=" << endAngleDiff
823 <<
" geom1=" << geom1 <<
" geom2=" << geom2
824 <<
" distances=" <<
toString(distances) <<
" minDist=" << minDist <<
" maxDist=" << maxDist <<
" thresh=" << minDistanceThreshold
825 <<
" neverTouch=" << neverTouch
826 <<
" intersectPos=" << intersect
830 return onTop || curvingTowards || !intersects || neverTouch;
837 std::map<
NBEdge*, std::set<NBEdge*> >& same,
844 auto e2NewAll = std::find(newAll.begin(), newAll.end(), e1);
845#ifdef DEBUG_NODE_SHAPE
846 if (
DEBUGCOND) std::cout <<
"computeUniqueDirectionList e1=" << e1->getID()
847 <<
" deleted=" << (e2NewAll == newAll.end())
850 if (e2NewAll == newAll.end()) {
853 auto e1It = std::find(all.begin(), all.end(), e1);
859 for (
NBEdge* e2 : same[e1]) {
860#ifdef DEBUG_NODE_SHAPE
862 std::cout <<
" e2=" << e2->getID() <<
"\n";
865 auto e2It = std::find(all.begin(), all.end(), e2);
866 if (e2It + 1 == bestCCW || (e2It == (all.end() - 1) && bestCCW == all.begin())) {
869#ifdef DEBUG_NODE_SHAPE
871 std::cout <<
" bestCCW=" << e2->getID() <<
"\n";
874 }
else if (bestCW + 1 == e2It || (bestCW == (all.end() - 1) && e2It == all.begin())) {
877#ifdef DEBUG_NODE_SHAPE
879 std::cout <<
" bestCW=" << e2->getID() <<
"\n";
885 if (bestCW != e1It) {
886 geomsCW[e1] = geomsCW[*bestCW];
889 if (bestCCW != e1It) {
890 geomsCCW[e1] = geomsCCW[*bestCCW];
894 for (
NBEdge* e2 : same[e1]) {
895 auto e2NewAllIt = std::find(newAll.begin(), newAll.end(), e2);
896 if (e2NewAllIt != newAll.end()) {
897 newAll.erase(e2NewAllIt);
901#ifdef DEBUG_NODE_SHAPE
903 std::cout <<
" newAll:\n";
904 for (
NBEdge* e : newAll) {
905 std::cout <<
" " << e->getID() <<
" geomCCW=" << geomsCCW[e] <<
" geomsCW=" << geomsCW[e] <<
"\n";
917 EdgeVector::const_iterator& cwi,
918 EdgeVector::const_iterator& ccwi,
921 const double twoPI = (double)(2 *
M_PI);
924 if (cwi == edges.end()) {
925 std::advance(cwi, -((
int)edges.size()));
928 if (ccwi == edges.begin()) {
929 std::advance(ccwi, edges.size() - 1);
934 const double angleCurCCW = geomsCCW[*current].angleAt2D(0);
935 const double angleCurCW = geomsCW[*current].angleAt2D(0);
936 const double angleCCW = geomsCW[*ccwi].angleAt2D(0);
937 const double angleCW = geomsCCW[*cwi].angleAt2D(0);
938 ccad = angleCCW - angleCurCCW;
942 cad = angleCurCW - angleCW;
952#ifdef DEBUG_NODE_SHAPE
954 std::cout <<
"computeNodeShapeSmall node=" <<
myNode.
getID() <<
"\n";
962 Position delta = edgebound1[1] - edgebound1[0];
963 delta.
set(-delta.
y(), delta.
x());
978 e->resetNodeBorder(&
myNode);
989 const double radius = oc.
getFloat(
"default.junctions.radius");
990 const double smallRadius = oc.
getFloat(
"junctions.small-radius");
991 double maxRightAngle = 0;
992 double extraWidthRight = 0;
993 double maxLeftAngle = 0;
994 double extraWidthLeft = 0;
996 int totalWideLanesIn = 0;
999 for (
int i = 0; i < in->getNumLanes(); i++) {
1004 totalWideLanesIn += wideLanesIn;
1006 if ((in->getPermissions() & out->getPermissions() &
SVC_LARGE_TURN) != 0) {
1011 in->getGeometry().angleAt2D(-2),
1012 out->getGeometry().angleAt2D(0));
1014 if (maxRightAngle < -angle) {
1015 maxRightAngle = -angle;
1019 if (maxLeftAngle < angle) {
1020 maxLeftAngle = angle;
1025 while (*pIn != out) {
1026 extraWidthLeft += (*pIn)->getTotalWidth();
1029 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" extra=" << (*pIn)->getID() <<
" extraWidthLeft=" << extraWidthLeft <<
"\n";
1036 int wideLanesOut = 0;
1037 for (
int i = 0; i < out->getNumLanes(); i++) {
1044 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" wideLanesIn=" << wideLanesIn <<
" wideLanesOut=" << wideLanesOut <<
"\n";
1047 laneDelta =
MAX2(laneDelta, abs(wideLanesOut - wideLanesIn));
1053 int totalWideLanesOut = 0;
1055 for (
int i = 0; i < out->getNumLanes(); i++) {
1057 totalWideLanesOut++;
1061 if (totalWideLanesIn == totalWideLanesOut) {
1068 double result = radius;
1070 double maxTurnAngle = maxRightAngle;
1071 double extraWidth = extraWidthRight;
1072 if (maxRightAngle <
DEG2RAD(5)) {
1073 maxTurnAngle = maxLeftAngle;
1074 extraWidth = extraWidthLeft;
1076 const double minRadius = maxTurnAngle >=
DEG2RAD(30) ?
MIN2(smallRadius, radius) : smallRadius;
1080 result = radius * tan(0.5 *
MIN2(0.5 *
M_PI, maxTurnAngle)) - extraWidth;
1082 result =
MAX2(minRadius, result);
1085 std::cout <<
"getDefaultRadius n=" <<
myNode.
getID()
1086 <<
" r=" << radius <<
" sr=" << smallRadius
1087 <<
" mr=" << minRadius
1088 <<
" laneDelta=" << laneDelta
1089 <<
" rightA=" <<
RAD2DEG(maxRightAngle)
1090 <<
" leftA=" <<
RAD2DEG(maxLeftAngle)
1091 <<
" maxA=" <<
RAD2DEG(maxTurnAngle)
1092 <<
" extraWidth=" << extraWidth
1093 <<
" result=" << result <<
"\n";
1102 if (same.size() < 2) {
1105 std::set<Position> endPoints;
1108 endPoints.insert(s->getEndpointAtNode(&
myNode));
1110 if (endPoints.size() > 1) {
1111 std::vector<double> distances = ccw.
distances(cw,
true);
1113 for (
const NBEdge* e2 : same) {
1114 width += e2->getTotalWidth();
1117 const double maxDivider = maxDist - width;
1118 return maxDivider >= 5;
1128 while (lane < e->getNumLanes() && e->
getPermissions(lane) == 0) {
1132 while (lane < e->getNumLanes() && (e->
getPermissions(lane) & exclude) == 0) {
1144 for (
NBEdge* e2 : same) {
1145 result -= e2->getTotalWidth();
1147 return MAX2(0.0, result);
#define WRITE_WARNINGF(...)
#define WRITE_WARNING(msg)
std::set< NBEdge * > EdgeSet
container for unique edges
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_PEDESTRIAN
pedestrian
@ TURN
The link is a 180 degree turn.
const double SUMO_const_laneWidth
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
The representation of a single edge during network building.
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
double getLaneWidth() const
Returns the default width of lanes of this edge.
NBNode * getToNode() const
Returns the destination node of the edge.
const PositionVector & getGeometry() const
Returns the geometry of the edge.
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Position getEndpointAtNode(const NBNode *node) const
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
NBNode * getFromNode() const
Returns the origin node of the edge.
bool hasDefaultGeometryEndpointAtNode(const NBNode *node) const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
static const double UNSPECIFIED_WIDTH
unspecified lane width
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Represents a single node (junction) during network building.
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
double getDisplacementError() const
compute the displacement error during s-curve computation
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
static const double UNSPECIFIED_RADIUS
unspecified lane width
SumoXMLNodeType getType() const
Returns the type of this node.
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
PositionVector computeSmoothShape(const PositionVector &begShape, const PositionVector &endShape, int numPoints, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, NBNode *recordError=0, int shapeFlag=0) const
Compute a smooth curve between the given geometries.
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
bool isConstantWidthTransition() const
detects whether a given junction splits or merges lanes while keeping constant road width
static const int AVOID_WIDE_LEFT_TURN
const Position & getPosition() const
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
double getRadius() const
Returns the turning radius of this node.
bool isRoundabout() const
return whether this node is part of a roundabout
PositionVector getSmoothCorner(PositionVector begShape, PositionVector endShape, const Position &begPoint, const Position &endPoint, int cornerDetail)
Compute smoothed corner shape.
double closestIntersection(const PositionVector &geom1, const PositionVector &geom2, double offset)
return the intersection point closest to the given offset
const PositionVector computeNodeShapeSmall()
Computes the node geometry using normals.
double myRadius
the computed node radius
EdgeVector computeUniqueDirectionList(const EdgeVector &all, std::map< NBEdge *, std::set< NBEdge * > > &same, GeomsMap &geomsCCW, GeomsMap &geomsCW)
Joins edges.
bool isDivided(const NBEdge *e, std::set< NBEdge * > same, const PositionVector &ccw, const PositionVector &cw) const
double EXT
the maximum distance to search for a place where neighboring edges intersect and do not overlap
void computeEdgeBoundaries(const EdgeVector &edges, GeomsMap &geomsCCW, GeomsMap &geomsCW)
compute clockwise/counter-clockwise edge boundaries
std::map< NBEdge *, PositionVector > GeomsMap
NBNodeShapeComputer(const NBNode &node)
Constructor.
~NBNodeShapeComputer()
Destructor.
bool badIntersection(const NBEdge *e1, const NBEdge *e2, double distance)
const PositionVector computeNodeShapeDefault(bool simpleContinuation)
Computes the node geometry Edges with the same direction are grouped. Then the node geometry is built...
const PositionVector compute(bool forceSmall)
Computes the shape of the assigned junction.
const NBNode & myNode
The node to compute the geometry for.
void joinSameDirectionEdges(const EdgeVector &edges, std::map< NBEdge *, std::set< NBEdge * > > &same, bool useEndpoints)
Joins edges and computes ccw/cw boundaries.
void computeSameEnd(PositionVector &l1, PositionVector &l2)
static double divisionWidth(const NBEdge *e, std::set< NBEdge * > same, const Position &p, const Position &p2)
compute the width of the divider space for divided roads
double getDefaultRadius(const OptionsCont &oc)
determine the default radius appropriate for the current junction
static void initNeighbors(const EdgeVector &edges, const EdgeVector::const_iterator ¤t, GeomsMap &geomsCW, GeomsMap &geomsCCW, EdgeVector::const_iterator &cwi, EdgeVector::const_iterator &ccwi, double &cad, double &ccad)
Initialize neighbors and angles.
bool needsLargeTurn(NBEdge *e1, NBEdge *e2, std::map< NBEdge *, std::set< NBEdge * > > &same) const
whether the given edges (along with those in the same direction) requires a large turning radius
static const SVCPermissions SVC_LARGE_TURN
static double getExtraWidth(const NBEdge *e, SVCPermissions exclude)
compute with of rightmost lanes that exlude the given permissions
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
const std::string & getID() const
Returns the id.
A storage for options typed value containers)
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool exists(const std::string &name) const
Returns the information whether the named option is known.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
A point in 2D or 3D with translation and scaling methods.
void set(double x, double y)
set positions x and y
static const Position INVALID
used to indicate that a position is valid
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
double x() const
Returns the x-position.
void add(const Position &pos)
Adds the given position to this one.
void setz(double z)
set position z
void mul(double val)
Multiplies position with the given value.
double z() const
Returns the z-position.
double y() const
Returns the y-position.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double length() const
Returns the length.
Position intersectionPosition2D(const Position &p1, const Position &p2, const double withinDist=0.) const
Returns the position of the intersection.
void push_front_noDoublePos(const Position &p)
insert in front a non double position
void add(double xoff, double yoff, double zoff)
std::vector< double > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
std::pair< PositionVector, PositionVector > splitAt(double where, bool use2D=false) const
Returns the two lists made when this list vector is splitted at the given point.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
PositionVector interpolateZ(double zStart, double zEnd) const
returned vector that varies z smoothly over its length
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void push_back_noDoublePos(const Position &p)
insert in back a non double position
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
PositionVector reverse() const
reverse position vector
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
void sub(const Position &offset)
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
static T maxValue(const std::vector< T > &v)
static T minValue(const std::vector< T > &v)