44#define DEBUGNODEID "gneJ34"
45#define DEBUGNODEID2 "28842974"
46#define DEBUGEDGEID "22820560#0"
47#define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID))
49#define SHARP_THRESHOLD_SAMEDIR 100
50#define SHARP_THRESHOLD 80
67const std::vector<NBRailwayTopologyAnalyzer::Track*>&
69 if ((minPermissions & svc) != 0) {
72 if (svcSuccessors.count(svc) == 0) {
73 std::vector<Track*> succ;
74 for (
Track* t : successors) {
75 if ((t->edge->getPermissions() & svc) != 0) {
79 svcSuccessors[svc] = succ;
81 return svcSuccessors[svc];
86const std::vector<std::pair<const NBRailwayTopologyAnalyzer::Track*, const NBRailwayTopologyAnalyzer::Track*> >&
88 if ((minPermissions & svc) != 0) {
91 if (svcViaSuccessors.count(svc) == 0) {
92 std::vector<std::pair<const Track*, const Track*> >& succ = svcViaSuccessors[svc];
93 for (
const Track*
const t : successors) {
94 if ((t->edge->getPermissions() & svc) != 0) {
95 succ.push_back(std::make_pair(t,
nullptr));
99 return svcViaSuccessors[svc];
137 int numNotCenterEdges = 0;
138 int numAddedBidiEdges = 0;
140 std::vector<NBEdge*> edges;
141 if (inputfile ==
"") {
143 edges.push_back(edge);
146 std::set<std::string> edgeIDs;
148 for (
const std::string& edgeID : edgeIDs) {
150 if (edge !=
nullptr) {
151 edges.push_back(edge);
155 for (
NBEdge* edge : edges) {
159 if (!edge->isBidiRail()) {
171 WRITE_MESSAGEF(
TL(
"Added % bidi-edges to ensure that all tracks are usable in both directions."),
toString(numAddedBidiEdges));
172 if (numNotCenterEdges) {
175 return numAddedBidiEdges;
183 const std::string id2 = (edge->
getID()[0] ==
'-'
184 ? edge->
getID().substr(1)
185 :
"-" + edge->
getID());
211 incoming->invalidateConnections(
true);
228 inEdges.push_back(e);
233 outEdges.push_back(e);
241 std::set<NBNode*> brokenNodes;
247 std::set<NBNode*> railNodes =
getRailNodes(ec, verbose);
248 std::map<std::pair<int, int>, std::set<NBNode*, ComparatorIdLess> > types;
249 std::set<NBEdge*, ComparatorIdLess> bidiEdges;
250 std::set<NBEdge*, ComparatorIdLess> bufferStops;
254 types[std::make_pair((
int)inEdges.size(), (
int)outEdges.size())].insert(
node);
255 for (
NBEdge* e : outEdges) {
256 if (e->isBidiRail() && bidiEdges.count(e->getTurnDestination(
true)) == 0) {
259 if (e->getID()[0] ==
'-') {
261 }
else if (primary->
getID()[0] !=
'-' && secondary->
getID()[0] !=
'-' && secondary->
getID() < primary->
getID()) {
264 if (bidiEdges.count(secondary) == 0) {
266 bidiEdges.insert(primary);
276 int numBufferStops = 0;
277 if (verbose && types.size() > 0) {
278 WRITE_MESSAGE(
TL(
"Railway nodes by number of incoming,outgoing edges:"))
283 device.
writeAttr(
"meaning",
"edge pair angle supports driving but both are outgoing");
287 device.
writeAttr(
"meaning",
"edge pair angle supports driving but both are incoming");
291 device.
writeAttr(
"meaning",
"an incoming edge has a sharp angle to all outgoing edges");
295 device.
writeAttr(
"meaning",
"an outgoing edge has a sharp angle from all incoming edges");
299 for (
auto it : types) {
300 int numBrokenType = 0;
301 device.
openTag(
"railNodeType");
302 int in = it.first.first;
303 int out = it.first.second;
306 for (
NBNode* n : it.second) {
314 std::string broken =
"";
324 for (
NBEdge* e : inRail) {
335 for (
NBEdge* e : outRail) {
346 if (((in == 1 && out == 1) || (in == 2 && out == 2))
351 if (broken.size() > 0) {
353 brokenNodes.insert(n);
365 +
" count: " +
toString(it.second.size()) +
" broken: " +
toString(numBrokenType));
379 for (
NBEdge* e : bidiEdges) {
382 device.
writeAttr(
"bidi", e->getTurnDestination(
true)->getID());
396 std::set<NBNode*> railNodes;
397 int numRailEdges = 0;
398 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
399 if (
hasRailway(it->second->getPermissions())) {
401 railNodes.insert(it->second->getFromNode());
402 railNodes.insert(it->second->getToNode());
405 int numRailSignals = 0;
444#ifdef DEBUG_SEQSTOREVERSE
449 for (
NBEdge* e1 : edges) {
450 for (
NBEdge* e2 : edges2) {
472 std::cout <<
" isStraight e=" << e->getID() <<
" candOut=" << candOut->
getID() <<
"\n";
480 std::cout <<
" isSharp e=" << e->getID() <<
" candOut=" << candOut->
getID() <<
"\n";
497 if (!e1->isBidiRail(
true)) {
503 return !
allBidi || countBidiAsSharp;
510 if (!e->isBidiRail()) {
521 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
539 if (bidiOut ==
nullptr) {
544 tmpBidiOut.push_back(bidiOut);
546 tmpBidiIn.push_back(bidiIn);
550 for (
NBEdge* cand : outRail) {
561 for (
NBEdge* cand : inRail) {
580 std::vector<EdgeVector> seqsToReverse;
583 const EdgeVector& route = item.second->getEdges();
584 lineEdges.insert(route.begin(), route.end());
586 for (
NBNode* n : brokenNodes) {
589 for (
NBEdge* start : outRail) {
591 if (!
allBroken(n, start, inRail, outRail)
592 || (inRail.size() == 1 && outRail.size() == 1)) {
593#ifdef DEBUG_SEQSTOREVERSE
595 std::cout <<
" abort at start n=" << n->getID() <<
" (not all broken)\n";
604 if (lineEdges.count(start)) {
609#ifdef DEBUG_SEQSTOREVERSE
616 seq.push_back(start);
618 NBNode* n2 = start->getToNode();
621 if (brokenNodes.count(n2) != 0) {
623 tmp2.push_back(start);
624 if (
allBroken(n2, start, outRail2, inRail2)) {
625 seqsToReverse.push_back(seq);
627#ifdef DEBUG_SEQSTOREVERSE
629 std::cout <<
" abort at n2=" << n2->
getID() <<
" (not all broken)\n";
635 if (outRail2.size() == 0) {
638#ifdef DEBUG_SEQSTOREVERSE
640 std::cout <<
" abort at n2=" << n2->
getID() <<
" (border)\n";
643 }
else if (outRail2.size() > 1 || inRail2.size() > 1) {
646#ifdef DEBUG_SEQSTOREVERSE
648 std::cout <<
" abort at n2=" << n2->
getID() <<
" (switch)\n";
652 start = outRail2.front();
659 if (seqsToReverse.size() > 0) {
662 std::sort(seqsToReverse.begin(), seqsToReverse.end(),
664 return a.size() < b.size();
667 std::set<NBNode*> affectedEndpoints;
668 std::set<std::string> reversedIDs;
669 std::map<int, int> seqLengths;
671 NBNode* seqStart = seq.front()->getFromNode();
672 NBNode* seqEnd = seq.back()->getToNode();
674 if (affectedEndpoints.count(seqStart) == 0
675 && affectedEndpoints.count(seqEnd) == 0) {
676 affectedEndpoints.insert(seqStart);
677 affectedEndpoints.insert(seqEnd);
681 reversedIDs.insert(e->getID());
683 seqLengths[(int)seq.size()]++;
687 if (numReversed > 0) {
690 if (reversedIDs.count(item.second->getEdgeId())) {
691 item.second->findLaneAndComputeBusStopExtent(ec);
714 int numBufferStops = 0;
715 int numAddedBidiTotal = 0;
718 if (
node->getEdges().size() != 1) {
729 while (prev ==
nullptr || (inRail.size() + outRail.size()) == 3) {
731 if (prev ==
nullptr) {
732 assert(
node->getEdges().size() == 1);
733 e =
node->getEdges().front();
738 assert(inRail.size() == 2);
739 e = inRail.front() == prev2 ? inRail.back() : inRail.front();
742 assert(outRail.size() == 2);
743 e = outRail.front() == prev2 ? outRail.back() : outRail.front();
775 if (numAddedBidiTotal > 0) {
778 return numAddedBidiTotal;
785 if (inRail.size() == 2 && outRail.size() == 1 &&
isStraight(n, inRail.front(), inRail.back())) {
786 if (
isStraight(n, inRail.front(), outRail.front())) {
787 return inRail.front();
788 }
else if (
isStraight(n, inRail.back(), outRail.front())) {
789 return inRail.back();
792 if (inRail.size() == 1 && outRail.size() == 2 &&
isStraight(n, outRail.front(), outRail.back())) {
793 if (
isStraight(n, outRail.front(), inRail.front())) {
794 return outRail.front();
795 }
else if (
isStraight(n, outRail.back(), inRail.front())) {
796 return outRail.back();
806 std::map<int, int> seqLengths;
809 for (
NBNode* n : brokenNodes) {
812 std::vector<NBNode*> nodeSeq;
815 nodeSeq.push_back(prev);
816 edgeSeq.push_back(edge);
824 if (allRail.size() == 2 &&
isStraight(next, allRail.front(), allRail.back())) {
826 edge = allRail.front() == edge ? allRail.back() : allRail.front();
827 nodeSeq.push_back(prev);
828 edgeSeq.push_back(edge);
837 for (
NBEdge* e : edgeSeq) {
840 seqLengths[(int)edgeSeq.size()]++;
842 numAdded += (int)edgeSeq.size();
856 if (seqLengths.size() > 0) {
865 std::set<NBPTLine*> result;
866 std::set<std::pair<std::shared_ptr<NBPTStop>, std::shared_ptr<NBPTStop> > > visited;
867 for (
const auto& item : lc.
getLines()) {
868 const std::vector<std::shared_ptr<NBPTStop> >& stops = item.second->getStops();
869 if (stops.size() > 1) {
870 for (
auto it = stops.begin(); it + 1 != stops.end(); ++it) {
871 std::shared_ptr<NBPTStop> fromStop = *it;
872 std::shared_ptr<NBPTStop> toStop = *(it + 1);
873 visited.insert({fromStop, toStop});
877 for (
const auto& item : lc.
getLines()) {
878 const std::vector<std::shared_ptr<NBPTStop> >& stops = item.second->getStops();
879 if (stops.size() > 1) {
880 for (
auto it = stops.begin(); it + 1 != stops.end(); ++it) {
881 std::shared_ptr<NBPTStop> fromStop = *it;
882 std::shared_ptr<NBPTStop> toStop = *(it + 1);
883 std::pair<std::shared_ptr<NBPTStop>, std::shared_ptr<NBPTStop> > reverseTrip({toStop, fromStop});
884 if (visited.count(reverseTrip)) {
885 result.insert(item.second);
898 std::vector<Track*> tracks;
900 tracks.push_back(
new Track(edge));
902 const int numEdges = (int)tracks.size();
904 tracks.push_back(
new Track(edge, (
int)tracks.size(), edge->getID() +
"_reverse", penalty));
907 std::map<NBEdge*, std::pair<Track*, Track*> > stopTracks;
910 Track* start =
new Track(edge, (
int)tracks.size(), edge->getID() +
"_start");
911 tracks.push_back(start);
912 Track* end =
new Track(edge, (
int)tracks.size(), edge->getID() +
"_end");
913 tracks.push_back(end);
914 stopTracks[edge] = {start, end};
921 for (
NBEdge* e1 : railEdges) {
922 for (
NBEdge* e2 : railEdges) {
924 int i = e1->getNumericalID();
925 int i2 = e2->getNumericalID();
926 if (e1->getToNode() ==
node) {
927 if (e2->getFromNode() ==
node) {
929 tracks[i]->addSuccessor(tracks[i2]);
931 tracks[i2 + numEdges]->addSuccessor(tracks[i + numEdges]);
934 tracks[i]->addSuccessor(tracks[i2 + numEdges]);
935 tracks[i2]->addSuccessor(tracks[i + numEdges]);
938 if (e2->getFromNode() ==
node) {
940 tracks[i + numEdges]->addSuccessor(tracks[i2]);
941 tracks[i2 + numEdges]->addSuccessor(tracks[i]);
952 for (
auto& item : stopTracks) {
953 const int index = item.first->getNumericalID();
955 item.second.first->addSuccessor(tracks[index]);
956 item.second.first->addSuccessor(tracks[index + numEdges]);
958 tracks[index]->addSuccessor(item.second.second);
959 tracks[index + numEdges]->addSuccessor(item.second.second);
975 int numDisconnected = 0;
976 std::set<std::shared_ptr<NBPTStop>> addBidiStops;
977 std::set<NBEdge*, ComparatorIdLess> addBidiStopEdges;
978 std::set<NBEdge*, ComparatorIdLess> addBidiEdges;
979 std::set<std::pair<std::string, std::string> > visited;
986 for (
const auto& item : lc.
getLines()) {
988 std::vector<NBPTLine::PTStopInfo> stops = line->
getStopEdges(ec);
989 std::vector<NBEdge*> stopEdges;
990 for (
auto it : stops) {
991 stopEdges.push_back(it.edge);
995 if (routeStart !=
nullptr && (stopEdges.empty() || routeStart != stopEdges.front())) {
998 if (routeEnd !=
nullptr && (stopEdges.empty() || routeEnd != stopEdges.back())) {
1001 if (stops.size() < 2) {
1004 if (!line->
isConsistent(stopEdges) && requireBidi.count(line) == 0) {
1005 WRITE_WARNINGF(
TL(
"Edge sequence is not consistent with stop sequence in line '%', not adding bidi edges."), item.first);
1008 for (
auto it = stops.begin(); it + 1 != stops.end(); ++it) {
1009 NBEdge* fromEdge = it->edge;
1010 NBEdge* toEdge = (it + 1)->edge;
1011 const std::string fromStop = it->stopID;
1012 const std::string toStop = (it + 1)->stopID;
1013 const double fromPos = it->pos;
1014 const double toPos = (it + 1)->pos;
1015 bool fromRevised = it->revised;
1016 bool toRevised = (it + 1)->revised;
1017 std::pair<std::string, std::string> trip(fromStop, toStop);
1018 std::pair<std::string, std::string> reverseTrip(toStop, fromStop);
1022 if (visited.count(trip) != 0) {
1025 visited.insert(trip);
1027 if (stopTracks.count(fromEdge) == 0
1028 || stopTracks.count(toEdge) == 0) {
1031 bool needBidi = visited.count(reverseTrip) != 0;
1033 std::vector<const Track*> route;
1034 Track* from = fromRevised ? tracks[fromEdge->
getNumericalID()] : stopTracks[fromEdge].first;
1036 int iStart = fromRevised ? 0 : 1;
1037 int iDeltaEnd = toRevised ? 0 : 1;
1038 if (fromEdge == toEdge && fromPos > toPos) {
1045 router->
compute(from, to, &veh, 0, route);
1050 if (route.size() > 0) {
1051 assert((
int)route.size() > iStart + iDeltaEnd);
1052 for (
int i = iStart; i < (int)route.size() - iDeltaEnd; ++i) {
1053 const bool isBidi = route[i]->getNumericalID() >= numEdges;
1054 bool isStop = i == iStart || i == (int)route.size() - 1 - iDeltaEnd;
1055 if (isBidi || needBidi) {
1056 NBEdge* edge = route[i]->edge;
1057 if (addBidiEdges.count(edge) == 0) {
1060 addBidiEdges.insert(edge);
1062 addBidiStopEdges.insert(edge);
1066 WRITE_WARNINGF(
TL(
"Stop on edge '%' can only be reached in reverse but edge has the wrong spreadType."), fromEdge->
getID());
1072 if (isStop && isBidi) {
1073 std::shared_ptr<NBPTStop> fs = sc.
get(fromStop);
1075 addBidiStops.insert(fs);
1077 std::shared_ptr<NBPTStop> ts = sc.
get(toStop);
1079 addBidiStops.insert(ts);
1089 for (
NBEdge* edge : addBidiEdges) {
1090 if (!edge->isBidiRail()) {
1091 if (edge->getFromNode()->getIncomingEdges().size() == 0
1092 && edge->getToNode()->getOutgoingEdges().size() == 0) {
1098 if (e2 !=
nullptr) {
1108 for (std::shared_ptr<NBPTStop> stop : addBidiStops) {
1109 std::shared_ptr<NBPTStop> fromReverse = sc.
getReverseStop(stop, ec);
1112 stop->setBidiStop(fromReverse);
1115 if (addBidiEdges.size() > 0 || numDisconnected > 0) {
1116 WRITE_MESSAGE(
"Added " +
toString(addBidiStopEdges.size()) +
" bidi-edges for public transport stops and a total of "
1117 +
toString(added) +
" bidi-edges to ensure connectivity of stops ("
1118 +
toString(numDisconnected) +
" stops remain disconnected)");
1122 for (
Track* t : tracks) {
1126 return (
int)addBidiEdges.size();
1134 for (
const auto& e : ec) {
1135 if (!
hasRailway(e.second->getPermissions())) {
1138 NBNode*
const from = e.second->getFromNode();
1139 NBNode*
const to = e.second->getToNode();
1140 if (brokenNodes.count(from) == 0 && brokenNodes.count(to) == 0) {
1143 if (e.second->isBidiRail()) {
1146 EdgeVector inRailFrom, outRailFrom, inRailTo, outRailTo;
1151 bool haveStraight =
false;
1152 bool haveStraightReverse =
false;
1153 if (!geometryLike || outRailFrom.size() + inRailFrom.size() == 2) {
1154 for (
const NBEdge* fromStraightCand : outRailFrom) {
1155 if (fromStraightCand != e.second &&
isStraight(from, fromStraightCand, e.second)) {
1156 haveStraightReverse =
true;
1161 if (haveStraightReverse) {
1162 for (
const NBEdge* fromStraightCand : inRailFrom) {
1163 if (fromStraightCand != e.second &&
isStraight(from, fromStraightCand, e.second)) {
1164 haveStraight =
true;
1171 if ((!haveStraightReverse || haveStraight) && (!geometryLike || outRailTo.size() + inRailTo.size() == 2)) {
1174 haveStraight =
false;
1175 haveStraightReverse =
false;
1176 for (
const NBEdge* toStraightCand : inRailTo) {
1177 if (toStraightCand != e.second &&
isStraight(to, toStraightCand, e.second)) {
1178 haveStraightReverse =
true;
1183 if (haveStraightReverse) {
1184 for (
const NBEdge* toStraightCand : outRailTo) {
1185 if (toStraightCand != e.second &&
isStraight(to, toStraightCand, e.second)) {
1186 haveStraight =
true;
1194 if (haveStraightReverse && !haveStraight) {
1197 if (e2 !=
nullptr) {
1206 WRITE_MESSAGEF(
TL(
"Added % bidi-edges to ensure connectivity of straight tracks at geometry-like nodes."),
toString(added));
1232 if (
isRailway(p) && (p & vClasses) != 0) {
1233 if (edge->getRoutingType() ==
"") {
1234 edge->setPriority(-1);
1240 for (
const auto& item : lc.
getLines()) {
1241 if ((item.second->getVClass() & vClasses) == 0) {
1244 for (
NBEdge* edge : item.second->getEdges()) {
1245 if (edge->getRoutingType() ==
"") {
1246 edge->setPriority(4);
1247 edge->setRoutingType(
"4");
1271 std::set<NBEdge*, ComparatorIdLess> bidi;
1276 if (!edge->isBidiRail()) {
1277 edge->setPriority(4);
1278 edge->setRoutingType(
"4");
1284 if (edge->getPriority() >= 0) {
1293 if (uni.size() == 0) {
1294 if (bidi.size() != 0) {
1295 WRITE_WARNING(
TL(
"Cannot extend track direction priority because there are no track edges with positive priority"));
1302 while (!check.empty()) {
1303 NBEdge* edge = *check.begin();
1305 if (seen.count(edge) != 0) {
1312 check.insert(straightOut);
1317 check.insert(straightIn);
1319#ifdef DEBUG_DIRECTION_PRIORITY
1327 for (
NBEdge* edge : bidi) {
1328 NBEdge* bidiEdge =
const_cast<NBEdge*
>(edge->getBidiEdge());
1331 if (
forward.count(edge) != 0) {
1332 if (
forward.count(bidiEdge) == 0) {
1341 if (
forward.count(bidiEdge) != 0) {
1350 if (bidiEdge ==
nullptr) {
1351 WRITE_WARNINGF(
TL(
"Edge '%' was loaded with undefined priority (%) but has unambiguous main direction (no bidi edge)"), edge->getID(), edge->getPriority());
1353 if (edge->getPriority() >= 0) {
1356 if (bidiEdge !=
nullptr && bidiEdge->
getPriority() >= 0) {
1359 if (edge->getPriority() < 0) {
1360 edge->setPriority(prio);
1361 edge->setRoutingType(
toString(prio));
1363 if (bidiEdge !=
nullptr && bidiEdge->
getPriority() < 0) {
1368 std::map<int, int> numPrios;
1369 for (
NBEdge* edge : bidi) {
1370 numPrios[edge->getPriority()]++;
1386 int addedSignals = 0;
1387 if (oc.
exists(
"railway.signal.guess.by-stops")) {
1388 if (oc.
getBool(
"railway.signal.guess.by-stops")) {
1390 const double minLength = oc.
getFloat(
"osm.stop-output.length.train");
1391 const bool split = oc.
getBool(
"railway.signal.guess.by-stops.split");
1396 addedSignals += guessByStops(nc, ec, sc, dc, minLength,
split);
1399 return addedSignals;
1406 &&
node->getIncomingEdges().size() >= 1
1407 &&
node->getOutgoingEdges().size() >= 1
1408 && (
node->getEdges().size() > 2
1409 ||
node->getIncomingEdges().front()->getFromNode() !=
node->getOutgoingEdges().front()->getToNode()));
1415 const double splitOffset = 10;
1416 const double splitOffsetSlack = 200;
1417 int addedSignals = 0;
1418 for (
const auto& item : sc.
getStops()) {
1422 if (canBeSignal(to)) {
1423 const double stopEnd = item.second->getEndPos();
1430 const std::string stopEdgeID = stopEdge->
getID();
1433 if (bidi !=
nullptr) {
1438 item.second->findLaneAndComputeBusStopExtent(stopEdge);
1439 stopEdge = ec.
retrieve(stopEdgeID);
1453 if (in->getFromNode() != curr->
getToNode()) {
1467 if (canBeSignal(from)) {
1468 const double minPos =
MIN2(splitOffset, curr->
getLength() / 2);
1469 const double splitPos = searchDist >= 0
1471 :
MAX2(minPos,
MIN2(item.second->getStartPos(), -searchDist - 10));
1477 const std::string currID = curr->
getID();
1480 if (bidi !=
nullptr) {
1485 item.second->findLaneAndComputeBusStopExtent(stopEdge);
1498 return addedSignals;
1505 int numCorridors = 0;
1507 std::set<NBNode*> railGeomNodes;
1508 for (
NBNode* n : railNodes) {
1509 if (n->geometryLike()) {
1510 railGeomNodes.insert(n);
1513 std::set<NBNode*, ComparatorIdLess> kinkNodes;;
1514 for (
NBNode* n : railGeomNodes) {
1516 NBEdge* out = n->getOutgoingEdges().size() == 1 || n->getOutgoingEdges()[1]->
isTurningDirectionAt(in) ? n->getOutgoingEdges().front() : n->getOutgoingEdges().back();
1518 if (maxAngle > 0 && relAngle > maxAngle) {
1519 kinkNodes.insert(n);
1522 while (!kinkNodes.empty()) {
1523 std::vector<NBNode*> corridor;
1524 std::vector<NBEdge*> corridorEdges;
1527 NBNode* n = *kinkNodes.begin();
1528 kinkNodes.erase(kinkNodes.begin());
1533 NBEdge*
const centerIn = in;
1534 NBEdge*
const centerOut = out;
1537 corridor.push_back(up);
1538 corridor.push_back(n);
1539 corridor.push_back(down);
1542 corridorEdges.push_back(in);
1543 corridorEdges.push_back(out);
1547 while (kinkNodes.count(up) != 0) {
1552 corridor.insert(corridor.begin(), up);
1553 corridorEdges.insert(corridorEdges.begin(), in2);
1554 kinkNodes.erase(up);
1559 delta = cEnd - cBeg;
1560 while (delta.
length2D() <= POSITION_EPS * (
double)corridor.size() && railGeomNodes.count(up) != 0) {
1565 corridor.insert(corridor.begin(), up);
1566 corridorEdges.insert(corridorEdges.begin(), in2);
1567 kinkNodes.erase(up);
1571 delta = cEnd - cBeg;
1575 while (kinkNodes.count(down) != 0) {
1580 corridor.push_back(down);
1581 corridorEdges.push_back(out2);
1582 kinkNodes.erase(down);
1587 delta = cEnd - cBeg;
1588 while (delta.
length2D() <= POSITION_EPS * (
double)corridor.size() && railGeomNodes.count(down) != 0) {
1593 corridor.push_back(down);
1594 corridorEdges.push_back(out2);
1595 kinkNodes.erase(down);
1599 delta = cEnd - cBeg;
1602 std::set<NBNode*> corridorNodes(corridor.begin(), corridor.end());
1603 for (
NBNode* n2 : corridorNodes) {
1604 for (
NBEdge* e : n2->getEdges()) {
1605 if (corridorNodes.count(e->getFromNode()) != 0
1606 && corridorNodes.count(e->getToNode()) != 0) {
1608 simpleGeom.push_back(e->getFromNode()->getPosition());
1609 simpleGeom.push_back(e->getToNode()->getPosition());
1610 e->setGeometry(simpleGeom);
1615 double currLength = 0;
1616 for (
int i = 1; i < (int)corridor.size() - 1; i++) {
1617 currLength += corridorEdges[i - 1]->getLoadedLength();
1618 const Position newPos = cBeg + delta * (currLength / length);
1619 NBNode*
const n2 = corridor[i];
1620 n2->
reinit(newPos, n2->getType());
1621 for (
NBEdge* e : n2->getEdges()) {
1622 e->resetEndpointAtNode(n2);
1633 WRITE_MESSAGEF(
TL(
"Moved % rail junctions for straightening % corridors."), moved, numCorridors);
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
#define WRITE_WARNINGF(...)
#define WRITE_MESSAGEF(...)
#define WRITE_MESSAGE(msg)
#define WRITE_WARNING(msg)
#define SHARP_THRESHOLD_SAMEDIR
std::set< NBEdge * > EdgeSet
container for unique edges
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
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
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SUMO_TAG_NODE
alternative definition for junction
bool gDebugFlag1
global utility flags for debugging
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A class that stores a 2D geometrical boundary.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Computes the shortest path through a network using the Dijkstra algorithm.
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
A container for districts.
Storage for edges, including some functionality operating on multiple edges.
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
EdgeVector getAllEdges() const
return all edges
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
std::string createUnusedID(const std::string &base, const std::string &sep)
if base is an existing edge id, find a unused id of the form base + sep + INT
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
bool wasIgnored(std::string id) const
Returns whether the edge with the id was ignored during parsing.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
The representation of a single edge during network building.
double getLength() const
Returns the computed length of the edge.
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
void reinitNodes(NBNode *from, NBNode *to)
Resets nodes but keeps all other values the same (used when joining)
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.
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
NBEdge * getStraightContinuation(SVCPermissions permissions) const
return the straightest follower edge for the given permissions or nullptr (never returns turn-arounds...
int getNumericalID() const
Returns the index (numeric id) of the edge.
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
static double getTravelTimeStatic(const NBEdge *const edge, const NBVehicle *const, double)
NBEdge * getStraightPredecessor(SVCPermissions permissions) const
return the straightest predecessor edge for the given permissions or nullptr (never returns turn-arou...
const std::string & getID() const
double getDistance() const
get distance
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
int getNumLanes() const
Returns the number of lanes.
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
const NBEdge * getBidiEdge() const
NBNode * getFromNode() const
Returns the origin node of the edge.
NBEdge * getTurnDestination(bool possibleDestination=false) const
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
void setPriority(int priority)
Sets the priority of the edge.
int getPriority() const
Returns the priority of the edge.
void setRoutingType(const std::string &routingType)
set the routingType for this edge
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
static void loadEdgesFromFile(const std::string &file, std::set< std::string > &into)
Add edge ids defined in file (either ID or edge:ID per line) into the given set.
Container for nodes during the netbuilding process.
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
std::string createUnusedID(const std::string &base, const std::string &sep)
if base is an existing node id, find a unused id of the form base + sep + INT
Represents a single node (junction) during network building.
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
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)
const Position & getPosition() const
bool geometryLike() const
whether this is structurally similar to a geometry node
const std::map< std::string, NBPTLine * > & getLines() const
bool isConsistent(std::vector< NBEdge * > stops) const
return whether the mentioned edges appear in that order in the route
std::vector< PTStopInfo > getStopEdges(const NBEdgeCont &ec) const
const std::string & getRef() const
get line reference (not unique)
NBEdge * getRouteEnd(const NBEdgeCont &ec) const
return last valid edge of myRoute (if it doest not lie before the last stop)
NBEdge * getRouteStart(const NBEdgeCont &ec) const
return first valid edge of myRoute (if it doest not lie after the first stop)
Container for public transport stops during the net building process.
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
std::shared_ptr< NBPTStop > get(std::string id) const
Retrieve a previously inserted pt stop.
std::shared_ptr< NBPTStop > getReverseStop(std::shared_ptr< NBPTStop > pStop, const NBEdgeCont &ec)
bool insert(std::shared_ptr< NBPTStop > ptStop, bool floating=false)
Inserts a node into the map.
static int straigthenCorrdidor(NBEdgeCont &ec, double maxAngle)
static bool canBeSignal(const NBNode *node)
static int guessByStops(NBNodeCont &nc, NBEdgeCont &ec, NBPTStopCont &sc, NBDistrictCont &dc, double minLength, bool split)
static int guessRailSignals(NBNodeCont &nc, NBEdgeCont &ec, NBPTStopCont &sc, NBDistrictCont &dc)
SVCPermissions minPermissions
const std::vector< std::pair< const Track *, const Track * > > & getViaSuccessors(SUMOVehicleClass svc=SVC_IGNORING, bool ignoreTransientPermissions=false) const
const std::vector< Track * > & getSuccessors(SUMOVehicleClass svc=SVC_IGNORING) const
std::vector< Track * > successors
void addSuccessor(Track *track)
std::vector< std::pair< const Track *, const Track * > > viaSuccessors
static NBEdge * isBidiSwitch(const NBNode *n)
static int repairTopology(NBEdgeCont &ec, NBPTStopCont &sc, NBPTLineCont &lc)
static void getRailEdges(const NBNode *node, EdgeVector &inEdges, EdgeVector &outEdges)
filter out rail edges among all edges of a the given node
static void extendDirectionPriority(NBEdgeCont &ec, bool fromUniDir)
static std::set< NBNode * > getRailNodes(NBEdgeCont &ec, bool verbose=false)
static void updateTurns(NBEdge *edge)
recompute turning directions for both nodes of the given edge
static bool isStraight(const NBNode *node, const NBEdge *e1, const NBEdge *e2)
static int reverseEdges(NBEdgeCont &ec, NBPTStopCont &sc, NBPTLineCont &lc)
reverse edges sequences that are to broken nodes on both sides
static void analyzeTopology(NBEdgeCont &ec)
static void setPTLinePriority(NBEdgeCont &ec, NBPTLineCont &lc, SVCPermissions vClasses)
static int addBidiEdgesForStops(NBEdgeCont &ec, NBPTLineCont &lc, NBPTStopCont &sc, bool minimal)
add bidi-edges to connect successive public transport stops
static std::set< NBPTLine * > findBidiCandidates(NBPTLineCont &lc)
identify lines that are likely to require bidirectional tracks
static void reverseEdge(NBEdge *e)
reverse a single edge
static int addBidiEdgesForStraightConnectivity(NBEdgeCont &ec, bool geometryLike)
add bidi-edges to connect straight tracks
static bool allSharp(const NBNode *node, const EdgeVector &in, const EdgeVector &out, bool countBidiAsSharp=false)
static bool allBroken(const NBNode *node, NBEdge *candOut, const EdgeVector &in, const EdgeVector &out)
static std::set< NBNode * > getBrokenRailNodes(NBEdgeCont &ec, bool verbose=false)
static int addBidiEdgesBetweenSwitches(NBEdgeCont &ec)
add bidi-edges to connect switches that are approached in both directions
static bool allBidi(const EdgeVector &edges)
static int makeAllBidi(NBEdgeCont &ec)
static double getTravelTimeStatic(const Track *const track, const NBVehicle *const veh, double time)
static bool hasRailway(SVCPermissions permissions)
filter for rail edges but do not return (legacy) all purpose edges
static bool hasStraightPair(const NBNode *node, const EdgeVector &edges, const EdgeVector &edges2)
static int addBidiEdgesForBufferStops(NBEdgeCont &ec)
add bidi-edges to connect buffers stops in both directions
static NBEdge * addBidiEdge(NBEdgeCont &ec, NBEdge *edge, bool update=true)
add bidi-edge for the given edge
static int extendBidiEdges(NBEdgeCont &ec)
add further bidi-edges near existing bidi-edges
static const std::string OSM_DIRECTION
processing parameter for rail signal edges and nodes
static void computeTurnDirections(NBNodeCont &nc, bool warn=true)
Computes turnaround destinations for all edges (if exist)
static void computeTurnDirectionsForNode(NBNode *node, bool warn)
Computes turnaround destinations for all incoming edges of the given nodes (if any)
A vehicle as used by router.
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
const std::string & getID() const
Returns the id.
A storage for options typed value containers)
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
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.
Static storage of an output device and its base (abstract) implementation.
void close()
Closes the device and removes it from the dictionary.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false, const bool escape=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static OutputDevice & getDevice(const std::string &name, bool usePrefix=true)
Returns the described OutputDevice.
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >(), bool includeConfig=true)
Writes an XML header with optional configuration.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
A point in 2D or 3D with translation and scaling methods.
double length2D() const
Computes the length of the given vector neglecting the z coordinate.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
PositionVector reverse() const
reverse position vector
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool isInt(const std::string &sData)
check if the given sData can be converted to int
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
get stop edges and stop ids and directional validity