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*, ComparatorIdLess> > 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*, ComparatorIdLess> >& 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);
693 if (geomsCCW[edge].isNAN() || geomsCW[edge].isNAN()) {
694 WRITE_WARNING(
"While computing intersection geometry at junction '" +
myNode.
getID() +
"': found invalid boundary line for edge '" + edge->getID() +
"'.")
696 if (geomsCCW[edge].isNAN()) {
697 geomsCCW[edge] = edge->getGeometry();
699 if (geomsCW[edge].isNAN()) {
700 geomsCW[edge] = edge->getGeometry();
709 const double angleChangeLookahead = 35;
712 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); i++) {
713 EdgeVector::const_iterator j;
714 if (i == edges.end() - 1) {
720 && !(*i)->hasDefaultGeometryEndpointAtNode(&
myNode)
721 && !(*j)->hasDefaultGeometryEndpointAtNode(&
myNode)) {
724 const bool incoming = (*i)->getToNode() == &
myNode;
725 const bool incoming2 = (*j)->getToNode() == &
myNode;
726 const bool differentDirs = (incoming != incoming2);
727 const bool sameGeom = (*i)->getGeometry() == (differentDirs ? (*j)->getGeometry().reverse() : (*j)->getGeometry());
730 const double angle1further = (g1.size() > 2 && g1[0].distanceTo2D(g1[1]) < angleChangeLookahead ?
732 const double angle2further = (g2.size() > 2 && g2[0].distanceTo2D(g2[1]) < angleChangeLookahead ?
736 const bool ambiguousGeometry = ((angleDiff > 0 && angleDiffFurther < 0) || (angleDiff < 0 && angleDiffFurther > 0));
741#ifdef DEBUG_NODE_SHAPE
743 std::cout <<
" checkSameDirection " << (*i)->getID() <<
" " << (*j)->getID()
744 <<
" sameGeom=" << sameGeom
745 <<
" diffDirs=" << differentDirs
746 <<
" isOpposite=" << (differentDirs && foundOpposite.count(*i) == 0)
747 <<
" angleDiff=" << angleDiff
748 <<
" ambiguousGeometry=" << ambiguousGeometry
754 if (sameGeom || fabs(angleDiff) <
DEG2RAD(20)) {
755 const bool isOpposite = differentDirs && foundOpposite.count(*i) == 0;
757 foundOpposite.insert(*i);
758 foundOpposite.insert(*j);
762 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
768 for (std::set<NBEdge*>::iterator k = same[*j].begin(); k != same[*j].end(); ++k) {
776#ifdef DEBUG_NODE_SHAPE
778 std::cout <<
" joinedSameDirectionEdges " << (*i)->getID() <<
" " << (*j)->getID() <<
" isOpposite=" << isOpposite <<
" ambiguousGeometry=" << ambiguousGeometry <<
"\n";
810 double endAngleDiff = 0;
811 if (geom1.size() >= 2 && geom2.size() >= 2) {
814 geom2.
angleAt2D((
int)geom2.size() - 2))));
817 std::vector<double> distances = geom1.
distances(geom2,
true);
818 std::vector<double> distances2 = geom1.
distances(geom2);
821 const bool curvingTowards = geom1[0].distanceTo2D(geom2[0]) > minDistanceThreshold && minDist < minDistanceThreshold;
822 const bool onTop = (maxDist - POSITION_EPS < minDistanceThreshold) && endAngleDiff < 30;
824 const bool neverTouch = minDist > minDistanceThreshold * 2 && !bothDefault;
829#ifdef DEBUG_NODE_SHAPE
831 std::cout <<
" badIntersect: onTop=" << onTop <<
" curveTo=" << curvingTowards <<
" intersects=" << intersects
832 <<
" endAngleDiff=" << endAngleDiff
833 <<
" geom1=" << geom1 <<
" geom2=" << geom2
834 <<
" distances=" <<
toString(distances) <<
" minDist=" << minDist <<
" maxDist=" << maxDist <<
" thresh=" << minDistanceThreshold
835 <<
" neverTouch=" << neverTouch
836 <<
" intersectPos=" << intersect
840 return onTop || curvingTowards || !intersects || neverTouch;
847 std::map<
NBEdge*, std::set<NBEdge*, ComparatorIdLess> >& same,
854 auto e2NewAll = std::find(newAll.begin(), newAll.end(), e1);
855#ifdef DEBUG_NODE_SHAPE
856 if (
DEBUGCOND) std::cout <<
"computeUniqueDirectionList e1=" << e1->getID()
857 <<
" deleted=" << (e2NewAll == newAll.end())
860 if (e2NewAll == newAll.end()) {
863 auto e1It = std::find(all.begin(), all.end(), e1);
869 for (
NBEdge* e2 : same[e1]) {
870#ifdef DEBUG_NODE_SHAPE
872 std::cout <<
" e2=" << e2->getID() <<
"\n";
875 auto e2It = std::find(all.begin(), all.end(), e2);
876 if (e2It + 1 == bestCCW || (e2It == (all.end() - 1) && bestCCW == all.begin())) {
879#ifdef DEBUG_NODE_SHAPE
881 std::cout <<
" bestCCW=" << e2->getID() <<
"\n";
884 }
else if (bestCW + 1 == e2It || (bestCW == (all.end() - 1) && e2It == all.begin())) {
887#ifdef DEBUG_NODE_SHAPE
889 std::cout <<
" bestCW=" << e2->getID() <<
"\n";
895 if (bestCW != e1It) {
896 geomsCW[e1] = geomsCW[*bestCW];
899 if (bestCCW != e1It) {
900 geomsCCW[e1] = geomsCCW[*bestCCW];
904 for (
NBEdge* e2 : same[e1]) {
905 auto e2NewAllIt = std::find(newAll.begin(), newAll.end(), e2);
906 if (e2NewAllIt != newAll.end()) {
907 newAll.erase(e2NewAllIt);
911#ifdef DEBUG_NODE_SHAPE
913 std::cout <<
" newAll:\n";
914 for (
NBEdge* e : newAll) {
915 std::cout <<
" " << e->getID() <<
" geomCCW=" << geomsCCW[e] <<
" geomsCW=" << geomsCW[e] <<
"\n";
927 EdgeVector::const_iterator& cwi,
928 EdgeVector::const_iterator& ccwi,
931 const double twoPI = (double)(2 *
M_PI);
934 if (cwi == edges.end()) {
935 std::advance(cwi, -((
int)edges.size()));
938 if (ccwi == edges.begin()) {
939 std::advance(ccwi, edges.size() - 1);
944 const double angleCurCCW = geomsCCW[*current].angleAt2D(0);
945 const double angleCurCW = geomsCW[*current].angleAt2D(0);
946 const double angleCCW = geomsCW[*ccwi].angleAt2D(0);
947 const double angleCW = geomsCCW[*cwi].angleAt2D(0);
948 ccad = angleCCW - angleCurCCW;
952 cad = angleCurCW - angleCW;
962#ifdef DEBUG_NODE_SHAPE
964 std::cout <<
"computeNodeShapeSmall node=" <<
myNode.
getID() <<
"\n";
972 Position delta = edgebound1[1] - edgebound1[0];
973 delta.
set(-delta.
y(), delta.
x());
988 e->resetNodeBorder(&
myNode);
999 const double radius = oc.
getFloat(
"default.junctions.radius");
1000 const double smallRadius = oc.
getFloat(
"junctions.small-radius");
1001 double maxRightAngle = 0;
1002 double extraWidthRight = 0;
1003 double maxLeftAngle = 0;
1004 double extraWidthLeft = 0;
1006 int totalWideLanesIn = 0;
1008 int wideLanesIn = 0;
1009 for (
int i = 0; i < in->getNumLanes(); i++) {
1014 totalWideLanesIn += wideLanesIn;
1016 if ((in->getPermissions() & out->getPermissions() &
SVC_LARGE_TURN) != 0) {
1021 in->getGeometry().angleAt2D(-2),
1022 out->getGeometry().angleAt2D(0));
1024 if (maxRightAngle < -angle) {
1025 maxRightAngle = -angle;
1029 if (maxLeftAngle < angle) {
1030 maxLeftAngle = angle;
1035 while (*pIn != out) {
1036 extraWidthLeft += (*pIn)->getTotalWidth();
1039 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" extra=" << (*pIn)->getID() <<
" extraWidthLeft=" << extraWidthLeft <<
"\n";
1046 int wideLanesOut = 0;
1047 for (
int i = 0; i < out->getNumLanes(); i++) {
1054 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" wideLanesIn=" << wideLanesIn <<
" wideLanesOut=" << wideLanesOut <<
"\n";
1057 laneDelta =
MAX2(laneDelta, abs(wideLanesOut - wideLanesIn));
1063 int totalWideLanesOut = 0;
1065 for (
int i = 0; i < out->getNumLanes(); i++) {
1067 totalWideLanesOut++;
1071 if (totalWideLanesIn == totalWideLanesOut) {
1078 double result = radius;
1080 double maxTurnAngle = maxRightAngle;
1081 double extraWidth = extraWidthRight;
1082 if (maxRightAngle <
DEG2RAD(5)) {
1083 maxTurnAngle = maxLeftAngle;
1084 extraWidth = extraWidthLeft;
1086 const double minRadius = maxTurnAngle >=
DEG2RAD(30) ?
MIN2(smallRadius, radius) : smallRadius;
1090 result = radius * tan(0.5 *
MIN2(0.5 *
M_PI, maxTurnAngle)) - extraWidth;
1092 result =
MAX2(minRadius, result);
1095 std::cout <<
"getDefaultRadius n=" <<
myNode.
getID()
1096 <<
" r=" << radius <<
" sr=" << smallRadius
1097 <<
" mr=" << minRadius
1098 <<
" laneDelta=" << laneDelta
1099 <<
" rightA=" <<
RAD2DEG(maxRightAngle)
1100 <<
" leftA=" <<
RAD2DEG(maxLeftAngle)
1101 <<
" maxA=" <<
RAD2DEG(maxTurnAngle)
1102 <<
" extraWidth=" << extraWidth
1103 <<
" result=" << result <<
"\n";
1112 if (same.size() < 2) {
1115 std::set<Position> endPoints;
1118 endPoints.insert(s->getEndpointAtNode(&
myNode));
1120 if (endPoints.size() > 1) {
1121 std::vector<double> distances = ccw.
distances(cw,
true);
1123 for (
const NBEdge* e2 : same) {
1124 width += e2->getTotalWidth();
1127 const double maxDivider = maxDist - width;
1128 return maxDivider >= 5;
1138 while (lane < e->getNumLanes() && e->
getPermissions(lane) == 0) {
1142 while (lane < e->getNumLanes() && (e->
getPermissions(lane) & exclude) == 0) {
1154 for (
NBEdge* e2 : same) {
1155 result -= e2->getTotalWidth();
1157 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 (exclusive) 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
bool needsLargeTurn(NBEdge *e1, NBEdge *e2, std::map< NBEdge *, std::set< NBEdge *, ComparatorIdLess > > &same) const
whether the given edges (along with those in the same direction) requires a large turning radius
const PositionVector computeNodeShapeSmall()
Computes the node geometry using normals.
double myRadius
the computed node radius
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
void joinSameDirectionEdges(const EdgeVector &edges, std::map< NBEdge *, std::set< NBEdge *, ComparatorIdLess > > &same, bool useEndpoints)
Joins edges and computes ccw/cw 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.
bool isDivided(const NBEdge *e, std::set< NBEdge *, ComparatorIdLess > same, const PositionVector &ccw, const PositionVector &cw) const
static double divisionWidth(const NBEdge *e, std::set< NBEdge *, ComparatorIdLess > same, const Position &p, const Position &p2)
compute the width of the divider space for divided roads
const NBNode & myNode
The node to compute the geometry for.
EdgeVector computeUniqueDirectionList(const EdgeVector &all, std::map< NBEdge *, std::set< NBEdge *, ComparatorIdLess > > &same, GeomsMap &geomsCCW, GeomsMap &geomsCW)
Joins edges.
void computeSameEnd(PositionVector &l1, PositionVector &l2)
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.
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)
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
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
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)