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 for (
NBEdge* e : clusterIncoming) {
1754 while (open.size() > 0) {
1755 NBEdge* cur = open.back();
1759 if (cluster.count(cur->
getToNode()) == 0) {
1767 if (seen.count(out) == 0
1768 && allEdges.count(out) != 0
1770 open.push_back(out);
1775 for (
const auto& con : cons) {
1776 if (con.toEdge !=
nullptr
1777 && seen.count(con.toEdge) == 0
1778 && allEdges.count(con.toEdge) != 0) {
1779 open.push_back(con.toEdge);
1785 for (
NBEdge* reached : seen) {
1787 if (inside.count(reached) == 0) {
1788 reachable[e].insert(reached);
1791#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1792 std::cout <<
" reachable e=" << e->getID() <<
" seen=" <<
toString(seen) <<
" reachable=" <<
toString(reachable[e]) <<
"\n";
1800 for (
NBEdge* e : inside) {
1801 for (
NBEdge* e2 : allEdges) {
1803 e2->replaceInConnections(e, e->getConnections());
1811 for (
NBEdge* e : allEdges) {
1812 std::vector<NBEdge::Connection> conns = e->getConnections();
1813 const bool outgoing = cluster.count(e->getFromNode()) > 0;
1814 NBNode* from = outgoing ? newNode : e->getFromNode();
1815 NBNode* to = outgoing ? e->getToNode() : newNode;
1818 e->
setParameter(
"origFrom", e->getFromNode()->getID());
1820 e->setParameter(
"origTo", e->getToNode()->getID());
1823 if (e->getTurnSignTarget() !=
"") {
1824 for (
NBNode* n : cluster) {
1825 if (e->getTurnSignTarget() == n->getID()) {
1826 e->setTurnSignTarget(to->
getID());
1831 e->reinitNodes(from, to);
1834 for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1836 if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1839#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1840 std::cout <<
" e=" << e->getID() <<
" declareConnectionsAsLoaded\n";
1845 if (!resetConnections) {
1851 in->removeFromConnections(out, -1, -1,
true,
false,
true);
1857 in->invalidateConnections(
true);
1863 for (
NBNode* n : cluster) {
1871 std::set<std::string> ids;
1872 for (
NBNode* n : cluster) {
1873 ids.insert(n->getID());
1883 bool ambiguousType =
false;
1884 for (
NBNode* j : cluster) {
1885 pos.
add(j->getPosition());
1887 if (j->isTLControlled()) {
1890 type = (*j->getControllingTLS().begin())->getType();
1891 }
else if (type != (*j->getControllingTLS().begin())->getType()) {
1892 ambiguousType =
true;
1898 nodeType = otherType;
1899 }
else if (nodeType != otherType) {
1911 pos.
mul(1. / (
double)cluster.size());
1912 if (ambiguousType) {
1922 bool tooFast =
false;
1923 double laneSpeedSum = 0;
1924 std::set<NBEdge*> seen;
1926 for (
const NBEdge* e : j->getEdges()) {
1927 if (c.find(e->getFromNode()) != c.end() && c.find(e->getToNode()) != c.end()) {
1931 if (j->hasIncoming(e)) {
1932 if (recheck && !j->hasConflict(e)) {
1937 laneSpeedSum += (double)e->getNumLanes() * e->getLaneSpeed(0);
1939 if (e->getLaneSpeed(0) * 3.6 > 79) {
1945 return !tooFast && laneSpeedSum >= laneSpeedThreshold && c.size() != 0;
1957 nonPedIncoming.push_back(e);
1960 for (
NBEdge* e : node->getOutgoingEdges()) {
1962 nonPedOutgoing.push_back(e);
1965 if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
1981 if (node->isTLControlled()) {
1987 const std::string tlID = tl->
getID();
1988 if (tlID != node->getID()
2004 const double laneSpeedThreshold = oc.
getFloat(
"tls.guess.threshold");
2005 if (oc.
isSet(
"tls.unset")) {
2006 std::vector<std::string> notTLControlledNodes = oc.
getStringVector(
"tls.unset");
2007 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
2010 throw ProcessError(
TLF(
" The junction '%' to set as not-controlled is not known.", *i));
2013 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
2014 (*j)->removeNode(n);
2024 if (oc.
exists(
"tls.taz-nodes") && oc.
getBool(
"tls.taz-nodes")) {
2025 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2026 NBNode* cur = (*i).second;
2035 if (oc.
exists(
"tls.guess-signals") && oc.
getBool(
"tls.guess-signals")) {
2037 const double signalDist = oc.
getFloat(
"tls.guess-signals.dist");
2038 for (
const auto& item :
myNodes) {
2039 const NBNode* node = item.second;
2041#ifdef DEBUG_GUESSSIGNALS
2043 std::cout <<
" propagate TLS from " << node->
getID() <<
" downstream\n";
2049 edge->setSignalPosition(node->
getPosition(), node);
2054 std::set<NBEdge*> seen;
2055 std::set<NBEdge*> check;
2056 for (
const auto& item :
myNodes) {
2057 for (
NBEdge* edge : item.second->getOutgoingEdges()) {
2061#ifdef DEBUG_GUESSSIGNALS
2062 if (
DEBUGCOND(edge->getSignalNode()) ||
true) {
2063 std::cout <<
" primary signalPosition edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2070 while (check.size() > 0) {
2071 NBEdge*
const edge = *check.begin();
2072 check.erase(check.begin());
2077 if (seen.count(outEdge) == 0) {
2079#ifdef DEBUG_GUESSSIGNALS
2081 std::cout <<
" setSignalPosition edge=" << outEdge->
getID() <<
" pos=" << edge->
getSignalPosition() <<
"\n";
2084 check.insert(outEdge);
2091 const int slack = oc.
getInt(
"tls.guess-signals.slack");
2092 for (std::map<std::string, NBNode*>::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2093 NBNode* node = i->second;
2102 std::vector<const NBNode*> signals;
2103 int foundSignals = 0;
2104 int missingSignals = 0;
2106 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2107 const NBEdge* inEdge = *it_i;
2110#ifdef DEBUG_GUESSSIGNALS
2112 std::cout <<
" noTLS, edge=" << inEdge->
getID() <<
"\n";
2116 if (missingSignals > slack) {
2125 int foundSignalsAtDist = 0;
2126 if (foundSignals > 1 && missingSignals <= slack && missingSignals < foundSignals) {
2130 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2131 const NBEdge* inEdge = *it_i;
2134#ifdef DEBUG_GUESSSIGNALS
2140 if (missingSignals > slack) {
2145 foundSignalsAtDist++;
2148 if (signal !=
nullptr) {
2149 signals.push_back(signal);
2154 for (
const NBEdge* outEdge : outgoing) {
2155 NBNode* cand = outEdge->getToNode();
2157#ifdef DEBUG_GUESSSIGNALS
2159 std::cout <<
" node=" << node->
getID() <<
" outEdge=" << outEdge->getID() <<
" signalNode=" << cand->
getID() <<
" len=" << outEdge->getLength() <<
"\n";
2162 signals.push_back(cand);
2166 if (foundSignalsAtDist > 1 && missingSignals <= slack && missingSignals < foundSignalsAtDist) {
2167 for (
const NBNode* s : signals) {
2168 std::set<NBTrafficLightDefinition*> tls = s->getControllingTLS();
2170 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
2177 if (!tlc.
insert(tlDef)) {
2189 if (oc.
getBool(
"tls.guess.joining")) {
2194 for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
2198 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2199 if ((*j)->isTLControlled() ||
myUnsetTLS.count(*j) != 0) {
2214 for (
auto nodeSet : cands) {
2215 std::vector<NBNode*> nodes;
2216 for (
NBNode* node : nodeSet) {
2217 nodes.push_back(node);
2222 if (!tlc.
insert(tlDef)) {
2232 if (oc.
getBool(
"tls.guess")) {
2233 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2234 NBNode* cur = (*i).second;
2257 std::set<NBTrafficLightDefinition*> recompute;
2260 const std::set<NBTrafficLightDefinition*>& tlDefs = node->getControllingTLS();
2261 recompute.insert(tlDefs.begin(), tlDefs.end());
2262 node->removeTrafficLights(
true);
2264 edge->clearControllingTLInformation();
2269 if (def->getNodes().size() == 0) {
2272 def->setParticipantsInformation();
2273 def->setTLControllingInformation();
2298 for (
const auto& item :
myNodes) {
2299 item.second->computeKeepClear();
2309 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2310 if (!(*j)->isTLControlled()) {
2321 bool dummySetTL =
false;
2322 std::string
id =
"joinedS_";
2327 std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
2328 j->removeTrafficLights();
2333 std::vector<NBNode*> nodes;
2338 if (!tlc.
insert(tlDef)) {
2355 if (!tlc.
insert(tlDef)) {
2357 WRITE_WARNINGF(
TL(
"Building a tl-logic for junction '%' twice is not possible."),
id);
2367 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2368 (*i).second->computeLanes2Lanes();
2376 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2377 (*i).second->computeLogic(ec);
2384 std::set<NBNode*> roundaboutNodes;
2385 const bool checkLaneFoesAll = oc.
getBool(
"check-lane-foes.all");
2386 const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.
getBool(
"check-lane-foes.roundabout");
2387 if (checkLaneFoesRoundabout) {
2389 for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
2390 for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
2391 roundaboutNodes.insert((*j)->getToNode());
2395 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2396 const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
2397 (*i).second->computeLogic2(checkLaneFoes);
2404 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2405 delete ((*i).second);
2418 std::string freeID =
"SUMOGenerated" + toString<int>(counter);
2420 while (
retrieve(freeID) !=
nullptr) {
2423 freeID =
"SUMOGenerated" + toString<int>(counter);
2431 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2432 (*i).second->computeNodeShape(mismatchThreshold);
2439 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2442 int numUnregulatedJunctions = 0;
2443 int numDeadEndJunctions = 0;
2444 int numTrafficLightJunctions = 0;
2445 int numPriorityJunctions = 0;
2446 int numRightBeforeLeftJunctions = 0;
2447 int numLeftBeforeRightJunctions = 0;
2448 int numAllWayStopJunctions = 0;
2449 int numZipperJunctions = 0;
2450 int numDistrictJunctions = 0;
2451 int numRailCrossing = 0;
2452 int numRailSignals = 0;
2453 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2454 switch ((*i).second->getType()) {
2456 ++numUnregulatedJunctions;
2459 ++numDeadEndJunctions;
2464 ++numTrafficLightJunctions;
2468 ++numPriorityJunctions;
2471 ++numRightBeforeLeftJunctions;
2474 ++numLeftBeforeRightJunctions;
2477 ++numAllWayStopJunctions;
2480 ++numZipperJunctions;
2483 ++numDistrictJunctions;
2500 if (numDeadEndJunctions > 0) {
2505 if (numLeftBeforeRightJunctions > 0) {
2508 if (numTrafficLightJunctions > 0) {
2511 if (numAllWayStopJunctions > 0) {
2514 if (numZipperJunctions > 0) {
2517 if (numRailCrossing > 0) {
2520 if (numRailSignals > 0) {
2523 if (numDistrictJunctions > 0) {
2531 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2535std::vector<std::string>
2537 std::vector<std::string> ret;
2538 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2539 ret.push_back((*i).first);
2548 const auto nodeContainerCopy =
myNodes;
2550 for (
const auto& node : nodeContainerCopy) {
2551 node.second->setID(prefix + node.second->getID());
2552 myNodes[node.second->getID()] = node.second;
2559 if (
myNodes.count(newID) != 0) {
2560 throw ProcessError(
TLF(
"Attempt to rename node using existing id '%'", newID));
2570 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2571 NBNode* node = i->second;
2575 if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
2582 edge->setSignalPosition(node->
getPosition(),
nullptr);
2583#ifdef DEBUG_GUESSSIGNALS
2584 std::cout <<
" discard-simple " << node->
getID() <<
" edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2588 for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
2603 NBNode* node = item.second;
2614 if (!numericaIDs && !reservedIDs && prefix ==
"" && !startGiven) {
2617 std::vector<std::string> avoid;
2623 std::set<std::string> reserve;
2627 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
2631 for (NodeCont::iterator it =
myNodes.begin(); it !=
myNodes.end(); it++) {
2633 toChange.insert(it->second);
2640 toChange.insert(it->second);
2643 if (reservedIDs && reserve.count(it->first) > 0) {
2644 toChange.insert(it->second);
2648 for (
NBNode* node : toChange) {
2651 for (
NBNode* node : toChange) {
2655 node->setID(idSupplier.
getNext());
2657 tlc.
rename(tlDef, node->getID());
2659 myNodes[node->getID()] = node;
2661 if (prefix.empty()) {
2662 return (
int)toChange.size();
2667 for (
auto item : oldNodes) {
2669 rename(item.second, prefix + item.first);
2672 tlc.
rename(tlDef, prefix + tlDef->getID());
2690 for (
const auto& item :
myNodes) {
2693 paretoCheck(item.second, bottomRightFront, 1, -1);
2694 paretoCheck(item.second, bottomLeftFront, -1, -1);
2697 front.insert(topRightFront.begin(), topRightFront.end());
2698 front.insert(topLeftFront.begin(), topLeftFront.end());
2699 front.insert(bottomRightFront.begin(), bottomRightFront.end());
2700 front.insert(bottomLeftFront.begin(), bottomLeftFront.end());
2702 for (
NBNode* n : front) {
2703 const int in = (int)n->getIncomingEdges().size();
2704 const int out = (int)n->getOutgoingEdges().size();
2705 if ((in <= 1 && out <= 1) &&
2706 (in == 0 || out == 0
2707 || n->getIncomingEdges().front()->isTurningDirectionAt(n->getOutgoingEdges().front()))) {
2714 for (
const auto& item :
myNodes) {
2716 if (front.count(n) != 0) {
2719 if (n->
getEdges().size() == 1 && n->
getEdges().front()->getSpeed() > speedThreshold) {
2732 std::vector<NBNode*> dominated;
2734 const double x2 =
fn->getPosition().x() * xSign;
2735 const double y2 =
fn->getPosition().y() * ySign;
2736 if (x2 >= x && y2 >= y) {
2738 }
else if (x2 <= x && y2 <= y) {
2739 dominated.push_back(
fn);
2742 frontier.insert(node);
2743 for (
NBNode* r : dominated) {
2751 for (
const auto& item :
myNodes) {
2754 bool hasNEMA =
false;
2772 bool hadShapes =
false;
2773 for (
const auto& item :
myNodes) {
2774 if (item.second->getShape().size() > 0 && !item.second->hasCustomShape()) {
2776 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.
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permission is a waterway edge.
@ 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 accoring 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.