40#define DEBUGCOND (myNode.getID() == "C")
56 myRadius(node.getRadius()) {
65#ifdef DEBUG_NODE_SHAPE
97 assert(l1[0].distanceTo2D(l1[1]) >=
EXT);
98 assert(l2[0].distanceTo2D(l2[1]) >=
EXT);
101 tmp.push_back(l1[1]);
103 tmp[1].set(-tmp[1].y(), tmp[1].x());
108 if (l2.
length2D() - offset > POSITION_EPS) {
111 l2.erase(l2.begin(), l2.begin() + (l2.size() - tl2.size()));
129 double smallRadius = useDefaultRadius ? oc.
getFloat(
"junctions.small-radius") :
myRadius;
130 const int cornerDetail = oc.
getInt(
"junctions.corner-detail");
131 const double sCurveStretch = oc.
getFloat(
"junctions.scurve-stretch");
132 const bool rectangularCut = oc.
getBool(
"rectangular-lane-cut");
133 const bool openDriveOutput = oc.
isSet(
"opendrive-output");
140 const double advanceStopLine = oc.
exists(
"opendrive-files") && oc.
isSet(
"opendrive-files") ? oc.
getFloat(
"opendrive.advance-stopline") : 0;
143#ifdef DEBUG_NODE_SHAPE
145 std::cout <<
"\ncomputeNodeShapeDefault node " <<
myNode.
getID() <<
" simple=" << simpleContinuation <<
" useDefaultRadius=" << useDefaultRadius <<
" radius=" <<
myRadius <<
"\n";
150 EdgeVector::const_iterator i;
152 std::map<NBEdge*, std::set<NBEdge*> > same;
165 if (newAll.size() < 2) {
174 std::map<NBEdge*, double> distances;
175 std::map<NBEdge*, bool> myExtended;
177 for (i = newAll.begin(); i != newAll.end(); ++i) {
178 EdgeVector::const_iterator cwi = i;
179 EdgeVector::const_iterator ccwi = i;
182 initNeighbors(newAll, i, geomsCW, geomsCCW, cwi, ccwi, cad, ccad);
183 assert(geomsCCW.find(*i) != geomsCCW.end());
184 assert(geomsCW.find(*ccwi) != geomsCW.end());
185 assert(geomsCW.find(*cwi) != geomsCW.end());
191 (simpleContinuation && fabs(ccad - cad) < (
double) 0.1)
194 || (!simpleContinuation && fabs(ccad - cad) <
DEG2RAD(22.5)))
198 if (myExtended.find(*ccwi) != myExtended.end()) {
199 p = geomsCCW[*ccwi][0];
200 p.
add(geomsCW[*ccwi][0]);
202#ifdef DEBUG_NODE_SHAPE
204 std::cout <<
" extended: p=" << p <<
" angle=" << (ccad - cad) <<
"\n";
208 p = geomsCCW[*ccwi][0];
209 p.
add(geomsCW[*ccwi][0]);
210 p.
add(geomsCCW[*i][0]);
211 p.
add(geomsCW[*i][0]);
213#ifdef DEBUG_NODE_SHAPE
215 std::cout <<
" unextended: p=" << p <<
" angle=" << (ccad - cad) <<
"\n";
221 geomsCCW[*i].nearest_offset_to_point2D(p),
222 geomsCW[*i].nearest_offset_to_point2D(p));
238 (*i)->setGeometry(g);
240 geomsCCW[*i] = (*i)->getCCWBoundaryLine(
myNode);
241 geomsCCW[*i].extrapolate(
EXT);
242 geomsCW[*i] = (*i)->getCWBoundaryLine(
myNode);
243 geomsCW[*i].extrapolate(
EXT);
246 myExtended[*i] =
true;
247#ifdef DEBUG_NODE_SHAPE
249 std::cout <<
" extending (dist=" << dist <<
")\n";
253 if (!simpleContinuation) {
257 double radius2 = fabs(ccad - cad) * (*i)->getNumLanes();
258 if (radius2 > NUMERICAL_EPS || openDriveOutput) {
259 radius2 =
MAX2(0.15, radius2);
266 radius2 =
MAX2(radius2, width / 2);
269#ifdef DEBUG_NODE_SHAPE
271 std::cout <<
" using radius=" << radius2 <<
" ccad=" << ccad <<
" cad=" << cad <<
"\n";
275 distances[*i] = dist;
281 const bool ccwCloser = ccad < cad;
284 const bool neighLargeTurn = ccwCloser ? ccwLargeTurn : cwLargeTurn;
285 const bool neigh2LargeTurn = ccwCloser ? cwLargeTurn : ccwLargeTurn;
287 const PositionVector& currGeom = ccwCloser ? geomsCCW[*i] : geomsCW[*i];
289 const PositionVector& currGeom2 = ccwCloser ? geomsCW[*i] : geomsCCW[*i];
291 const PositionVector& neighGeom = ccwCloser ? geomsCW[*ccwi] : geomsCCW[*cwi];
293 const PositionVector& neighGeom2 = ccwCloser ? geomsCCW[*cwi] : geomsCW[*ccwi];
294#ifdef DEBUG_NODE_SHAPE
296 std::cout <<
" i=" << (*i)->getID() <<
" neigh=" << (*ccwi)->getID() <<
" neigh2=" << (*cwi)->getID() <<
"\n";
297 std::cout <<
" ccwCloser=" << ccwCloser
298 <<
"\n currGeom=" << currGeom <<
" neighGeom=" << neighGeom
299 <<
"\n currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2
303 if (!simpleContinuation) {
306#ifdef DEBUG_NODE_SHAPE
308 std::cout <<
" neigh intersects dist=" << distances[*i] <<
" currGeom=" << currGeom <<
" neighGeom=" << neighGeom <<
"\n";
311 if (*cwi != *ccwi && currGeom2.
intersects(neighGeom2)) {
314 const double farAngleDist = ccwCloser ? cad : ccad;
315 double a1 = distances[*i];
317#ifdef DEBUG_NODE_SHAPE
319 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";
326 distances[*i] =
MAX2(a1, a2);
327 }
else if (ccad >
DEG2RAD(90. + 45.) && cad >
DEG2RAD(90. + 45.)) {
329 }
else if (farAngleDist <
DEG2RAD(135) || (fabs(
RAD2DEG(farAngleDist) - 180) > 1 && fabs(a2 - a1) < 10)) {
330 distances[*i] =
MAX2(a1, a2);
332#ifdef DEBUG_NODE_SHAPE
334 std::cout <<
" a1=" << a1 <<
" a2=" << a2 <<
" dist=" << distances[*i] <<
"\n";
339 if (*cwi != *ccwi && currGeom2.
intersects(neighGeom2)) {
341#ifdef DEBUG_NODE_SHAPE
343 std::cout <<
" neigh2 intersects dist=" << distances[*i] <<
" currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2 <<
"\n";
348#ifdef DEBUG_NODE_SHAPE
350 std::cout <<
" no intersects dist=" << distances[*i] <<
" currGeom=" << currGeom <<
" neighGeom=" << neighGeom <<
" currGeom2=" << currGeom2 <<
" neighGeom2=" << neighGeom2 <<
"\n";
359 distances[*i] = (double)
EXT;
363 if (useDefaultRadius && sCurveStretch > 0) {
365 if (sCurveWidth > 0) {
366 const double sCurveRadius =
myRadius + sCurveWidth /
SUMO_const_laneWidth * sCurveStretch * pow((*i)->getSpeed(), 2 + sCurveStretch) / 1000;
367 const double stretch =
EXT + sCurveRadius - distances[*i];
369 distances[*i] += stretch;
371 const double shorten = distances[*i] -
EXT;
372 (*i)->shortenGeometryAtNode(&
myNode, shorten);
373 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
374 (*k)->shortenGeometryAtNode(&
myNode, shorten);
376#ifdef DEBUG_NODE_SHAPE
378 std::cout <<
" stretching junction: sCurveWidth=" << sCurveWidth <<
" sCurveRadius=" << sCurveRadius <<
" stretch=" << stretch <<
" dist=" << distances[*i] <<
"\n";
386 for (
NBEdge*
const edge : newAll) {
387 if (distances.find(edge) == distances.end()) {
389 distances[edge] =
EXT;
393 const double off =
EXT - NUMERICAL_EPS;
397 for (
NBEdge*
const edge : newAll) {
398 if (distances[edge] < off && edge->hasDefaultGeometryEndpointAtNode(&
myNode)) {
399 for (EdgeVector::const_iterator j = newAll.begin(); j != newAll.end(); ++j) {
400 if (distances[*j] > off && (*j)->hasDefaultGeometryEndpointAtNode(&
myNode) && distances[edge] + distances[*j] < minDistSum) {
402 if (angleDiff > 160 || angleDiff < 20) {
403#ifdef DEBUG_NODE_SHAPE
405 std::cout <<
" increasing dist for i=" << edge->getID() <<
" because of j=" << (*j)->getID() <<
" jDist=" << distances[*j]
406 <<
" oldI=" << distances[edge] <<
" newI=" << minDistSum - distances[*j]
407 <<
" angleDiff=" << angleDiff
408 <<
" geomI=" << edge->getGeometry() <<
" geomJ=" << (*j)->getGeometry() <<
"\n";
411 distances[edge] = minDistSum - distances[*j];
421 for (i = newAll.begin(); i != newAll.end(); ++i) {
425 double offset = distances[*i];
426 if (!(*i)->hasDefaultGeometryEndpointAtNode(&
myNode)) {
428 if (advanceStopLine > 0 && offset <
EXT) {
429#ifdef DEBUG_NODE_SHAPE
430 std::cout <<
" i=" << (*i)->getID() <<
" offset=" << offset <<
" advanceStopLine=" << advanceStopLine <<
"\n";
433 (*i)->extendGeometryAtNode(&
myNode, advanceStopLine);
434 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
435 (*k)->extendGeometryAtNode(&
myNode, advanceStopLine);
438 offset =
MAX2(
EXT - advanceStopLine, offset);
442 offset = (double) - .1;
446 if (i != newAll.begin()) {
454#ifdef DEBUG_NODE_SHAPE
456 std::cout <<
" build stopLine for i=" << (*i)->getID() <<
" offset=" << offset <<
" dist=" << distances[*i] <<
" cwLength=" << cwBound.
length2D() <<
" ccwLength=" << ccwBound.
length2D() <<
" p=" << p <<
" p2=" << p2 <<
" ccwBound=" << ccwBound <<
" cwBound=" << cwBound <<
"\n";
459 (*i)->setNodeBorder(&
myNode, p, p2, rectangularCut);
460 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
461 (*k)->setNodeBorder(&
myNode, p, p2, rectangularCut);
465 ret.
append(
getSmoothCorner(geomsCW[*(newAll.end() - 1)], geomsCCW[*newAll.begin()], ret[-1], ret[0], cornerDetail));
466#ifdef DEBUG_NODE_SHAPE
468 std::cout <<
" final shape=" << ret <<
"\n";
478 double result = intersections[0];
479 for (std::vector<double>::iterator it = intersections.begin() + 1; it != intersections.end(); ++it) {
480 if (fabs(*it - offset) < fabs(result - offset)) {
489 std::map<
NBEdge*, std::set<NBEdge*> >& same)
const {
498 for (
NBEdge* e2s : same[e2]) {
503 for (
NBEdge* e1s : same[e1]) {
504 if ((e2s->getPermissions() & e1s->getPermissions() &
SVC_LARGE_TURN) != 0
505 && (e2s->getToNode() == e1s->getFromNode() || e1s->getToNode() == e2s->getFromNode())) {
510 for (
NBEdge* e1s : same[e1]) {
524 if (cornerDetail > 0) {
527#ifdef DEBUG_SMOOTH_CORNERS
529 std::cout <<
" begLength=" << begShape2.
length2D() <<
" begSplit=" << begSplit <<
"\n";
532 if (begSplit > POSITION_EPS && begSplit < begShape2.
length2D() - POSITION_EPS) {
533 begShape2 = begShape2.
splitAt(begSplit,
true).first;
539#ifdef DEBUG_SMOOTH_CORNERS
541 std::cout <<
" endLength=" << endShape2.
length2D() <<
" endSplit=" << endSplit <<
"\n";
544 if (endSplit > POSITION_EPS && endSplit < endShape2.
length2D() - POSITION_EPS) {
545 endShape2 = endShape2.
splitAt(endSplit,
true).second;
552#ifdef DEBUG_SMOOTH_CORNERS
554 std::cout <<
"getSmoothCorner begPoint=" << begPoint <<
" endPoint=" << endPoint
555 <<
" begShape=" << begShape <<
" endShape=" << endShape
556 <<
" begShape2=" << begShape2 <<
" endShape2=" << endShape2
560 if (begShape2.size() < 2 || endShape2.size() < 2) {
564 NBNode* recordError =
nullptr;
565#ifdef DEBUG_SMOOTH_CORNERS
567 std::cout <<
" angle=" <<
RAD2DEG(angle) <<
"\n";
578#ifdef DEBUG_SMOOTH_CORNERS
580 std::cout <<
" curve=" << curve <<
" curveLength=" << curve.
length2D() <<
" dist=" << begPoint.
distanceTo2D(endPoint) <<
" curvature=" << curvature <<
"\n";
583 if (curvature > 2 && angle >
DEG2RAD(85)) {
587 if (curve.size() > 2) {
588 curve.erase(curve.begin());
601 for (
NBEdge*
const edge : edges) {
604 geomsCCW[edge] = edge->getCCWBoundaryLine(
myNode);
606 WRITE_WARNING(
"While computing intersection geometry at junction '" +
myNode.
getID() +
"': " + std::string(e.what()));
607 geomsCCW[edge] = edge->getGeometry();
610 geomsCW[edge] = edge->getCWBoundaryLine(
myNode);
612 WRITE_WARNING(
"While computing intersection geometry at junction '" +
myNode.
getID() +
"': " + std::string(e.what()));
613 geomsCW[edge] = edge->getGeometry();
616 if (geomsCCW[edge].length2D() < NUMERICAL_EPS) {
617 geomsCCW[edge] = edge->getGeometry();
619 if (geomsCW[edge].length2D() < NUMERICAL_EPS) {
620 geomsCW[edge] = edge->getGeometry();
623 geomsCCW[edge] = geomsCCW[edge].getSubpart2D(0,
MAX2(
EXT, edge->getTotalWidth()));
624 geomsCW[edge] = geomsCW[edge].getSubpart2D(0,
MAX2(
EXT, edge->getTotalWidth()));
626 geomsCCW[edge].extrapolate2D(
EXT,
true);
627 geomsCW[edge].extrapolate2D(
EXT,
true);
629 geomsCCW[edge].extrapolate(
EXT2,
false,
true);
630 geomsCW[edge].extrapolate(
EXT2,
false,
true);
638 const double angleChangeLookahead = 35;
641 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); i++) {
642 EdgeVector::const_iterator j;
643 if (i == edges.end() - 1) {
648 const bool incoming = (*i)->getToNode() == &
myNode;
649 const bool incoming2 = (*j)->getToNode() == &
myNode;
650 const bool differentDirs = (incoming != incoming2);
651 const bool sameGeom = (*i)->getGeometry() == (differentDirs ? (*j)->getGeometry().reverse() : (*j)->getGeometry());
654 const double angle1further = (g1.size() > 2 && g1[0].distanceTo2D(g1[1]) < angleChangeLookahead ?
656 const double angle2further = (g2.size() > 2 && g2[0].distanceTo2D(g2[1]) < angleChangeLookahead ?
660 const bool ambiguousGeometry = ((angleDiff > 0 && angleDiffFurther < 0) || (angleDiff < 0 && angleDiffFurther > 0));
665#ifdef DEBUG_NODE_SHAPE
667 std::cout <<
" checkSameDirection " << (*i)->getID() <<
" " << (*j)->getID()
668 <<
" diffDirs=" << differentDirs
669 <<
" isOpposite=" << (differentDirs && foundOpposite.count(*i) == 0)
670 <<
" angleDiff=" << angleDiff
671 <<
" ambiguousGeometry=" << ambiguousGeometry
677 if (sameGeom || fabs(angleDiff) <
DEG2RAD(20)) {
678 const bool isOpposite = differentDirs && foundOpposite.count(*i) == 0;
680 foundOpposite.insert(*i);
681 foundOpposite.insert(*j);
685 for (std::set<NBEdge*>::iterator k = same[*i].begin(); k != same[*i].end(); ++k) {
691 for (std::set<NBEdge*>::iterator k = same[*j].begin(); k != same[*j].end(); ++k) {
699#ifdef DEBUG_NODE_SHAPE
701 std::cout <<
" joinedSameDirectionEdges " << (*i)->getID() <<
" " << (*j)->getID() <<
" isOpposite=" << isOpposite <<
" ambiguousGeometry=" << ambiguousGeometry <<
"\n";
733 double endAngleDiff = 0;
734 if (geom1.size() >= 2 && geom2.size() >= 2) {
737 geom2.
angleAt2D((
int)geom2.size() - 2))));
740 std::vector<double> distances = geom1.
distances(geom2,
true);
743 const bool curvingTowards = geom1[0].distanceTo2D(geom2[0]) > minDistanceThreshold && minDist < minDistanceThreshold;
744 const bool onTop = (maxDist - POSITION_EPS < minDistanceThreshold) && endAngleDiff < 30;
749#ifdef DEBUG_NODE_SHAPE
751 std::cout <<
" badIntersect: onTop=" << onTop <<
" curveTo=" << curvingTowards <<
" intersects=" << intersects
752 <<
" endAngleDiff=" << endAngleDiff
753 <<
" geom1=" << geom1 <<
" geom2=" << geom2
754 <<
" distances=" <<
toString(distances) <<
" minDist=" << minDist <<
" maxDist=" << maxDist <<
" thresh=" << minDistanceThreshold
755 <<
" intersectPos=" << intersect
759 return onTop || curvingTowards || !intersects;
766 std::map<
NBEdge*, std::set<NBEdge*> >& same,
773 auto e2NewAll = std::find(newAll.begin(), newAll.end(), e1);
774#ifdef DEBUG_NODE_SHAPE
775 if (
DEBUGCOND) std::cout <<
"computeUniqueDirectionList e1=" << e1->getID()
776 <<
" deleted=" << (e2NewAll == newAll.end())
779 if (e2NewAll == newAll.end()) {
782 auto e1It = std::find(all.begin(), all.end(), e1);
788 for (
NBEdge* e2 : same[e1]) {
789#ifdef DEBUG_NODE_SHAPE
791 std::cout <<
" e2=" << e2->getID() <<
"\n";
794 auto e2It = std::find(all.begin(), all.end(), e2);
795 if (e2It + 1 == bestCCW || (e2It == (all.end() - 1) && bestCCW == all.begin())) {
798#ifdef DEBUG_NODE_SHAPE
800 std::cout <<
" bestCCW=" << e2->getID() <<
"\n";
803 }
else if (bestCW + 1 == e2It || (bestCW == (all.end() - 1) && e2It == all.begin())) {
806#ifdef DEBUG_NODE_SHAPE
808 std::cout <<
" bestCW=" << e2->getID() <<
"\n";
814 if (bestCW != e1It) {
815 geomsCW[e1] = geomsCW[*bestCW];
818 if (bestCCW != e1It) {
819 geomsCCW[e1] = geomsCCW[*bestCCW];
823 for (
NBEdge* e2 : same[e1]) {
824 auto e2NewAllIt = std::find(newAll.begin(), newAll.end(), e2);
825 if (e2NewAllIt != newAll.end()) {
826 newAll.erase(e2NewAllIt);
830#ifdef DEBUG_NODE_SHAPE
832 std::cout <<
" newAll:\n";
833 for (
NBEdge* e : newAll) {
834 std::cout <<
" " << e->getID() <<
" geomCCW=" << geomsCCW[e] <<
" geomsCW=" << geomsCW[e] <<
"\n";
846 EdgeVector::const_iterator& cwi,
847 EdgeVector::const_iterator& ccwi,
850 const double twoPI = (double)(2 *
M_PI);
853 if (cwi == edges.end()) {
854 std::advance(cwi, -((
int)edges.size()));
857 if (ccwi == edges.begin()) {
858 std::advance(ccwi, edges.size() - 1);
863 const double angleCurCCW = geomsCCW[*current].angleAt2D(0);
864 const double angleCurCW = geomsCW[*current].angleAt2D(0);
865 const double angleCCW = geomsCW[*ccwi].angleAt2D(0);
866 const double angleCW = geomsCCW[*cwi].angleAt2D(0);
867 ccad = angleCCW - angleCurCCW;
871 cad = angleCurCW - angleCW;
881#ifdef DEBUG_NODE_SHAPE
883 std::cout <<
"computeNodeShapeSmall node=" <<
myNode.
getID() <<
"\n";
891 Position delta = edgebound1[1] - edgebound1[0];
892 delta.
set(-delta.
y(), delta.
x());
907 e->resetNodeBorder(&
myNode);
918 const double radius = oc.
getFloat(
"default.junctions.radius");
919 const double smallRadius = oc.
getFloat(
"junctions.small-radius");
920 double maxRightAngle = 0;
921 double extraWidthRight = 0;
922 double maxLeftAngle = 0;
923 double extraWidthLeft = 0;
925 int totalWideLanesIn = 0;
928 for (
int i = 0; i < in->getNumLanes(); i++) {
933 totalWideLanesIn += wideLanesIn;
935 if ((in->getPermissions() & out->getPermissions() &
SVC_LARGE_TURN) != 0) {
940 in->getGeometry().angleAt2D(-2),
941 out->getGeometry().angleAt2D(0));
943 if (maxRightAngle < -angle) {
944 maxRightAngle = -angle;
948 if (maxLeftAngle < angle) {
949 maxLeftAngle = angle;
954 while (*pIn != out) {
955 extraWidthLeft += (*pIn)->getTotalWidth();
958 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" extra=" << (*pIn)->getID() <<
" extraWidthLeft=" << extraWidthLeft <<
"\n";
965 int wideLanesOut = 0;
966 for (
int i = 0; i < out->getNumLanes(); i++) {
973 std::cout <<
" in=" << in->getID() <<
" out=" << out->getID() <<
" wideLanesIn=" << wideLanesIn <<
" wideLanesOut=" << wideLanesOut <<
"\n";
976 laneDelta =
MAX2(laneDelta, abs(wideLanesOut - wideLanesIn));
982 int totalWideLanesOut = 0;
984 for (
int i = 0; i < out->getNumLanes(); i++) {
990 if (totalWideLanesIn == totalWideLanesOut) {
997 double result = radius;
999 double maxTurnAngle = maxRightAngle;
1000 double extraWidth = extraWidthRight;
1001 if (maxRightAngle <
DEG2RAD(5)) {
1002 maxTurnAngle = maxLeftAngle;
1003 extraWidth = extraWidthLeft;
1005 const double minRadius = maxTurnAngle >=
DEG2RAD(30) ?
MIN2(smallRadius, radius) : smallRadius;
1009 result = radius * tan(0.5 *
MIN2(0.5 *
M_PI, maxTurnAngle)) - extraWidth;
1011 result =
MAX2(minRadius, result);
1014 std::cout <<
"getDefaultRadius n=" <<
myNode.
getID()
1015 <<
" r=" << radius <<
" sr=" << smallRadius
1016 <<
" mr=" << minRadius
1017 <<
" laneDelta=" << laneDelta
1018 <<
" rightA=" <<
RAD2DEG(maxRightAngle)
1019 <<
" leftA=" <<
RAD2DEG(maxLeftAngle)
1020 <<
" maxA=" <<
RAD2DEG(maxTurnAngle)
1021 <<
" extraWidth=" << extraWidth
1022 <<
" result=" << result <<
"\n";
1033 while (lane < e->getNumLanes() && e->
getPermissions(lane) == 0) {
1037 while (lane < e->getNumLanes() && (e->
getPermissions(lane) & exclude) == 0) {
#define WRITE_WARNINGF(...)
#define WRITE_WARNING(msg)
std::set< NBEdge * > EdgeSet
container for unique edges
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
void computeSameEnd(PositionVector &l1, PositionVector &l2)
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
@ 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
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ 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.
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
NBNode * getFromNode() const
Returns the origin node of the edge.
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
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.
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.
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.
const PositionVector compute()
Computes the shape of the assigned junction.
~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 NBNode & myNode
The node to compute the geometry for.
void joinSameDirectionEdges(const EdgeVector &edges, std::map< NBEdge *, std::set< NBEdge * > > &same)
Joins edges and computes ccw/cw boundaries.
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
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 both positions 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 ammount
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
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)