61#define MAX_SLIPLANE_LENGTH 1000
71#define DEBUGNODEID2 ""
73#define DEBUGCOND(obj) ((obj) != 0 && ((obj)->getID() == DEBUGNODEID || (obj)->getID() == DEBUGNODEID2))
89 NodeCont::iterator i =
myNodes.find(
id);
95 const float pos[2] = {(float)position.
x(), (float)position.
y()};
103 std::string
id = node->
getID();
104 NodeCont::iterator i =
myNodes.find(
id);
117 NodeCont::const_iterator i =
myNodes.find(
id);
127 const double extOffset = offset + POSITION_EPS;
128 const float cmin[2] = {(float)(position.
x() - extOffset), (
float)(position.
y() - extOffset)};
129 const float cmax[2] = {(float)(position.
x() + extOffset), (
float)(position.
y() + extOffset)};
130 std::set<const Named*> into;
133 for (
const Named* namedNode : into) {
177 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
178 no += (*i).second->removeSelfLoops(dc, ec, tc);
189 const double distanceThreshold = 7.;
190 const double lengthThreshold = 0.10;
192 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
194 std::map<NBNode*, EdgeVector> connectionCount;
195 const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
196 for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) {
197 connectionCount[(*j)->getToNode()].push_back(*j);
200 std::map<NBNode*, EdgeVector>::iterator k;
201 for (k = connectionCount.begin(); k != connectionCount.end(); k++) {
203 if ((*k).second.size() < 2) {
209 const NBEdge*
const first = ev.front();
210 EdgeVector::const_iterator jci;
211 for (jci = ev.begin() + 1; jci != ev.end(); ++jci) {
214 (relativeLengthDifference > lengthThreshold) ||
215 (fabs(first->
getSpeed() - (*jci)->getSpeed()) >= 0.01) ||
223 if (jci == ev.end()) {
224 if (removeDuplicates) {
225 for (
int ei = 1; ei < (int)ev.size(); ei++) {
240 const std::vector<std::string>& edgeNames = ec.
getAllNames();
241 for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
250 if (outgoingEdges.size() != 1) {
255 if (incomingEdges.size() > 1) {
258 }
else if (incomingEdges.size() == 1) {
259 NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
260 NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
261 if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
269 bool hasJunction =
false;
281 adjacentNodes.clear();
282 for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
283 if ((*itOfOutgoings)->getToNode() != from
284 && (*itOfOutgoings)->getToNode() != to
288 adjacentNodes.insert((*itOfOutgoings)->getToNode());
290 for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) {
291 adjacentNodes.insert((*itOfIncomings)->getFromNode());
293 adjacentNodes.erase(to);
294 if (adjacentNodes.size() > 2) {
297 }
while (!hasJunction && eOld != e);
299 std::string warningString;
300 for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
301 if (roadIt == road.begin()) {
302 warningString += (*roadIt)->
getID();
304 warningString +=
"," + (*roadIt)->getID();
307 NBNode* fromNode = (*roadIt)->getFromNode();
308 NBNode* toNode = (*roadIt)->getToNode();
309 ec.
erase(dc, *roadIt);
328 std::vector<std::set<NBEdge*> > components;
330 std::set<std::string> edgesLeft;
331 for (std::map<std::string, NBEdge*>::const_iterator edgeIt = ec.
begin(); edgeIt != ec.
end(); ++edgeIt) {
332 edgesLeft.insert(edgeIt->first);
335 std::set<NBEdge*> toRemove;
336 int foundComponents = 0;
338 while (!edgesLeft.empty()) {
339 queue.push_back(ec.
getByID(*edgesLeft.begin()));
340 std::set<NBEdge*> component;
341 while (!queue.empty()) {
342 NBEdge*
const e = queue.back();
345 std::vector<EdgeVector> edgeLists;
350 for (std::vector<EdgeVector>::const_iterator listIt = edgeLists.begin(); listIt != edgeLists.end(); ++listIt) {
351 for (EdgeVector::const_iterator edgeIt = listIt->begin(); edgeIt != listIt->end(); ++edgeIt) {
352 std::set<std::string>::iterator leftIt = edgesLeft.find((*edgeIt)->getID());
353 if (leftIt != edgesLeft.end()) {
354 queue.push_back(*edgeIt);
355 edgesLeft.erase(leftIt);
361 std::vector<std::set<NBEdge*> >::iterator cIt;
362 for (cIt = components.begin(); cIt != components.end(); ++cIt) {
363 if (cIt->size() < component.size()) {
367 components.insert(cIt, component);
368 if ((
int)components.size() > numKeep) {
369 bool recheck =
false;
371 for (
NBEdge* e : components.back()) {
381 toRemove.insert(components.back().begin(), components.back().end());
384 std::vector<std::string> edgeIDs;
385 for (
NBEdge* e : components.back()) {
386 edgeIDs.push_back(e->getID());
390 components.pop_back();
394 for (
NBEdge* e : toRemove) {
395 NBNode*
const fromNode = e->getFromNode();
396 NBNode*
const toNode = e->getToNode();
405 if (foundComponents > 1) {
413 std::set<std::string> stopEdges;
414 for (
const auto& item : sc.
getStops()) {
415 stopEdges.insert(item.second->getEdgeId());
418 int numRemovedEdges = 0;
421 for (std::string edgeID : component) {
422 if (stopEdges.count(edgeID) != 0) {
429 numRemovedEdges += (int)component.size();
430 for (std::string edgeID : component) {
446 if (numRemoved > 0) {
457 bool removeGeometryNodes) {
459 std::set<std::string> edges2keep;
460 if (removeGeometryNodes) {
462 if (oc.
isSet(
"geometry.remove.keep-edges.input-file")) {
465 if (oc.
isSet(
"geometry.remove.keep-edges.explicit")) {
466 const std::vector<std::string> edges = oc.
getStringVector(
"geometry.remove.keep-edges.explicit");
467 edges2keep.insert(edges.begin(), edges.end());
472 if (oc.
exists(
"geometry.remove.keep-ptstops") && oc.
getBool(
"geometry.remove.keep-ptstops")) {
477 std::map<NBEdge*, std::set<NBTrafficLightDefinition*> > tlsLookup;
478 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
486 std::vector<NBNode*> toRemove;
487 for (
const auto& i :
myNodes) {
488 NBNode*
const current = i.second;
495 if (edges2keep.find(it_edge->getID()) != edges2keep.end()) {
505 for (
const std::pair<NBEdge*, NBEdge*>& j : current->
getEdgesToJoin()) {
507 NBEdge*
const continuation = j.second;
508 begin->append(continuation);
510 auto itTL = tlsLookup.find(continuation);
511 if (itTL != tlsLookup.end()) {
515 tlsLookup[
begin] = itTL->second;
519 ec.
extract(dc, continuation,
true);
521 toRemove.push_back(current);
524 for (
NBNode* n : toRemove) {
527 return (
int)toRemove.size();
533 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
534 (*i).second->avoidOverlap();
542 std::set<NBNode*> visited;
543 for (
const auto& i :
myNodes) {
544 if (visited.count(i.second) > 0) {
547 std::vector<NodeAndDist> toProc;
548 toProc.emplace_back(i.second, 0.);
550 while (!toProc.empty()) {
551 NBNode*
const n = toProc.back().first;
552 const double dist = toProc.back().second;
554 if (visited.count(n) > 0) {
558 bool pureRail =
true;
559 bool railAndPeds =
true;
577 const double length = e->getLoadedLength();
578#ifdef DEBUG_JOINJUNCTIONS
580 std::cout <<
"generateNodeClusters: consider s=" << s->
getID()
581 <<
" clusterNode=" << n->
getID() <<
" edge=" << e->getID() <<
" length=" << length <<
" with cluster " <<
joinNamedToString(c,
' ') <<
"\n";
585 bool railAndPeds2 =
true;
588 railAndPeds2 =
false;
599 const bool joinPedCrossings = bothCrossing && e->getPermissions() ==
SVC_PEDESTRIAN;
601 !joinPedCrossings && (
604 || (length > 3 * POSITION_EPS
607#ifdef DEBUG_JOINJUNCTIONS
618 bool foundRail =
false;
621 if ((e2->getPermissions() & railNoTram) != 0) {
634 if (visited.find(s) != visited.end()) {
637 if (length + dist < maxDist) {
639 toProc.emplace_back(s, dist + length);
641 toProc.emplace_back(s, 0.);
649#ifdef DEBUG_JOINJUNCTIONS
659 for (
const std::string& nodeID : ids) {
663 WRITE_WARNINGF(
TL(
"Ignoring join exclusion for junction '%' since it already occurred in a list of nodes to be joined."), nodeID);
675 maxIds = (int)cluster.size();
677 if ((
int)cluster.size() > maxIds) {
678 auto clusterIt = cluster.begin();
679 std::string result = prefix + *clusterIt;
680 for (
int i = 1; i < maxIds; i++) {
682 result +=
"_" + *clusterIt;
684 return result +
"_#" +
toString((
int)cluster.size() - maxIds) +
"more";
693 std::set<std::string> validCluster;
694 for (std::string nodeID : cluster) {
696 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' was already excluded from joining."), nodeID);
698 }
else if (
myJoined.count(nodeID) > 0) {
699 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' already occurred in another join-cluster."), nodeID);
703 validCluster.insert(nodeID);
705 WRITE_ERRORF(
TL(
"Unknown junction '%' in join-cluster."), nodeID);
709 if (validCluster.size() > 1) {
710 myJoined.insert(validCluster.begin(), validCluster.end());
713 WRITE_WARNINGF(
TL(
"Ignoring join-cluster '%' because it has size '%'."), node->
getID(), validCluster.size());
724 for (std::string nodeID : item.first) {
726 if (node ==
nullptr) {
729 cluster.insert(node);
732 if (cluster.size() > 1) {
745#ifdef DEBUG_JOINJUNCTIONS
746 std::cout <<
"joinJunctions...\n";
750 std::map<const NBNode*, std::vector<NBNode*> > ptStopEnds;
752 for (
const auto& stopIt : sc.
getStops()) {
754 if (edge !=
nullptr) {
759 for (
NodeSet& cluster : cands) {
760#ifdef DEBUG_JOINJUNCTIONS
762 for (
NBNode* n : cluster) {
769 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
770 NodeSet::iterator check = j;
773 cluster.erase(check);
779 if (cluster.size() < 2) {
784 if (cluster.size() < 2) {
785 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
789 std::string origReason;
791 bool feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, origReason);
792 if (feasible && ((
int)cluster.size() -
pruneLongEdges(cluster, maxDist,
true) < 2)) {
793 origReason =
"long edge";
797#ifdef DEBUG_JOINJUNCTIONS
799 std::cout <<
" try to reduce to 4-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
805 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
810#ifdef DEBUG_JOINJUNCTIONS
812 std::cout <<
" try to reduce to 2-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
819 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
825 if (cluster.size() < 2) {
826 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
832 if (cluster.size() < 2) {
833 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
837 if (cluster.size() < 2) {
838 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
845 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster, origReason);
851 for (
NBNode* current : cluster) {
855 newComp.insert(current);
856 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
857 NodeClusters::iterator check = it_comp;
859 bool connected =
false;
860 for (
NBNode* k : *check) {
861 if (current->getConnectionTo(k) !=
nullptr || k->getConnectionTo(current) !=
nullptr) {
863 newComp.insert((*check).begin(), (*check).end());
864 it_comp = components.erase(check);
874 components.push_back(newComp);
876 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
877 if ((*it_comp).size() > 1) {
879 clusters.push_back(*it_comp);
882#ifdef DEBUG_JOINJUNCTIONS
887 return (
int)clusters.size();
893#ifdef DEBUG_JOINJUNCTIONS
894 std::cout <<
"joinSameJunctions...\n";
896 std::map<std::string, NodeSet> positions;
898 Position pos = item.second->getPosition();
902 positions[rounded].insert(item.second);
905 for (
auto& item : positions) {
906 if (item.second.size() > 1) {
907 for (
NBNode* n : item.second) {
909 item.second.erase(n);
912 if (item.second.size() > 1) {
913 clusters.push_back(item.second);
918 return (
int)clusters.size();
923#ifdef DEBUG_JOINJUNCTIONS
929 bool pruneFringe =
true;
932 while (pruneFringe) {
934 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
935 NodeSet::iterator check = j;
940 double clusterDist = std::numeric_limits<double>::max();
941 bool touchingCluster =
false;
943 NBNode* neighbor = (*it_edge)->getToNode();
944 if (cluster.count(neighbor) != 0) {
945 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
950 NBNode* neighbor = (*it_edge)->getFromNode();
951 if (cluster.count(neighbor) != 0) {
952 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
958 std::set<NBNode*> outsideNeighbors;
959 std::set<NBNode*> clusterNeighbors;
960 const double pedestrianFringeThreshold = 0.3;
962 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
963 if (cluster.count(neighbor) == 0) {
966 || clusterDist <= pedestrianFringeThreshold
967 || touchingCluster) {
968 outsideNeighbors.insert(neighbor);
971 clusterNeighbors.insert(neighbor);
974#ifdef DEBUG_JOINJUNCTIONS
976 <<
" clusterDist=" << clusterDist
977 <<
" cd<th=" << (clusterDist <= pedestrianFringeThreshold)
978 <<
" touching=" << touchingCluster
983 if (clusterNeighbors.size() == 0
984 || (outsideNeighbors.size() <= 1
985 && clusterNeighbors.size() == 1
987 cluster.erase(check);
989#ifdef DEBUG_JOINJUNCTIONS
991 std::cout <<
" pruned n=" << n->
getID() <<
"\n";
1002 std::set<NBNode*> toRemove;
1003 int maxPassengerLanes = 0;
1004 for (
NBNode* n : cluster) {
1005 for (
NBEdge* edge : n->getEdges()) {
1006 maxPassengerLanes =
MAX2(maxPassengerLanes, edge->getNumLanesThatAllow(
SVC_PASSENGER));
1009 for (
NBNode* n : cluster) {
1010 for (
NBEdge* edge : n->getOutgoingEdges()) {
1014 std::vector<NBNode*> passed;
1017 NBNode* to = edge->getToNode();
1018 while (cluster.count(to) != 0) {
1020 bool goStraight = (std::find(passed.begin(), passed.end(), to) == passed.end()
1025 passed.push_back(to);
1028 if (cur !=
nullptr) {
1039#ifdef DEBUG_JOINJUNCTIONS
1041 std::cout <<
"check edge length " << edge->getID() <<
" (" << length <<
", passed=" << passed.size() <<
", max=" << longThreshold <<
")\n";
1044 if (length > longThreshold) {
1048 const bool keepStart =
getClusterNeighbors(passed.back(), longThreshold, cluster).size() == 1;
1049 const bool keepEnd = !keepStart &&
getClusterNeighbors(n, longThreshold, cluster).size() == 1;
1050#ifdef DEBUG_JOINJUNCTIONS
1052 std::cout <<
"node=" << n->getID() <<
" long edge " << edge->getID() <<
" (" << length <<
", passed=" <<
toString(passed) <<
", max=" << longThreshold <<
") keepStart=" << keepStart <<
" keepEnd=" << keepEnd <<
"\n";
1058 toRemove.insert(passed.begin(), passed.end() - 1);
1060 toRemove.insert(passed.back());
1067 for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
1071 return (
int)toRemove.size();
1079 if (e->getLength() > longThreshold) {
1082 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1083 if (cluster.count(neighbor) != 0) {
1084 result.insert(neighbor);
1093#ifdef DEBUG_JOINJUNCTIONS
1095 std::cout <<
"pruning slip-lanes at cluster=" <<
joinNamedToString(cluster,
' ') <<
"\n";
1099 if (cluster.size() <= 2) {
1103 for (
NBNode* n : cluster) {
1109#ifdef DEBUG_JOINJUNCTIONS
1111 std::cout <<
" candidate slip-lane start=" << n->getID() <<
" outgoing=" <<
toString(outgoing) <<
"\n";
1114 for (
NBEdge* contEdge : outgoing) {
1118 double slipLength = contEdge->getLength();
1119 NBNode* cont = contEdge->getToNode();
1123 if (cands.count(cont) != 0) {
1127#ifdef DEBUG_JOINJUNCTIONS
1129 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1136#ifdef DEBUG_JOINJUNCTIONS
1138 std::cout <<
" candidate slip-lane end=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1145 const NBEdge*
const otherEdge = (contEdge == outgoing.front() ? outgoing.back() : outgoing.front());
1148 std::vector<NodeAndDist> toProc;
1151 while (!toProc.empty()) {
1153 NBNode* cont2 = nodeAndDist.first;
1154 double dist = nodeAndDist.second;
1155#ifdef DEBUG_JOINJUNCTIONS
1157 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1161 if (visited.find(cont2) != visited.end()) {
1164 visited.insert(cont2);
1165 if (cont2 == cont) {
1170 const double dist2 = dist + e->getLength();
1171 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1172 toProc.push_back(std::make_pair(e->getToNode(), dist2));
1179 toRemove.insert(cands.begin(), cands.end());
1180#ifdef DEBUG_JOINJUNCTIONS
1182 std::cout <<
" found slip-lane with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1195#ifdef DEBUG_JOINJUNCTIONS
1197 std::cout <<
" candidate slip-lane end=" << n->getID() <<
" incoming=" <<
toString(incoming) <<
"\n";
1200 for (
NBEdge* contEdge : incoming) {
1204 double slipLength = contEdge->getLength();
1205 NBNode* cont = contEdge->getFromNode();
1209 if (cands.count(cont) != 0) {
1213#ifdef DEBUG_JOINJUNCTIONS
1215 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1222#ifdef DEBUG_JOINJUNCTIONS
1224 std::cout <<
" candidate slip-lane start=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1231 const NBEdge*
const otherEdge = (contEdge == incoming.front() ? incoming.back() : incoming.front());
1234 std::vector<NodeAndDist> toProc;
1237 while (!toProc.empty()) {
1239 NBNode* cont2 = nodeAndDist.first;
1240 double dist = nodeAndDist.second;
1241#ifdef DEBUG_JOINJUNCTIONS
1243 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1247 if (visited.find(cont2) != visited.end()) {
1250 visited.insert(cont2);
1251 if (cont2 == cont) {
1256 const double dist2 = dist + e->getLength();
1257 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1258 toProc.push_back(std::make_pair(e->getFromNode(), dist2));
1265 toRemove.insert(cands.begin(), cands.end());
1266#ifdef DEBUG_JOINJUNCTIONS
1268 std::cout <<
" found slip-lane start with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1280 for (
NBNode* n : toRemove) {
1281 numRemoved += (int)cluster.erase(n);
1283 if (numRemoved > 0) {
1284#ifdef DEBUG_JOINJUNCTIONS
1286 std::cout <<
" removed " << numRemoved <<
" nodes from cluster: " <<
joinNamedToString(toRemove,
' ') <<
"\n";
1304 if (inPE.size() == 1 && outPE.size() == 2) {
1305 outgoing.insert(outgoing.begin(), outPE.begin(), outPE.end());
1306 inAngle = inPE.front()->getAngleAtNode(n);
1308 }
else if (inPE.size() >= 2 && outPE.size() == 3) {
1311 const double inRelAngle = fabs(
NBHelpers::relAngle(inPE.front()->getAngleAtNode(n), inPE.back()->getAngleAtNode(n)));
1313 if (inRelAngle < 135) {
1316 for (
NBEdge* in : inPE) {
1319 for (
NBEdge* out : outPE) {
1320 const double outRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1321 if (outRelAngle <= 45) {
1322 straight.push_back(out);
1323 }
else if (outRelAngle >= 135) {
1327 if (straight.size() == 2 && numReverse == 1) {
1328 outgoing.insert(outgoing.begin(), straight.begin(), straight.end());
1329 inAngle = in->getAngleAtNode(n);
1342 if (inPE.size() == 2 && outPE.size() == 1) {
1343 incoming.insert(incoming.begin(), inPE.begin(), inPE.end());
1344 outAngle = outPE.front()->getAngleAtNode(n);
1346 }
else if (inPE.size() == 3 && outPE.size() >= 2) {
1349 const double outRelAngle = fabs(
NBHelpers::relAngle(outPE.front()->getAngleAtNode(n), outPE.back()->getAngleAtNode(n)));
1351 if (outRelAngle < 135) {
1354 for (
NBEdge* out : outPE) {
1357 for (
NBEdge* in : inPE) {
1358 const double inRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1359 if (inRelAngle <= 45) {
1360 straight.push_back(in);
1361 }
else if (inRelAngle >= 135) {
1365 if (straight.size() == 2 && numReverse == 1) {
1366 incoming.insert(incoming.begin(), straight.begin(), straight.end());
1367 outAngle = out->getAngleAtNode(n);
1377 double maxDist, std::string& reason)
const {
1380 std::map<NBEdge*, double, ComparatorIdLess> finalIncomingAngles;
1381 std::map<NBEdge*, double, ComparatorIdLess> finalOutgoingAngles;
1382 for (
NBNode* n : cluster) {
1383 for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
1390 for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
1399#ifdef DEBUG_JOINJUNCTIONS
1400 for (
NBNode* n : cluster) {
1409 if (finalIncomingAngles.size() > 5) {
1410 reason =
toString(finalIncomingAngles.size()) +
" incoming edges";
1414 const double PARALLEL_THRESHOLD_SAME_NODE = 10;
1415 const double PARALLEL_THRESHOLD_DIFF_NODE = 30;
1416 bool foundParallel =
false;
1417 for (
auto j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
1419 for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
1420 const double angleDiff = fabs(j->second - k->second);
1421 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1423 const double edgeDist = j->first->getLaneShape(0).back().distanceTo2D(k->first->getLaneShape(0).back());
1424#ifdef DEBUG_JOINJUNCTIONS
1426 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1429 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1430 (j->first->getToNode() == k->first->getToNode()
1431 || (edgeDist < maxDist)))) {
1434 reason =
"parallel incoming " + j->first->getID() +
"," + k->first->getID();
1440 for (
auto j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
1442 for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
1443 const double angleDiff = fabs(j->second - k->second);
1444 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1446 const double edgeDist = j->first->getLaneShape(0).front().distanceTo2D(k->first->getLaneShape(0).front());
1447#ifdef DEBUG_JOINJUNCTIONS
1448 if (
DEBUGCOND(j->first->getFromNode())) {
1449 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1452 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1453 (j->first->getFromNode() == k->first->getFromNode()
1454 || (edgeDist < maxDist)))) {
1457 reason =
"parallel outgoing " + j->first->getID() +
"," + k->first->getID();
1463 bool hasTLS =
false;
1464 for (
NBNode* n : cluster) {
1465 if (n->isTLControlled()) {
1468 const auto& stopEnds = ptStopEnds.find(n);
1469 if (stopEnds != ptStopEnds.end()) {
1470 for (
NBNode*
const to : stopEnds->second) {
1471 if (cluster.count(to) != 0) {
1472 reason =
"it contains a pt stop edge";
1479 if (cluster.size() > 2) {
1481 double maxLength = -1;
1482 NBEdge* maxEdge =
nullptr;
1483 for (
NBNode* n1 : cluster) {
1484 for (
NBNode* n2 : cluster) {
1485 NBEdge* e1 = n1->getConnectionTo(n2);
1486 NBEdge* e2 = n2->getConnectionTo(n1);
1497#ifdef DEBUG_JOINJUNCTIONS
1498 for (
NBNode* n : cluster) {
1500 std::cout <<
"feasible hasTLS=" << hasTLS <<
" maxLength=" << maxLength <<
" maxEdge=" << maxEdge->
getID() <<
"\n";
1504 if (!hasTLS && maxLength > 5) {
1506 std::vector<NBNode*> toCheck;
1507 std::set<NBNode*> visited;
1508 toCheck.push_back(maxEdge->
getToNode());
1509 bool foundCircle =
false;
1510 while (!toCheck.empty()) {
1511 NBNode* n = toCheck.back();
1520 NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1521 if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
1522 toCheck.push_back(cand);
1528 reason =
"not compact (maxEdge=" + maxEdge->
getID() +
" length=" +
toString(maxLength) +
")";
1534 if (!hasTLS && cluster.size() >= 2) {
1537 int outsideIncoming = 0;
1538 int outsideOutgoing = 0;
1539 int edgesWithin = 0;
1540 for (
NBNode* n : cluster) {
1541 bool foundOutsideIncoming =
false;
1543 if (cluster.count(e->getFromNode()) == 0) {
1546 foundOutsideIncoming =
true;
1551 if (foundOutsideIncoming) {
1554 bool foundOutsideOutgoing =
false;
1555 for (
NBEdge* e : n->getOutgoingEdges()) {
1556 if (cluster.count(e->getToNode()) == 0) {
1559 foundOutsideOutgoing =
true;
1562 if (foundOutsideOutgoing) {
1566 if (entryNodes < 2) {
1567 reason =
"only 1 entry node";
1570 if (exitNodes < 2) {
1571 reason =
"only 1 exit node";
1574 if (cluster.size() == 2) {
1575 if (edgesWithin == 1 && outsideIncoming < 3 && outsideOutgoing < 3) {
1576 reason =
"only 1 edge within and no cross-traffic";
1588 assert(circleSize >= 2);
1589 if ((
int)cands.size() == circleSize) {
1590 if (cands.back()->getConnectionTo(cands.front()) !=
nullptr) {
1593 candCluster.insert(cands.begin(), cands.end());
1595 const bool feasible = (int)candCluster.size() == circleSize;
1598 cluster.insert(cands.begin(), cands.end());
1605 if ((
int)cluster.size() <= circleSize || startNodes.size() == 0) {
1610 if (cands.size() == 0) {
1625 singleStart.insert(cands.back());
1628 std::vector<NBNode*> cands2(cands);
1642 double minDist = std::numeric_limits<double>::max();
1643 NBEdge* result =
nullptr;
1644 for (
NBNode* n : startNodes) {
1645 for (
NBEdge* e : n->getOutgoingEdges()) {
1646 NBNode* neigh = e->getToNode();
1647 if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
1650 if (dist < minDist) {
1664 for (
NodeSet cluster : clusters) {
1673 assert(cluster.size() > 1);
1674 std::string
id =
"cluster_";
1680 std::set<NBEdge*, ComparatorIdLess> allEdges;
1681 for (
NBNode* n : cluster) {
1683 allEdges.insert(edges.begin(), edges.end());
1686 std::set<NBEdge*, ComparatorIdLess> clusterIncoming;
1687 std::set<NBEdge*, ComparatorIdLess> inside;
1688 for (
NBEdge* e : allEdges) {
1689 if (cluster.count(e->getToNode()) > 0) {
1690 if (cluster.count(e->getFromNode()) > 0) {
1697 clusterIncoming.insert(e);
1701#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1703 <<
" resetConnections=" << resetConnections <<
"\n"
1708 NBNode* newNode =
nullptr;
1709 if (predefined !=
nullptr) {
1710 newNode = predefined;
1719 std::string tlID = id;
1720 if (predefined !=
nullptr) {
1722 nodeType = predefined->
getType();
1735 newNode->
reinit(pos, nodeType);
1741 if (!tlc.
insert(tlDef)) {
1749 std::map<NBEdge*, EdgeSet> reachable;
1750 std::map<std::pair<NBEdge*, NBEdge*>,
SVCPermissions> conPermissions;
1752 for (
NBEdge*
const e : clusterIncoming) {
1756 while (open.size() > 0) {
1757 NBEdge*
const cur = open.back();
1759#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1760 if (e->getID() ==
"625058945") {
1767 if (cluster.count(cur->
getToNode()) == 0) {
1775 if (allEdges.count(out) != 0) {
1777 if (seen.count(out) == 0 || (~conPermissions[ {e, out}] & p) != 0) {
1779 open.push_back(out);
1780 conPermissions[ {e, out}] |= p;
1781#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1782 if (e->getID() ==
"625058945") {
1792 for (
const auto& con : cons) {
1793 if (con.toEdge !=
nullptr && allEdges.count(con.toEdge) != 0) {
1796 p &= con.permissions;
1798 if (seen.count(con.toEdge) == 0 || (~conPermissions[ {e, con.toEdge}] & p) != 0) {
1799 open.push_back(con.toEdge);
1800 conPermissions[ {e, con.toEdge}] |= p;
1808 for (
NBEdge* reached : seen) {
1810 if (inside.count(reached) == 0) {
1811 reachable[e].insert(reached);
1812 const SVCPermissions pDefault = e->getPermissions() & reached->getPermissions();
1813 if (conPermissions[ {e, reached}] != pDefault) {
1814 specialPermissions.insert(e);
1815#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1816 if (e->getID() ==
"625058945") {
1817 std::cout <<
"e=" << e->getID() <<
" out=" << reached->getID() <<
" special=" <<
getVehicleClassNames(conPermissions[ {e, reached}]) <<
"\n";
1823#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1824 std::cout <<
" reachable e=" << e->getID() <<
" seen=" <<
toString(seen) <<
" reachable=" <<
toString(reachable[e]) <<
"\n";
1832 for (
NBEdge* e : inside) {
1833 for (
NBEdge* e2 : allEdges) {
1835 e2->replaceInConnections(e, e->getConnections());
1843 for (
NBEdge* e : allEdges) {
1844 std::vector<NBEdge::Connection> conns = e->getConnections();
1845 const bool outgoing = cluster.count(e->getFromNode()) > 0;
1846 NBNode* from = outgoing ? newNode : e->getFromNode();
1847 NBNode* to = outgoing ? e->getToNode() : newNode;
1850 e->
setParameter(
"origFrom", e->getFromNode()->getID());
1852 e->setParameter(
"origTo", e->getToNode()->getID());
1855 if (e->getTurnSignTarget() !=
"") {
1856 for (
NBNode* n : cluster) {
1857 if (e->getTurnSignTarget() == n->getID()) {
1858 e->setTurnSignTarget(to->
getID());
1863 e->reinitNodes(from, to);
1866 for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1868 if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1871#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1872 std::cout <<
" e=" << e->getID() <<
" declareConnectionsAsLoaded\n";
1877 if (!resetConnections) {
1882 if (reachable[in].count(out) == 0) {
1885 in->removeFromConnections(out, -1, -1,
true,
false,
true);
1889 }
else if (specialPermissions.count(in) != 0) {
1890 SVCPermissions pDefault = in->getPermissions() & out->getPermissions();
1891 SVCPermissions p = conPermissions[ {in, out}] == 0 ? pDefault : conPermissions[ {in, out}];
1892 in->addEdge2EdgeConnection(out,
true, p == pDefault ?
SVC_UNSPECIFIED : p);
1899 in->invalidateConnections(
true);
1905 for (
NBNode* n : cluster) {
1913 std::set<std::string> ids;
1914 for (
NBNode* n : cluster) {
1915 ids.insert(n->getID());
1925 bool ambiguousType =
false;
1926 for (
NBNode* j : cluster) {
1927 pos.
add(j->getPosition());
1929 if (j->isTLControlled()) {
1932 type = (*j->getControllingTLS().begin())->getType();
1933 }
else if (type != (*j->getControllingTLS().begin())->getType()) {
1934 ambiguousType =
true;
1940 nodeType = otherType;
1941 }
else if (nodeType != otherType) {
1953 pos.
mul(1. / (
double)cluster.size());
1954 if (ambiguousType) {
1964 bool tooFast =
false;
1965 double laneSpeedSum = 0;
1966 std::set<NBEdge*> seen;
1968 for (
const NBEdge* e : j->getEdges()) {
1969 if (c.find(e->getFromNode()) != c.end() && c.find(e->getToNode()) != c.end()) {
1973 if (j->hasIncoming(e)) {
1974 if (recheck && !j->hasConflict(e)) {
1979 laneSpeedSum += (double)e->getNumLanes() * e->getLaneSpeed(0);
1981 if (e->getLaneSpeed(0) * 3.6 > 79) {
1987 return !tooFast && laneSpeedSum >= laneSpeedThreshold && c.size() != 0;
1999 nonPedIncoming.push_back(e);
2002 for (
NBEdge* e : node->getOutgoingEdges()) {
2004 nonPedOutgoing.push_back(e);
2007 if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
2023 if (node->isTLControlled()) {
2029 const std::string tlID = tl->
getID();
2030 if (tlID != node->getID()
2046 const double laneSpeedThreshold = oc.
getFloat(
"tls.guess.threshold");
2047 if (oc.
isSet(
"tls.unset")) {
2048 std::vector<std::string> notTLControlledNodes = oc.
getStringVector(
"tls.unset");
2049 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
2052 throw ProcessError(
TLF(
" The junction '%' to set as not-controlled is not known.", *i));
2055 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
2056 (*j)->removeNode(n);
2066 if (oc.
exists(
"tls.taz-nodes") && oc.
getBool(
"tls.taz-nodes")) {
2067 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2068 NBNode* cur = (*i).second;
2077 if (oc.
exists(
"tls.guess-signals") && oc.
getBool(
"tls.guess-signals")) {
2079 const double signalDist = oc.
getFloat(
"tls.guess-signals.dist");
2080 for (
const auto& item :
myNodes) {
2081 const NBNode* node = item.second;
2083#ifdef DEBUG_GUESSSIGNALS
2085 std::cout <<
" propagate TLS from " << node->
getID() <<
" downstream\n";
2091 edge->setSignalPosition(node->
getPosition(), node);
2096 std::set<NBEdge*> seen;
2097 std::set<NBEdge*> check;
2098 for (
const auto& item :
myNodes) {
2099 for (
NBEdge* edge : item.second->getOutgoingEdges()) {
2103#ifdef DEBUG_GUESSSIGNALS
2104 if (
DEBUGCOND(edge->getSignalNode()) ||
true) {
2105 std::cout <<
" primary signalPosition edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2112 while (check.size() > 0) {
2113 NBEdge*
const edge = *check.begin();
2114 check.erase(check.begin());
2119 if (seen.count(outEdge) == 0) {
2121#ifdef DEBUG_GUESSSIGNALS
2123 std::cout <<
" setSignalPosition edge=" << outEdge->
getID() <<
" pos=" << edge->
getSignalPosition() <<
"\n";
2126 check.insert(outEdge);
2133 const int slack = oc.
getInt(
"tls.guess-signals.slack");
2134 for (std::map<std::string, NBNode*>::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2135 NBNode* node = i->second;
2144 std::vector<const NBNode*> signals;
2145 int foundSignals = 0;
2146 int missingSignals = 0;
2148 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2149 const NBEdge* inEdge = *it_i;
2152#ifdef DEBUG_GUESSSIGNALS
2154 std::cout <<
" noTLS, edge=" << inEdge->
getID() <<
"\n";
2158 if (missingSignals > slack) {
2167 int foundSignalsAtDist = 0;
2168 if (foundSignals > 1 && missingSignals <= slack && missingSignals < foundSignals) {
2172 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2173 const NBEdge* inEdge = *it_i;
2176#ifdef DEBUG_GUESSSIGNALS
2182 if (missingSignals > slack) {
2187 foundSignalsAtDist++;
2190 if (signal !=
nullptr) {
2191 signals.push_back(signal);
2196 for (
const NBEdge* outEdge : outgoing) {
2197 NBNode* cand = outEdge->getToNode();
2199#ifdef DEBUG_GUESSSIGNALS
2201 std::cout <<
" node=" << node->
getID() <<
" outEdge=" << outEdge->getID() <<
" signalNode=" << cand->
getID() <<
" len=" << outEdge->getLength() <<
"\n";
2204 signals.push_back(cand);
2208 if (foundSignalsAtDist > 1 && missingSignals <= slack && missingSignals < foundSignalsAtDist) {
2209 for (
const NBNode* s : signals) {
2210 std::set<NBTrafficLightDefinition*> tls = s->getControllingTLS();
2212 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
2219 if (!tlc.
insert(tlDef)) {
2231 if (oc.
getBool(
"tls.guess.joining")) {
2236 for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
2240 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2241 if ((*j)->isTLControlled() ||
myUnsetTLS.count(*j) != 0) {
2256 for (
auto nodeSet : cands) {
2257 std::vector<NBNode*> nodes;
2258 for (
NBNode* node : nodeSet) {
2259 nodes.push_back(node);
2264 if (!tlc.
insert(tlDef)) {
2274 if (oc.
getBool(
"tls.guess")) {
2275 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2276 NBNode* cur = (*i).second;
2299 std::set<NBTrafficLightDefinition*> recompute;
2302 const std::set<NBTrafficLightDefinition*>& tlDefs = node->getControllingTLS();
2303 recompute.insert(tlDefs.begin(), tlDefs.end());
2304 node->removeTrafficLights(
true);
2306 edge->clearControllingTLInformation();
2311 if (def->getNodes().size() == 0) {
2314 def->setParticipantsInformation();
2315 def->setTLControllingInformation();
2340 for (
const auto& item :
myNodes) {
2341 item.second->computeKeepClear();
2349 std::set<std::string> exclude(excludeList.begin(), excludeList.end());
2353 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2354 if (!(*j)->isTLControlled() || exclude.count((*(*j)->getControllingTLS().begin())->getID()) != 0) {
2365 bool dummySetTL =
false;
2366 std::string
id =
"joinedS_";
2371 std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
2372 j->removeTrafficLights();
2377 std::vector<NBNode*> nodes;
2382 if (!tlc.
insert(tlDef)) {
2399 if (!tlc.
insert(tlDef)) {
2401 WRITE_WARNINGF(
TL(
"Building a tl-logic for junction '%' twice is not possible."),
id);
2411 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2412 (*i).second->computeLanes2Lanes();
2420 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2421 (*i).second->computeLogic(ec);
2428 std::set<NBNode*> roundaboutNodes;
2429 const bool checkLaneFoesAll = oc.
getBool(
"check-lane-foes.all");
2430 const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.
getBool(
"check-lane-foes.roundabout");
2431 if (checkLaneFoesRoundabout) {
2433 for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
2434 for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
2435 roundaboutNodes.insert((*j)->getToNode());
2439 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2440 const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
2441 (*i).second->computeLogic2(checkLaneFoes);
2448 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2449 delete ((*i).second);
2462 std::string freeID =
"SUMOGenerated" + toString<int>(counter);
2464 while (
retrieve(freeID) !=
nullptr) {
2467 freeID =
"SUMOGenerated" + toString<int>(counter);
2475 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2476 (*i).second->computeNodeShape(mismatchThreshold);
2483 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2486 int numUnregulatedJunctions = 0;
2487 int numDeadEndJunctions = 0;
2488 int numTrafficLightJunctions = 0;
2489 int numPriorityJunctions = 0;
2490 int numRightBeforeLeftJunctions = 0;
2491 int numLeftBeforeRightJunctions = 0;
2492 int numAllWayStopJunctions = 0;
2493 int numZipperJunctions = 0;
2494 int numDistrictJunctions = 0;
2495 int numRailCrossing = 0;
2496 int numRailSignals = 0;
2497 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2498 switch ((*i).second->getType()) {
2500 ++numUnregulatedJunctions;
2503 ++numDeadEndJunctions;
2508 ++numTrafficLightJunctions;
2512 ++numPriorityJunctions;
2515 ++numRightBeforeLeftJunctions;
2518 ++numLeftBeforeRightJunctions;
2521 ++numAllWayStopJunctions;
2524 ++numZipperJunctions;
2527 ++numDistrictJunctions;
2544 if (numDeadEndJunctions > 0) {
2549 if (numLeftBeforeRightJunctions > 0) {
2552 if (numTrafficLightJunctions > 0) {
2555 if (numAllWayStopJunctions > 0) {
2558 if (numZipperJunctions > 0) {
2561 if (numRailCrossing > 0) {
2564 if (numRailSignals > 0) {
2567 if (numDistrictJunctions > 0) {
2575 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2579std::vector<std::string>
2581 std::vector<std::string> ret;
2582 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2583 ret.push_back((*i).first);
2592 const auto nodeContainerCopy =
myNodes;
2594 for (
const auto& node : nodeContainerCopy) {
2595 node.second->setID(prefix + node.second->getID());
2596 myNodes[node.second->getID()] = node.second;
2603 if (
myNodes.count(newID) != 0) {
2604 throw ProcessError(
TLF(
"Attempt to rename node using existing id '%'", newID));
2614 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2615 NBNode* node = i->second;
2619 if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
2626 edge->setSignalPosition(node->
getPosition(),
nullptr);
2627#ifdef DEBUG_GUESSSIGNALS
2628 std::cout <<
" discard-simple " << node->
getID() <<
" edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2632 for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
2647 NBNode* node = item.second;
2658 if (!numericaIDs && !reservedIDs && prefix ==
"" && !startGiven) {
2661 std::vector<std::string> avoid;
2667 std::set<std::string> reserve;
2671 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
2675 for (NodeCont::iterator it =
myNodes.begin(); it !=
myNodes.end(); it++) {
2677 toChange.insert(it->second);
2684 toChange.insert(it->second);
2687 if (reservedIDs && reserve.count(it->first) > 0) {
2688 toChange.insert(it->second);
2692 for (
NBNode* node : toChange) {
2695 for (
NBNode* node : toChange) {
2699 node->setID(idSupplier.
getNext());
2701 tlc.
rename(tlDef, node->getID());
2703 myNodes[node->getID()] = node;
2705 if (prefix.empty()) {
2706 return (
int)toChange.size();
2711 for (
auto item : oldNodes) {
2713 rename(item.second, prefix + item.first);
2716 tlc.
rename(tlDef, prefix + tlDef->getID());
2734 for (
const auto& item :
myNodes) {
2737 paretoCheck(item.second, bottomRightFront, 1, -1);
2738 paretoCheck(item.second, bottomLeftFront, -1, -1);
2741 front.insert(topRightFront.begin(), topRightFront.end());
2742 front.insert(topLeftFront.begin(), topLeftFront.end());
2743 front.insert(bottomRightFront.begin(), bottomRightFront.end());
2744 front.insert(bottomLeftFront.begin(), bottomLeftFront.end());
2746 for (
NBNode* n : front) {
2747 const int in = (int)n->getIncomingEdges().size();
2748 const int out = (int)n->getOutgoingEdges().size();
2749 if ((in <= 1 && out <= 1) &&
2750 (in == 0 || out == 0
2751 || n->getIncomingEdges().front()->isTurningDirectionAt(n->getOutgoingEdges().front()))) {
2758 for (
const auto& item :
myNodes) {
2760 if (front.count(n) != 0) {
2763 if (n->
getEdges().size() == 1 && n->
getEdges().front()->getSpeed() > speedThreshold) {
2776 std::vector<NBNode*> dominated;
2778 const double x2 =
fn->getPosition().x() * xSign;
2779 const double y2 =
fn->getPosition().y() * ySign;
2780 if (x2 >= x && y2 >= y) {
2782 }
else if (x2 <= x && y2 <= y) {
2783 dominated.push_back(
fn);
2786 frontier.insert(node);
2787 for (
NBNode* r : dominated) {
2795 for (
const auto& item :
myNodes) {
2798 bool hasNEMA =
false;
2816 bool hadShapes =
false;
2817 for (
const auto& item :
myNodes) {
2818 if (item.second->getShape().size() > 0 && !item.second->hasCustomShape()) {
2820 item.second->resetShape();
#define WRITE_WARNINGF(...)
#define WRITE_MESSAGEF(...)
#define WRITE_ERRORF(...)
#define WRITE_MESSAGE(msg)
#define WRITE_WARNING(msg)
std::set< NBNode *, ComparatorIdLess > NodeSet
std::set< NBEdge * > EdgeSet
container for unique edges
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
#define MAX_SLIPLANE_LENGTH
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permission is a waterway edge.
const std::string & getVehicleClassNames(SVCPermissions permissions, bool expand)
Returns the ids of the given classes, divided using a ' '.
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const std::string SUMO_PARAM_ORIGID
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
@ TRAFFIC_LIGHT_RIGHT_ON_RED
@ TRAFFIC_LIGHT_NOJUNCTION
int gPrecision
the precision for floating point outputs
bool gDebugFlag1
global utility flags for debugging
const double SUMO_const_laneWidth
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
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)
static methods for processing the coordinates conversion for the current net
const Boundary & getOrigBoundary() const
Returns the original boundary.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
const Position getOffsetBase() const
Returns the network base.
const Boundary & getConvBoundary() const
Returns the converted boundary.
std::string getNext()
Returns the next id.
A container for districts.
A class representing a single district.
Storage for edges, including some functionality operating on multiple edges.
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
void extract(NBDistrictCont &dc, NBEdge *edge, bool remember=false)
Removes the given edge from the container like erase but does not delete it.
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
add post process connections
void removeRoundaboutEdges(const EdgeSet &toRemove)
remove edges from all stored roundabouts
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
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
const std::vector< Connection > & getConnections() const
Returns the connections.
const Position & getSignalPosition() const
Returns the position of a traffic signal on this edge.
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
NBNode * getToNode() const
Returns the destination node of the edge.
static EdgeVector filterByPermissions(const EdgeVector &edges, SVCPermissions permissions)
return only those edges that permit at least one of the give permissions
EdgeBuildingStep getStep() const
The building step of this edge.
NBEdge * getStraightContinuation(SVCPermissions permissions) const
return the straightest follower edge for the given permissions or nullptr (never returns turn-arounds...
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
@ INIT
The edge has been loaded, nothing is computed yet.
double getSpeed() const
Returns the speed allowed on this edge.
const std::string & getID() const
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
const NBNode * getSignalNode() const
Returns the node that (possibly) represents a traffic signal controlling at the end of this edge.
@ USER
The connection was given by the user.
NBNode * getFromNode() const
Returns the origin node of the edge.
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
static void loadPrefixedIDsFomFile(const std::string &file, const std::string prefix, std::set< std::string > &into)
Add prefixed ids defined in file.
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
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.
void clear()
deletes all nodes
std::set< std::string > myJoinExclusions
set of node ids which should not be joined
std::vector< std::vector< std::string > > myRailComponents
network components that must be removed if not connected to the road network via stop access
NamedRTree myRTree
node positions for faster lookup
void removeRailComponents(NBDistrictCont &dc, NBEdgeCont &ec, NBPTStopCont &sc)
remove rail components after ptstops are built
void avoidOverlap()
fix overlap
bool onlyCrossings(const NodeSet &c) const
check wheter the set of nodes only contains pedestrian crossings
std::vector< std::pair< std::set< std::string >, NBNode * > > myClusters2Join
loaded sets of node ids to join (cleared after use)
std::string createClusterId(const NodeSet &cluster, const std::string &prefix="cluster_")
generate id from cluster node ids
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
void recheckGuessedTLS(NBTrafficLightLogicCont &tlc)
recheck myGuessedTLS after node logics are computed
std::vector< NodeSet > NodeClusters
Definition of a node cluster container.
void computeKeepClear()
compute keepClear status for all connections
NodeCont myNodes
The map of names to nodes.
bool feasibleCluster(const NodeSet &cluster, const std::map< const NBNode *, std::vector< NBNode * > > &ptStopEnds, double maxDist, std::string &reason) const
determine wether the cluster is not too complex for joining
void registerJoinedCluster(const NodeSet &cluster)
gets all joined clusters (see doc for myClusters2Join)
std::string getFreeID()
generates a new node ID
bool recheckTLSThreshold(NBNode *node)
check whether a specific guessed tls should keep its type
void paretoCheck(NBNode *node, NodeSet &frontier, int xSign, int ySign)
update pareto frontier with the given node
bool maybeSlipLaneStart(const NBNode *n, EdgeVector &outgoing, double &inAngle) const
check whether the given node maybe the start of a slip lane
void addJoinExclusion(const std::vector< std::string > &ids)
bool erase(NBNode *node)
Removes the given node, deleting it.
int joinLoadedClusters(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins loaded junction clusters (see NIXMLNodesHandler)
void applyConditionalDefaults()
apply default values after loading
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
std::set< const NBNode * > myUnsetTLS
nodes that are excluded from tls-guessing
int remapIDs(bool numericaIDs, bool reservedIDs, const std::string &prefix, NBTrafficLightLogicCont &tlc)
remap node IDs according to options –numerical-ids and –reserved-ids
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
NodeCont myExtractedNodes
The extracted nodes which are kept for reference.
void joinTLS(NBTrafficLightLogicCont &tlc, double maxdist)
Builds clusters of tls-controlled junctions and joins the control if possible.
int removeUnwishedNodes(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc, NBPTLineCont &lc, NBParkingCont &pc, bool removeGeometryNodes)
Removes "unwished" nodes.
bool reduceToCircle(NodeSet &cluster, int circleSize, NodeSet startNodes, std::vector< NBNode * > cands=std::vector< NBNode * >()) const
try to find a joinable subset (recursively)
bool extract(NBNode *node, bool remember=false)
Removes the given node but does not delete it.
std::vector< std::string > getAllNames() const
get all node names
void computeLogics2(const NBEdgeCont &ec, OptionsCont &oc)
compute right-of-way logic for all lane-to-lane connections
bool shouldBeTLSControlled(const NodeSet &c, double laneSpeedThreshold, bool recheck=false) const
Returns whethe the given node cluster should be controlled by a tls.
void rename(NBNode *node, const std::string &newID)
Renames the node. Throws exception if newID already exists.
void joinSimilarEdges(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, bool removeDuplicates)
Joins edges connecting the same nodes.
void joinNodeClusters(NodeClusters clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, bool resetConnections=false)
joins the given node clusters
void discardRailSignals()
discards rail signals
void addPrefix(const std::string &prefix)
add prefix to all nodes
void printBuiltNodesStatistics() const
Prints statistics about built nodes.
void removeIsolatedRoads(NBDistrictCont &dc, NBEdgeCont &ec)
Removes sequences of edges that are not connected with a junction. Simple roads without junctions som...
void setAsTLControlled(NBNode *node, NBTrafficLightLogicCont &tlc, TrafficLightType type, std::string id="")
Sets the given node as being controlled by a tls.
std::set< const NBNode * > mySplit
nodes that were created when splitting an edge
static NodeSet getClusterNeighbors(const NBNode *n, double longThreshold, NodeSet &cluster)
return all cluster neighbors for the given node
void computeLogics(const NBEdgeCont &ec)
build the list of outgoing edges and lanes
void joinNodeCluster(NodeSet clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBNode *predefined=nullptr, bool resetConnections=false)
void generateNodeClusters(double maxDist, NodeClusters &into) const
Builds node clusters.
static bool isSlipLaneContinuation(const NBNode *cont)
whether the given node may continue a slip lane
void computeNodeShapes(double mismatchThreshold=-1)
Compute the junction shape for this node.
std::vector< std::set< std::string > > myJoinedClusters
sets of node ids which were joined
void pruneClusterFringe(NodeSet &cluster) const
remove geometry-like fringe nodes from cluster
NBEdge * shortestEdge(const NodeSet &cluster, const NodeSet &startNodes, const std::vector< NBNode * > &exclude) const
find closest neighbor for building circle
std::pair< NBNode *, double > NodeAndDist
void guessTLs(OptionsCont &oc, NBTrafficLightLogicCont &tlc)
Guesses which junctions or junction clusters shall be controlled by tls.
int guessFringe()
guess and mark fringe nodes
int joinJunctions(double maxDist, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc)
Joins junctions that are very close together.
void computeLanes2Lanes()
divides the incoming lanes on outgoing lanes
void discardTrafficLights(NBTrafficLightLogicCont &tlc, bool geometryLike, bool guessSignals)
std::set< NBNode *, ComparatorIdLess > myGuessedTLS
nodes that received a traffic light due to guessing (–tls.guess)
void removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes self-loop edges (edges where the source and the destination node are the same)
std::set< std::string > myJoined
ids found in loaded join clusters used for error checking
int joinSameJunctions(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins junctions with the same coordinates regardless of topology.
void analyzeCluster(NodeSet cluster, std::string &id, Position &pos, bool &hasTLS, TrafficLightType &type, SumoXMLNodeType &nodeType)
void addCluster2Join(const std::set< std::string > &cluster, NBNode *node)
add ids of nodes which shall be joined into a single node
bool customTLID(const NodeSet &c) const
check wheter the set of nodes contains traffic lights with custom id
bool resetNodeShapes()
reset all node shapes
static int pruneLongEdges(NodeSet &cluster, double maxDist, const bool dryRun=false)
avoid removal of long edges when joining junction clusters
bool maybeSlipLaneEnd(const NBNode *n, EdgeVector &incoming, double &outAngle) const
check whether the given node maybe the end of a slip lane
void removeComponents(NBDistrictCont &dc, NBEdgeCont &ec, const int numKeep, bool hasPTStops)
Checks the network for weak connectivity and removes all but the largest components....
void pruneSlipLaneNodes(NodeSet &cluster) const
remove nodes that form a slip lane from cluster
Represents a single node (junction) during network building.
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
RightOfWay getRightOfWay() const
Returns hint on how to compute right of way.
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
SumoXMLNodeType getType() const
Returns the type of this node.
void setRightOfWay(RightOfWay rightOfWay)
set method for computing right-of-way
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
void removeTrafficLights(bool setAsPriority=false)
Removes all references to traffic lights that control this tls.
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of incoming by the second Connections are rema...
EdgeVector getPassengerEdges(bool incoming) const
return edges that permit passengers (either incoming or outgoing)
const Position & getPosition() const
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
void updateSurroundingGeometry()
update geometry of node and surrounding edges
bool checkIsRemovable() const
check if node is removable
void setFringeType(FringeType fringeType)
set method for computing right-of-way
bool geometryLike() const
whether this is structurally similar to a geometry node
bool isNearDistrict() const
@chech if node is near district
bool isTLControlled() const
Returns whether this node is controlled by any tls.
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
A traffic light logics which must be computed (only nodes/edges are given)
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the given edge list in all lines
Container for public transport stops during the net building process.
void replaceEdge(const std::string &edgeID, const std::vector< NBEdge * > &replacement)
replace the edge with the closes edge on the given edge list in all stops
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
The base class for traffic light logic definitions.
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
virtual void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)=0
Replaces a removed edge/lane.
A container for traffic light definitions and built programs.
void rename(NBTrafficLightDefinition *tlDef, const std::string &newID)
rename traffic light
bool computeSingleLogic(OptionsCont &oc, NBTrafficLightDefinition *def)
Computes a specific traffic light logic (using by netedit)
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
void extract(NBTrafficLightDefinition *definition)
Extracts a traffic light definition from myDefinitions but keeps it in myExtracted for eventual * del...
Allows to store the object; used as context while traveling the rtree in TraCI.
Base class for objects which have an id.
virtual void setID(const std::string &newID)
resets the id
const std::string & getID() const
Returns the id.
void Remove(const float a_min[2], const float a_max[2], Named *const &a_data)
Remove entry.
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
int Search(const float a_min[2], const float a_max[2], const Named::StoringVisitor &c) const
Find all within search rectangle.
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)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
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)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
static std::string realString(const double v, const int precision=gPrecision)
Helper method for string formatting.
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.
void setx(double x)
set position x
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.
void sety(double y)
set position y
double y() const
Returns the y-position.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
T get(const std::string &str) const
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.